#include <internal/thread_arch.h>
#if defined(OPENSSL_THREADS_WINNT)
#include <process.h>
#include <windows.h>
static unsigned __stdcall thread_start_thunk(LPVOID vthread)
{
CRYPTO_THREAD *thread;
CRYPTO_THREAD_RETVAL ret;
thread = (CRYPTO_THREAD *)vthread;
thread->thread_id = GetCurrentThreadId();
ret = thread->routine(thread->data);
ossl_crypto_mutex_lock(thread->statelock);
CRYPTO_THREAD_SET_STATE(thread, CRYPTO_THREAD_FINISHED);
thread->retval = ret;
ossl_crypto_condvar_signal(thread->condvar);
ossl_crypto_mutex_unlock(thread->statelock);
return 0;
}
int ossl_crypto_thread_native_spawn(CRYPTO_THREAD *thread)
{
HANDLE *handle;
handle = OPENSSL_zalloc(sizeof(*handle));
if (handle == NULL)
goto fail;
*handle = (HANDLE)_beginthreadex(NULL, 0, &thread_start_thunk, thread, 0, NULL);
if (*handle == NULL)
goto fail;
thread->handle = handle;
return 1;
fail:
thread->handle = NULL;
OPENSSL_free(handle);
return 0;
}
int ossl_crypto_thread_native_perform_join(CRYPTO_THREAD *thread, CRYPTO_THREAD_RETVAL *retval)
{
DWORD thread_retval;
HANDLE *handle;
if (thread == NULL || thread->handle == NULL)
return 0;
handle = (HANDLE *)thread->handle;
if (WaitForSingleObject(*handle, INFINITE) != WAIT_OBJECT_0)
return 0;
if (GetExitCodeThread(*handle, &thread_retval) == 0)
return 0;
if (thread_retval != 0)
return 0;
if (CloseHandle(*handle) == 0)
return 0;
return 1;
}
int ossl_crypto_thread_native_exit(void)
{
_endthreadex(0);
return 1;
}
int ossl_crypto_thread_native_is_self(CRYPTO_THREAD *thread)
{
return thread->thread_id == GetCurrentThreadId();
}
CRYPTO_MUTEX *ossl_crypto_mutex_new(void)
{
CRITICAL_SECTION *mutex;
if ((mutex = OPENSSL_zalloc(sizeof(*mutex))) == NULL)
return NULL;
InitializeCriticalSection(mutex);
return (CRYPTO_MUTEX *)mutex;
}
void ossl_crypto_mutex_lock(CRYPTO_MUTEX *mutex)
{
CRITICAL_SECTION *mutex_p;
mutex_p = (CRITICAL_SECTION *)mutex;
EnterCriticalSection(mutex_p);
}
int ossl_crypto_mutex_try_lock(CRYPTO_MUTEX *mutex)
{
CRITICAL_SECTION *mutex_p;
mutex_p = (CRITICAL_SECTION *)mutex;
if (TryEnterCriticalSection(mutex_p))
return 1;
return 0;
}
void ossl_crypto_mutex_unlock(CRYPTO_MUTEX *mutex)
{
CRITICAL_SECTION *mutex_p;
mutex_p = (CRITICAL_SECTION *)mutex;
LeaveCriticalSection(mutex_p);
}
void ossl_crypto_mutex_free(CRYPTO_MUTEX **mutex)
{
CRITICAL_SECTION **mutex_p;
mutex_p = (CRITICAL_SECTION **)mutex;
if (*mutex_p != NULL)
DeleteCriticalSection(*mutex_p);
OPENSSL_free(*mutex_p);
*mutex = NULL;
}
static int determine_timeout(OSSL_TIME deadline, DWORD *w_timeout_p)
{
OSSL_TIME now, delta;
uint64_t ms;
if (ossl_time_is_infinite(deadline)) {
*w_timeout_p = INFINITE;
return 1;
}
now = ossl_time_now();
delta = ossl_time_subtract(deadline, now);
if (ossl_time_is_zero(delta))
return 0;
ms = ossl_time2ms(delta);
if (ms > (uint64_t)(INFINITE - 1))
*w_timeout_p = INFINITE - 1;
else
*w_timeout_p = (DWORD)ms;
return 1;
}
#if defined(OPENSSL_THREADS_WINNT_LEGACY)
#include <assert.h>
typedef struct legacy_condvar_st {
CRYPTO_MUTEX *int_m;
HANDLE sema;
HANDLE prewait_sema;
size_t num_wait;
size_t num_wake;
size_t num_prewait;
size_t gen;
int closed;
} LEGACY_CONDVAR;
CRYPTO_CONDVAR *ossl_crypto_condvar_new(void)
{
LEGACY_CONDVAR *cv;
if ((cv = OPENSSL_malloc(sizeof(LEGACY_CONDVAR))) == NULL)
return NULL;
if ((cv->int_m = ossl_crypto_mutex_new()) == NULL) {
OPENSSL_free(cv);
return NULL;
}
if ((cv->sema = CreateSemaphoreA(NULL, 0, LONG_MAX, NULL)) == NULL) {
ossl_crypto_mutex_free(&cv->int_m);
OPENSSL_free(cv);
return NULL;
}
if ((cv->prewait_sema = CreateSemaphoreA(NULL, 0, LONG_MAX, NULL)) == NULL) {
CloseHandle(cv->sema);
ossl_crypto_mutex_free(&cv->int_m);
OPENSSL_free(cv);
return NULL;
}
cv->num_wait = 0;
cv->num_wake = 0;
cv->num_prewait = 0;
cv->closed = 0;
return (CRYPTO_CONDVAR *)cv;
}
void ossl_crypto_condvar_free(CRYPTO_CONDVAR **cv_p)
{
if (*cv_p != NULL) {
LEGACY_CONDVAR *cv = *(LEGACY_CONDVAR **)cv_p;
CloseHandle(cv->sema);
CloseHandle(cv->prewait_sema);
ossl_crypto_mutex_free(&cv->int_m);
OPENSSL_free(cv);
}
*cv_p = NULL;
}
static uint32_t obj_wait(HANDLE h, OSSL_TIME deadline)
{
DWORD timeout;
if (!determine_timeout(deadline, &timeout))
timeout = 1;
return WaitForSingleObject(h, timeout);
}
void ossl_crypto_condvar_wait_timeout(CRYPTO_CONDVAR *cv_, CRYPTO_MUTEX *ext_m,
OSSL_TIME deadline)
{
LEGACY_CONDVAR *cv = (LEGACY_CONDVAR *)cv_;
int closed, set_prewait = 0, have_orig_gen = 0;
uint32_t rc;
size_t orig_gen;
do {
ossl_crypto_mutex_lock(cv->int_m);
closed = cv->closed;
if (!have_orig_gen) {
orig_gen = cv->gen;
have_orig_gen = 1;
} else if (cv->gen != orig_gen) {
set_prewait = 0;
orig_gen = cv->gen;
}
if (!closed) {
++cv->num_wait;
if (set_prewait) {
--cv->num_prewait;
set_prewait = 0;
}
} else if (!set_prewait) {
++cv->num_prewait;
set_prewait = 1;
}
ossl_crypto_mutex_unlock(cv->int_m);
if (closed)
if (obj_wait(cv->prewait_sema, deadline) != WAIT_OBJECT_0) {
ossl_crypto_mutex_lock(cv->int_m);
if (set_prewait && cv->gen == orig_gen)
--cv->num_prewait;
ossl_crypto_mutex_unlock(cv->int_m);
return;
}
} while (closed);
ossl_crypto_mutex_unlock(ext_m);
for (;;) {
rc = obj_wait(cv->sema, deadline);
ossl_crypto_mutex_lock(cv->int_m);
if (cv->num_wake > 0) {
--cv->num_wake;
if (cv->num_wake == 0 && cv->closed) {
cv->closed = 0;
if (cv->num_prewait > 0) {
ReleaseSemaphore(cv->prewait_sema, (LONG)cv->num_prewait, NULL);
cv->num_prewait = 0;
++cv->gen;
}
}
} else if (rc == WAIT_OBJECT_0) {
ossl_crypto_mutex_unlock(cv->int_m);
continue;
} else {
assert(cv->num_wait > 0);
--cv->num_wait;
}
break;
}
ossl_crypto_mutex_unlock(cv->int_m);
ossl_crypto_mutex_lock(ext_m);
}
void ossl_crypto_condvar_wait(CRYPTO_CONDVAR *cv, CRYPTO_MUTEX *ext_m)
{
ossl_crypto_condvar_wait_timeout(cv, ext_m, ossl_time_infinite());
}
void ossl_crypto_condvar_broadcast(CRYPTO_CONDVAR *cv_)
{
LEGACY_CONDVAR *cv = (LEGACY_CONDVAR *)cv_;
size_t num_wake;
ossl_crypto_mutex_lock(cv->int_m);
num_wake = cv->num_wait;
if (num_wake == 0) {
ossl_crypto_mutex_unlock(cv->int_m);
return;
}
cv->num_wake += num_wake;
cv->num_wait -= num_wake;
cv->closed = 1;
ossl_crypto_mutex_unlock(cv->int_m);
ReleaseSemaphore(cv->sema, (LONG)num_wake, NULL);
}
void ossl_crypto_condvar_signal(CRYPTO_CONDVAR *cv_)
{
LEGACY_CONDVAR *cv = (LEGACY_CONDVAR *)cv_;
ossl_crypto_mutex_lock(cv->int_m);
if (cv->num_wait == 0) {
ossl_crypto_mutex_unlock(cv->int_m);
return;
}
--cv->num_wait;
++cv->num_wake;
ossl_crypto_mutex_unlock(cv->int_m);
ReleaseSemaphore(cv->sema, 1, NULL);
}
#else
CRYPTO_CONDVAR *ossl_crypto_condvar_new(void)
{
CONDITION_VARIABLE *cv_p;
if ((cv_p = OPENSSL_zalloc(sizeof(*cv_p))) == NULL)
return NULL;
InitializeConditionVariable(cv_p);
return (CRYPTO_CONDVAR *)cv_p;
}
void ossl_crypto_condvar_wait(CRYPTO_CONDVAR *cv, CRYPTO_MUTEX *mutex)
{
CONDITION_VARIABLE *cv_p;
CRITICAL_SECTION *mutex_p;
cv_p = (CONDITION_VARIABLE *)cv;
mutex_p = (CRITICAL_SECTION *)mutex;
SleepConditionVariableCS(cv_p, mutex_p, INFINITE);
}
void ossl_crypto_condvar_wait_timeout(CRYPTO_CONDVAR *cv, CRYPTO_MUTEX *mutex,
OSSL_TIME deadline)
{
DWORD timeout;
CONDITION_VARIABLE *cv_p = (CONDITION_VARIABLE *)cv;
CRITICAL_SECTION *mutex_p = (CRITICAL_SECTION *)mutex;
if (!determine_timeout(deadline, &timeout))
timeout = 1;
SleepConditionVariableCS(cv_p, mutex_p, timeout);
}
void ossl_crypto_condvar_broadcast(CRYPTO_CONDVAR *cv)
{
CONDITION_VARIABLE *cv_p;
cv_p = (CONDITION_VARIABLE *)cv;
WakeAllConditionVariable(cv_p);
}
void ossl_crypto_condvar_signal(CRYPTO_CONDVAR *cv)
{
CONDITION_VARIABLE *cv_p;
cv_p = (CONDITION_VARIABLE *)cv;
WakeConditionVariable(cv_p);
}
void ossl_crypto_condvar_free(CRYPTO_CONDVAR **cv)
{
CONDITION_VARIABLE **cv_p;
cv_p = (CONDITION_VARIABLE **)cv;
OPENSSL_free(*cv_p);
*cv_p = NULL;
}
#endif
void ossl_crypto_mem_barrier(void)
{
MemoryBarrier();
}
#endif