#include "runtime.h" #include "threading.h" #ifdef __linux__ #include 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 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