diff options
Diffstat (limited to 'kit/threads.win32.c')
-rw-r--r-- | kit/threads.win32.c | 342 |
1 files changed, 0 insertions, 342 deletions
diff --git a/kit/threads.win32.c b/kit/threads.win32.c deleted file mode 100644 index ac185f7..0000000 --- a/kit/threads.win32.c +++ /dev/null @@ -1,342 +0,0 @@ -#include "threads.h" - -#ifndef KIT_DISABLE_SYSTEM_THREADS -# include "allocator.h" - -# if defined(_WIN32) && !defined(__CYGWIN__) -# include <assert.h> -# include <errno.h> -# include <limits.h> -# include <process.h> -# include <stdlib.h> - -# ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN 1 -# endif -# ifndef NOMINMAX -# define NOMINMAX -# endif -# include <windows.h> - -/* -Configuration macro: - - EMULATED_THREADS_USE_NATIVE_CALL_ONCE - Use native WindowsAPI one-time initialization function. - (requires WinVista or later) - Otherwise emulate by mtx_trylock() + *busy loop* for WinXP. -*/ - -# if _WIN32_WINNT >= 0x0600 -/* Prefer native WindowsAPI on newer environment. */ -# if !defined(__MINGW32__) -# define EMULATED_THREADS_USE_NATIVE_CALL_ONCE -# endif -# endif - -/* check configuration */ -# if defined(EMULATED_THREADS_USE_NATIVE_CALL_ONCE) && \ - (_WIN32_WINNT < 0x0600) -# error EMULATED_THREADS_USE_NATIVE_CALL_ONCE requires _WIN32_WINNT>=0x0600 -# endif - -static_assert(sizeof(cnd_t) == sizeof(CONDITION_VARIABLE), - "The size of cnd_t must equal to CONDITION_VARIABLE"); -static_assert(sizeof(thrd_t) == sizeof(HANDLE), - "The size of thrd_t must equal to HANDLE"); -static_assert(sizeof(mtx_t) == sizeof(CRITICAL_SECTION), - "The size of mtx_t must equal to CRITICAL_SECTION"); -static_assert(sizeof(once_flag) == sizeof(INIT_ONCE), - "The size of once_flag must equal to INIT_ONCE"); - -/* -Implementation limits: - - Conditionally emulation for "Initialization functions" - (see EMULATED_THREADS_USE_NATIVE_CALL_ONCE macro) - - Emulated `mtx_timelock()' with mtx_trylock() + *busy loop* -*/ - -typedef struct { - thrd_start_t func; - void *arg; - thrd_t thrd; -} impl_thrd_param_t; - -struct thrd_state { - thrd_t thrd; - int handle_need_close; -}; - -static thread_local struct thrd_state impl_current_thread = { 0 }; - -static unsigned __stdcall impl_thrd_routine(void *p) { - impl_thrd_param_t *pack_p = (impl_thrd_param_t *) p; - impl_thrd_param_t pack; - int code; - impl_current_thread.thrd = pack_p->thrd; - impl_current_thread.handle_need_close = 0; - memcpy(&pack, pack_p, sizeof(impl_thrd_param_t)); - kit_alloc_dispatch(NULL, KIT_DEALLOCATE, 0, 0, p); - code = pack.func(pack.arg); - return (unsigned) code; -} - -static time_t impl_timespec2msec(const struct timespec *ts) { - return (ts->tv_sec * 1000U) + (ts->tv_nsec / 1000000L); -} - -static DWORD impl_abs2relmsec(const struct timespec *abs_time) { - const time_t abs_ms = impl_timespec2msec(abs_time); - struct timespec now; - timespec_get(&now, TIME_UTC); - const time_t now_ms = impl_timespec2msec(&now); - const DWORD rel_ms = (abs_ms > now_ms) ? (DWORD) (abs_ms - now_ms) - : 0; - return rel_ms; -} - -# ifdef EMULATED_THREADS_USE_NATIVE_CALL_ONCE -struct impl_call_once_param { - void (*func)(void); -}; - -static BOOL CALLBACK impl_call_once_callback(PINIT_ONCE InitOnce, - PVOID Parameter, - PVOID *Context) { - struct impl_call_once_param *param = (struct impl_call_once_param *) - Parameter; - (param->func)(); - ((void) InitOnce); - ((void) Context); /* suppress warning */ - return TRUE; -} -# endif /* ifdef EMULATED_THREADS_USE_NATIVE_CALL_ONCE */ - -void call_once(once_flag *flag, void (*func)(void)) { - assert(flag && func); -# ifdef EMULATED_THREADS_USE_NATIVE_CALL_ONCE - { - struct impl_call_once_param param; - param.func = func; - InitOnceExecuteOnce((PINIT_ONCE) flag, impl_call_once_callback, - (PVOID) ¶m, NULL); - } -# else - if (InterlockedCompareExchangePointer( - (PVOID volatile *) &flag->status, (PVOID) 1, (PVOID) 0) == - 0) { - (func)(); - InterlockedExchangePointer((PVOID volatile *) &flag->status, - (PVOID) 2); - } else { - while (flag->status == 1) { - // busy loop! - thrd_yield(); - } - } -# endif -} - -int cnd_broadcast(cnd_t *cond) { - assert(cond != NULL); - WakeAllConditionVariable((PCONDITION_VARIABLE) cond); - return thrd_success; -} - -void cnd_destroy(cnd_t *cond) { - assert(cond != NULL); - /* do nothing */ - (void) cond; -} - -int cnd_init(cnd_t *cond) { - assert(cond != NULL); - InitializeConditionVariable((PCONDITION_VARIABLE) cond); - return thrd_success; -} - -int cnd_signal(cnd_t *cond) { - assert(cond != NULL); - WakeConditionVariable((PCONDITION_VARIABLE) cond); - return thrd_success; -} - -int cnd_timedwait(cnd_t *cond, mtx_t *mtx, - const struct timespec *abs_time) { - assert(cond != NULL); - assert(mtx != NULL); - assert(abs_time != NULL); - const DWORD timeout = impl_abs2relmsec(abs_time); - if (SleepConditionVariableCS((PCONDITION_VARIABLE) cond, - (PCRITICAL_SECTION) mtx, timeout)) - return thrd_success; - return (GetLastError() == ERROR_TIMEOUT) ? thrd_timedout - : thrd_error; -} - -int cnd_wait(cnd_t *cond, mtx_t *mtx) { - assert(cond != NULL); - assert(mtx != NULL); - SleepConditionVariableCS((PCONDITION_VARIABLE) cond, - (PCRITICAL_SECTION) mtx, INFINITE); - return thrd_success; -} - -void mtx_destroy(mtx_t *mtx) { - assert(mtx); - DeleteCriticalSection((PCRITICAL_SECTION) mtx); -} - -int mtx_init(mtx_t *mtx, int type) { - assert(mtx != NULL); - if (type != mtx_plain && type != mtx_timed && - type != (mtx_plain | mtx_recursive) && - type != (mtx_timed | mtx_recursive)) - return thrd_error; - InitializeCriticalSection((PCRITICAL_SECTION) mtx); - return thrd_success; -} - -int mtx_lock(mtx_t *mtx) { - assert(mtx != NULL); - EnterCriticalSection((PCRITICAL_SECTION) mtx); - return thrd_success; -} - -int mtx_timedlock(mtx_t *mtx, const struct timespec *ts) { - assert(mtx != NULL); - assert(ts != NULL); - while (mtx_trylock(mtx) != thrd_success) { - if (impl_abs2relmsec(ts) == 0) - return thrd_timedout; - /* busy loop! */ - thrd_yield(); - } - return thrd_success; -} - -int mtx_trylock(mtx_t *mtx) { - assert(mtx != NULL); - return TryEnterCriticalSection((PCRITICAL_SECTION) mtx) - ? thrd_success - : thrd_busy; -} - -int mtx_unlock(mtx_t *mtx) { - assert(mtx != NULL); - LeaveCriticalSection((PCRITICAL_SECTION) mtx); - return thrd_success; -} - -int thrd_create_with_stack(thrd_t *thr, thrd_start_t func, void *arg, - ptrdiff_t const stack_size) { - impl_thrd_param_t *pack; - uintptr_t handle; - assert(thr != NULL); - assert(stack_size >= 0 && stack_size < 0x100000000); - - pack = (impl_thrd_param_t *) kit_alloc_dispatch( - NULL, KIT_ALLOCATE, (sizeof(impl_thrd_param_t)), 0, NULL); - if (!pack) - return thrd_nomem; - pack->func = func; - pack->arg = arg; - handle = _beginthreadex(NULL, (unsigned) stack_size, - impl_thrd_routine, pack, CREATE_SUSPENDED, - NULL); - if (handle == 0) { - kit_alloc_dispatch(NULL, KIT_DEALLOCATE, 0, 0, pack); - if (errno == EAGAIN || errno == EACCES) - return thrd_nomem; - return thrd_error; - } - thr->handle = (void *) handle; - pack->thrd = *thr; - ResumeThread((HANDLE) handle); - return thrd_success; -} - -int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) { - return thrd_create_with_stack(thr, func, arg, 0); -} - -thrd_t thrd_current(void) { - /* GetCurrentThread() returns a pseudo-handle, which we need - * to pass to DuplicateHandle(). Only the resulting handle can be - * used from other threads. - * - * Note that neither handle can be compared to the one by - * thread_create. Only the thread IDs - as returned by GetThreadId() - * and GetCurrentThreadId() can be compared directly. - * - * Other potential solutions would be: - * - define thrd_t as a thread Ids, but this would mean we'd need to - * OpenThread for many operations - * - use malloc'ed memory for thrd_t. This would imply using TLS for - * current thread. - * - * Neither is particularly nice. - * - * Life would be much easier if C11 threads had different - * abstractions for threads and thread IDs, just like C++11 threads - * does... - */ - struct thrd_state *state = &impl_current_thread; - if (state->thrd.handle == NULL) { - if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), - GetCurrentProcess(), &(state->thrd.handle), - 0, FALSE, DUPLICATE_SAME_ACCESS)) { - abort(); - } - state->handle_need_close = 1; - } - return state->thrd; -} - -int thrd_detach(thrd_t thr) { - CloseHandle(thr.handle); - return thrd_success; -} - -int thrd_equal(thrd_t thr0, thrd_t thr1) { - return GetThreadId(thr0.handle) == GetThreadId(thr1.handle); -} - -_Noreturn void thrd_exit(int res) { - _endthreadex((unsigned) res); -} - -int thrd_join(thrd_t thr, int *res) { - DWORD w, code; - if (thr.handle == NULL) { - return thrd_error; - } - w = WaitForSingleObject(thr.handle, INFINITE); - if (w != WAIT_OBJECT_0) - return thrd_error; - if (res) { - if (!GetExitCodeThread(thr.handle, &code)) { - CloseHandle(thr.handle); - return thrd_error; - } - *res = (int) code; - } - CloseHandle(thr.handle); - return thrd_success; -} - -int thrd_sleep(const struct timespec *time_point, - struct timespec *remaining) { - (void) remaining; - assert(time_point); - assert(!remaining); /* not implemented */ - Sleep((DWORD) impl_timespec2msec(time_point)); - return 0; -} - -void thrd_yield(void) { - SwitchToThread(); -} - -# endif -#endif |