2023-09-07 12:51:48 +00:00
|
|
|
/*************************************************************************
|
2023-07-31 03:59:00 +00:00
|
|
|
*
|
2023-09-07 12:51:48 +00:00
|
|
|
* Orca
|
|
|
|
* Copyright 2023 Martin Fouilleul and the Orca project contributors
|
|
|
|
* See LICENSE.txt for licensing information
|
2023-07-31 03:59:00 +00:00
|
|
|
*
|
2023-09-07 12:51:48 +00:00
|
|
|
**************************************************************************/
|
2023-08-19 12:49:23 +00:00
|
|
|
#include <math.h> //INFINITY
|
|
|
|
#include <processthreadsapi.h>
|
|
|
|
#include <synchapi.h>
|
|
|
|
#include <winuser.h> // PostMessage
|
2023-07-31 03:59:00 +00:00
|
|
|
|
2023-08-19 12:49:23 +00:00
|
|
|
#include "platform_thread.h"
|
2023-07-31 03:59:00 +00:00
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
struct oc_thread
|
2023-07-31 03:59:00 +00:00
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
oc_thread_start_function start;
|
|
|
|
HANDLE handle;
|
|
|
|
DWORD threadId;
|
|
|
|
void* userPointer;
|
|
|
|
oc_str8 name;
|
|
|
|
char nameBuffer[OC_THREAD_NAME_MAX_SIZE];
|
2023-07-31 03:59:00 +00:00
|
|
|
};
|
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
static DWORD WINAPI oc_thread_bootstrap(LPVOID lpParameter)
|
2023-07-31 03:59:00 +00:00
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
oc_thread* thread = (oc_thread*)lpParameter;
|
|
|
|
i32 exitCode = thread->start(thread->userPointer);
|
|
|
|
return (exitCode);
|
2023-07-31 03:59:00 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
oc_thread* oc_thread_create_with_name(oc_thread_start_function start, void* userPointer, oc_str8 name)
|
2023-07-31 03:59:00 +00:00
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
oc_thread* thread = (oc_thread*)malloc(sizeof(oc_thread));
|
|
|
|
thread->start = start;
|
|
|
|
thread->handle = INVALID_HANDLE_VALUE;
|
|
|
|
thread->userPointer = userPointer;
|
|
|
|
if(name.len && name.ptr)
|
|
|
|
{
|
|
|
|
strncpy(thread->nameBuffer, name.ptr, oc_min(name.len, OC_THREAD_NAME_MAX_SIZE - 1));
|
|
|
|
thread->nameBuffer[OC_THREAD_NAME_MAX_SIZE - 1] = '\0';
|
|
|
|
thread->name = OC_STR8(thread->nameBuffer);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
thread->nameBuffer[0] = '\0';
|
|
|
|
thread->name = oc_str8_from_buffer(0, thread->nameBuffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
SECURITY_ATTRIBUTES childProcessSecurity = {
|
|
|
|
.nLength = sizeof(SECURITY_ATTRIBUTES),
|
|
|
|
.bInheritHandle = false,
|
|
|
|
};
|
|
|
|
SIZE_T stackSize = 0; // uses process default
|
|
|
|
DWORD flags = 0;
|
|
|
|
DWORD threadId = 0;
|
|
|
|
thread->handle = CreateThread(&childProcessSecurity, stackSize, oc_thread_bootstrap, thread, flags, &threadId);
|
|
|
|
if(thread->handle == NULL)
|
|
|
|
{
|
|
|
|
free(thread);
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
thread->threadId = threadId;
|
|
|
|
|
|
|
|
if(thread->name.len)
|
|
|
|
{
|
|
|
|
wchar_t widename[OC_THREAD_NAME_MAX_SIZE];
|
|
|
|
size_t length = mbstowcs(widename, thread->nameBuffer, OC_THREAD_NAME_MAX_SIZE - 1);
|
|
|
|
widename[length] = '\0';
|
|
|
|
|
|
|
|
SetThreadDescription(thread->handle, widename);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (thread);
|
2023-07-31 03:59:00 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
oc_thread* oc_thread_create(oc_thread_start_function start, void* userPointer)
|
2023-07-31 03:59:00 +00:00
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
return (oc_thread_create_with_name(start, userPointer, (oc_str8){ 0 }));
|
2023-07-31 03:59:00 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
oc_str8 oc_thread_get_name(oc_thread* thread)
|
2023-07-31 03:59:00 +00:00
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
return (thread->name);
|
2023-07-31 03:59:00 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
u64 oc_thread_unique_id(oc_thread* thread)
|
2023-07-31 03:59:00 +00:00
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
return (thread->threadId);
|
2023-07-31 03:59:00 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
u64 oc_thread_self_id()
|
2023-07-31 03:59:00 +00:00
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
return (GetCurrentThreadId());
|
2023-07-31 03:59:00 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
int oc_thread_signal(oc_thread* thread, int sig)
|
2023-07-31 03:59:00 +00:00
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
BOOL success = TerminateThread(thread->handle, (DWORD)sig);
|
|
|
|
return (success ? 0 : -1);
|
2023-07-31 03:59:00 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
int oc_thread_join(oc_thread* thread, i64* exitCode)
|
2023-07-31 03:59:00 +00:00
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
DWORD result = WaitForSingleObject(thread->handle, INFINITE);
|
|
|
|
if(result == WAIT_FAILED)
|
|
|
|
{
|
|
|
|
return (-1);
|
|
|
|
}
|
2023-07-31 03:59:00 +00:00
|
|
|
|
2023-08-19 12:49:23 +00:00
|
|
|
if(exitCode)
|
|
|
|
{
|
|
|
|
DWORD exitCodeWin32 = 0;
|
|
|
|
if(GetExitCodeThread(thread->handle, &exitCodeWin32))
|
|
|
|
{
|
|
|
|
*exitCode = exitCodeWin32;
|
|
|
|
}
|
|
|
|
}
|
2023-07-31 03:59:00 +00:00
|
|
|
|
2023-08-19 12:49:23 +00:00
|
|
|
free(thread);
|
|
|
|
return (0);
|
2023-07-31 03:59:00 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
int oc_thread_detach(oc_thread* thread)
|
2023-07-31 03:59:00 +00:00
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
if(CloseHandle(thread->handle))
|
|
|
|
{
|
|
|
|
free(thread);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
return (-1);
|
2023-07-31 03:59:00 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
struct oc_mutex
|
2023-07-31 03:59:00 +00:00
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
u64 owningThreadId;
|
|
|
|
SRWLOCK lock;
|
2023-07-31 03:59:00 +00:00
|
|
|
};
|
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
oc_mutex* oc_mutex_create()
|
2023-07-31 03:59:00 +00:00
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
oc_mutex* mutex = (oc_mutex*)malloc(sizeof(oc_mutex));
|
|
|
|
mutex->owningThreadId = 0;
|
|
|
|
InitializeSRWLock(&mutex->lock);
|
|
|
|
return mutex;
|
2023-07-31 03:59:00 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
int oc_mutex_destroy(oc_mutex* mutex)
|
2023-07-31 03:59:00 +00:00
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
OC_DEBUG_ASSERT(mutex->owningThreadId == 0);
|
|
|
|
free(mutex);
|
|
|
|
return (0);
|
2023-07-31 03:59:00 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
int oc_mutex_lock(oc_mutex* mutex)
|
2023-07-31 03:59:00 +00:00
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
OC_DEBUG_ASSERT(mutex->owningThreadId == 0);
|
|
|
|
AcquireSRWLockExclusive(&mutex->lock);
|
|
|
|
return (0);
|
2023-07-31 03:59:00 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
int oc_mutex_unlock(oc_mutex* mutex)
|
2023-07-31 03:59:00 +00:00
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
OC_DEBUG_ASSERT(oc_thread_self_id() == mutex->owningThreadId);
|
|
|
|
ReleaseSRWLockExclusive(&mutex->lock);
|
|
|
|
mutex->owningThreadId = 0;
|
|
|
|
return (0);
|
2023-07-31 03:59:00 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
// oc_ticket has a mirrored implementation in posix_thread.c
|
2023-07-31 03:59:00 +00:00
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
void oc_ticket_init(oc_ticket* mutex)
|
2023-07-31 03:59:00 +00:00
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
mutex->nextTicket = 0;
|
|
|
|
mutex->serving = 0;
|
2023-07-31 03:59:00 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
void oc_ticket_lock(oc_ticket* mutex)
|
2023-07-31 03:59:00 +00:00
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
u64 ticket = atomic_fetch_add(&mutex->nextTicket, 1ULL);
|
|
|
|
while(ticket != mutex->serving)
|
|
|
|
; //spin
|
2023-07-31 03:59:00 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
void oc_ticket_unlock(oc_ticket* mutex)
|
2023-07-31 03:59:00 +00:00
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
atomic_fetch_add(&mutex->serving, 1ULL);
|
2023-07-31 03:59:00 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
struct oc_condition
|
2023-07-31 03:59:00 +00:00
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
CONDITION_VARIABLE cond;
|
2023-07-31 03:59:00 +00:00
|
|
|
};
|
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
oc_condition* oc_condition_create()
|
2023-07-31 03:59:00 +00:00
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
oc_condition* cond = (oc_condition*)malloc(sizeof(oc_condition));
|
|
|
|
InitializeConditionVariable(&cond->cond);
|
|
|
|
return cond;
|
2023-07-31 03:59:00 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
int oc_condition_destroy(oc_condition* cond)
|
2023-07-31 03:59:00 +00:00
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
free(cond);
|
|
|
|
return (0);
|
2023-07-31 03:59:00 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
int oc_condition_wait(oc_condition* cond, oc_mutex* mutex)
|
2023-07-31 03:59:00 +00:00
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
return oc_condition_timedwait(cond, mutex, INFINITY);
|
2023-07-31 03:59:00 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
int oc_condition_timedwait(oc_condition* cond, oc_mutex* mutex, f64 seconds)
|
2023-07-31 03:59:00 +00:00
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
const f32 ms = (seconds == INFINITY) ? INFINITE : seconds * 1000;
|
|
|
|
if(!SleepConditionVariableSRW(&cond->cond, &mutex->lock, ms, 0))
|
|
|
|
{
|
|
|
|
return (GetLastError());
|
|
|
|
}
|
|
|
|
return (0);
|
2023-07-31 03:59:00 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
int oc_condition_signal(oc_condition* cond)
|
2023-07-31 03:59:00 +00:00
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
WakeConditionVariable(&cond->cond);
|
|
|
|
return (0);
|
2023-07-31 03:59:00 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
int oc_condition_broadcast(oc_condition* cond)
|
2023-07-31 03:59:00 +00:00
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
WakeAllConditionVariable(&cond->cond);
|
|
|
|
return (0);
|
2023-07-31 03:59:00 +00:00
|
|
|
}
|