153 lines
4.6 KiB
C
153 lines
4.6 KiB
C
#include "runtime.h"
|
|
#include "threading.h"
|
|
|
|
#ifdef __linux__
|
|
|
|
#include <pthread.h>
|
|
struct vy_condition_var_s {
|
|
pthread_mutex_t mutex;
|
|
pthread_cond_t cond;
|
|
ptrdiff_t next_reusable;
|
|
};
|
|
|
|
#define MAX_CONDS 1024
|
|
vy_condition_var _conds[MAX_CONDS];
|
|
static ptrdiff_t _first_reusable = MAX_CONDS;
|
|
static ptrdiff_t _next = 0;
|
|
static pthread_mutex_t _guard = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
VY_DLLEXPORT vy_condition_var *vyCreateConditionVar(void) {
|
|
pthread_mutex_lock(&_guard);
|
|
if (_first_reusable < MAX_CONDS) {
|
|
vy_condition_var *cond = &_conds[_first_reusable];
|
|
_first_reusable = cond->next_reusable;
|
|
pthread_mutex_unlock(&_guard);
|
|
return cond;
|
|
} else if (_next < MAX_CONDS) {
|
|
vy_condition_var *cond = &_conds[_next];
|
|
if (pthread_mutex_init(&cond->mutex, NULL) != 0) {
|
|
vyLog("core", "Condition variable creation failed");
|
|
pthread_mutex_unlock(&_guard);
|
|
return NULL;
|
|
}
|
|
if (pthread_cond_init(&cond->cond, NULL) != 0) {
|
|
vyLog("core", "Condition variable creation failed");
|
|
}
|
|
cond->next_reusable = MAX_CONDS;
|
|
++_next;
|
|
pthread_mutex_unlock(&_guard);
|
|
return cond;
|
|
}
|
|
vyReportError("core", "Ran out of condition variable objects");
|
|
pthread_mutex_unlock(&_guard);
|
|
return NULL;
|
|
}
|
|
|
|
VY_DLLEXPORT void vyDestroyConditionVar(vy_condition_var *var) {
|
|
ptrdiff_t index = var - &_conds[0];
|
|
pthread_mutex_lock(&_guard);
|
|
var->next_reusable = _first_reusable;
|
|
_first_reusable = index;
|
|
pthread_mutex_unlock(&_guard);
|
|
}
|
|
|
|
VY_DLLEXPORT void vyLockConditionVar(vy_condition_var *var) {
|
|
pthread_mutex_lock(&var->mutex);
|
|
}
|
|
|
|
VY_DLLEXPORT void vyUnlockConditionVar(vy_condition_var *var, bool signal) {
|
|
if (signal)
|
|
pthread_cond_signal(&var->cond);
|
|
pthread_mutex_unlock(&var->mutex);
|
|
}
|
|
|
|
VY_DLLEXPORT void vyWaitOnConditionVar(vy_condition_var *var) {
|
|
pthread_cond_wait(&var->cond, &var->mutex);
|
|
}
|
|
|
|
#elif defined(_WIN32)
|
|
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#include <Windows.h>
|
|
struct vy_condition_var_s {
|
|
CRITICAL_SECTION critical_section;
|
|
CONDITION_VARIABLE cond;
|
|
ptrdiff_t next_reusable;
|
|
};
|
|
|
|
#define MAX_CONDS 1024
|
|
vy_condition_var _conds[MAX_CONDS];
|
|
static ptrdiff_t _first_reusable = MAX_CONDS;
|
|
static ptrdiff_t _next = 0;
|
|
static HANDLE _guard;
|
|
static INIT_ONCE _guard_init = INIT_ONCE_STATIC_INIT;
|
|
|
|
static BOOL CALLBACK InitGuardFn(PINIT_ONCE initOnce, PVOID parameter, PVOID *context) {
|
|
VY_UNUSED(initOnce);
|
|
VY_UNUSED(parameter);
|
|
VY_UNUSED(context);
|
|
|
|
_guard = CreateMutexW(NULL, FALSE, NULL);
|
|
return _guard != NULL;
|
|
}
|
|
|
|
VY_DLLEXPORT vy_condition_var *vyCreateConditionVar(void) {
|
|
if (!InitOnceExecuteOnce(&_guard_init, InitGuardFn, NULL, NULL)) {
|
|
vyReportError("core", "Failed to initialize the guard mutex.");
|
|
return NULL;
|
|
}
|
|
|
|
if (WaitForSingleObjectEx(_guard, INFINITE, TRUE) != WAIT_OBJECT_0) {
|
|
vyLog("core", "Failed to lock the guard variable: %u", GetLastError());
|
|
return NULL;
|
|
}
|
|
if (_first_reusable < MAX_CONDS) {
|
|
vy_condition_var *cond = &_conds[_first_reusable];
|
|
_first_reusable = cond->next_reusable;
|
|
ReleaseMutex(_guard);
|
|
return cond;
|
|
} else if (_next < MAX_CONDS) {
|
|
vy_condition_var *cond = &_conds[_next];
|
|
if (!InitializeCriticalSectionAndSpinCount(&cond->critical_section, 4000)) {
|
|
vyLog("core", "Condition variable creation failed");
|
|
ReleaseMutex(_guard);
|
|
return NULL;
|
|
}
|
|
InitializeConditionVariable(&cond->cond);
|
|
cond->next_reusable = MAX_CONDS;
|
|
++_next;
|
|
ReleaseMutex(_guard);
|
|
return cond;
|
|
}
|
|
vyReportError("core", "Ran out of condition variable objects");
|
|
ReleaseMutex(_guard);
|
|
return NULL;
|
|
}
|
|
|
|
VY_DLLEXPORT void vyDestroyConditionVar(vy_condition_var *var) {
|
|
ptrdiff_t index = var - &_conds[0];
|
|
if (WaitForSingleObjectEx(_guard, INFINITE, TRUE) != WAIT_OBJECT_0) {
|
|
vyLog("core", "Failed to lock the guard variable: %u", GetLastError());
|
|
return;
|
|
}
|
|
var->next_reusable = _first_reusable;
|
|
_first_reusable = index;
|
|
ReleaseMutex(_guard);
|
|
}
|
|
|
|
VY_DLLEXPORT void vyLockConditionVar(vy_condition_var *var) {
|
|
EnterCriticalSection(&var->critical_section);
|
|
}
|
|
|
|
VY_DLLEXPORT void vyUnlockConditionVar(vy_condition_var *var, bool signal) {
|
|
LeaveCriticalSection(&var->critical_section);
|
|
if (signal)
|
|
WakeAllConditionVariable(&var->cond);
|
|
}
|
|
|
|
VY_DLLEXPORT void vyWaitOnConditionVar(vy_condition_var *var) {
|
|
SleepConditionVariableCS(&var->cond, &var->critical_section, INFINITE);
|
|
}
|
|
|
|
#endif
|