1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * C11 <threads.h> emulation library 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * (C) Copyright yohhoy 2012. 5bf215546Sopenharmony_ci * Distributed under the Boost Software License, Version 1.0. 6bf215546Sopenharmony_ci * 7bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person or organization 8bf215546Sopenharmony_ci * obtaining a copy of the software and accompanying documentation covered by 9bf215546Sopenharmony_ci * this license (the "Software") to use, reproduce, display, distribute, 10bf215546Sopenharmony_ci * execute, and transmit the Software, and to prepare [[derivative work]]s of the 11bf215546Sopenharmony_ci * Software, and to permit third-parties to whom the Software is furnished to 12bf215546Sopenharmony_ci * do so, all subject to the following: 13bf215546Sopenharmony_ci * 14bf215546Sopenharmony_ci * The copyright notices in the Software and this entire statement, including 15bf215546Sopenharmony_ci * the above license grant, this restriction and the following disclaimer, 16bf215546Sopenharmony_ci * must be included in all copies of the Software, in whole or in part, and 17bf215546Sopenharmony_ci * all derivative works of the Software, unless such copies or derivative 18bf215546Sopenharmony_ci * works are solely in the form of machine-executable object code generated by 19bf215546Sopenharmony_ci * a source language processor. 20bf215546Sopenharmony_ci * 21bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 24bf215546Sopenharmony_ci * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 25bf215546Sopenharmony_ci * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 26bf215546Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 27bf215546Sopenharmony_ci * DEALINGS IN THE SOFTWARE. 28bf215546Sopenharmony_ci */ 29bf215546Sopenharmony_ci#include <assert.h> 30bf215546Sopenharmony_ci#include <limits.h> 31bf215546Sopenharmony_ci#include <errno.h> 32bf215546Sopenharmony_ci#include <process.h> // MSVCRT 33bf215546Sopenharmony_ci#include <stdlib.h> 34bf215546Sopenharmony_ci 35bf215546Sopenharmony_ci#include "c11/threads.h" 36bf215546Sopenharmony_ci 37bf215546Sopenharmony_ci#ifndef WIN32_LEAN_AND_MEAN 38bf215546Sopenharmony_ci#define WIN32_LEAN_AND_MEAN 1 39bf215546Sopenharmony_ci#endif 40bf215546Sopenharmony_ci#include <windows.h> 41bf215546Sopenharmony_ci 42bf215546Sopenharmony_ci/* 43bf215546Sopenharmony_ciConfiguration macro: 44bf215546Sopenharmony_ci 45bf215546Sopenharmony_ci EMULATED_THREADS_USE_NATIVE_CALL_ONCE 46bf215546Sopenharmony_ci Use native WindowsAPI one-time initialization function. 47bf215546Sopenharmony_ci (requires WinVista or later) 48bf215546Sopenharmony_ci Otherwise emulate by mtx_trylock() + *busy loop* for WinXP. 49bf215546Sopenharmony_ci 50bf215546Sopenharmony_ci EMULATED_THREADS_TSS_DTOR_SLOTNUM 51bf215546Sopenharmony_ci Max registerable TSS dtor number. 52bf215546Sopenharmony_ci*/ 53bf215546Sopenharmony_ci 54bf215546Sopenharmony_ci#if _WIN32_WINNT >= 0x0600 55bf215546Sopenharmony_ci// Prefer native WindowsAPI on newer environment. 56bf215546Sopenharmony_ci#if !defined(__MINGW32__) 57bf215546Sopenharmony_ci#define EMULATED_THREADS_USE_NATIVE_CALL_ONCE 58bf215546Sopenharmony_ci#endif 59bf215546Sopenharmony_ci#endif 60bf215546Sopenharmony_ci#define EMULATED_THREADS_TSS_DTOR_SLOTNUM 64 // see TLS_MINIMUM_AVAILABLE 61bf215546Sopenharmony_ci 62bf215546Sopenharmony_ci// check configuration 63bf215546Sopenharmony_ci#if defined(EMULATED_THREADS_USE_NATIVE_CALL_ONCE) && (_WIN32_WINNT < 0x0600) 64bf215546Sopenharmony_ci#error EMULATED_THREADS_USE_NATIVE_CALL_ONCE requires _WIN32_WINNT>=0x0600 65bf215546Sopenharmony_ci#endif 66bf215546Sopenharmony_ci 67bf215546Sopenharmony_ci 68bf215546Sopenharmony_cistatic_assert(sizeof(cnd_t) == sizeof(CONDITION_VARIABLE), "The size of cnd_t must equal to CONDITION_VARIABLE"); 69bf215546Sopenharmony_cistatic_assert(sizeof(thrd_t) == sizeof(HANDLE), "The size of thrd_t must equal to HANDLE"); 70bf215546Sopenharmony_cistatic_assert(sizeof(tss_t) == sizeof(DWORD), "The size of tss_t must equal to DWORD"); 71bf215546Sopenharmony_cistatic_assert(sizeof(mtx_t) == sizeof(CRITICAL_SECTION), "The size of mtx_t must equal to CRITICAL_SECTION"); 72bf215546Sopenharmony_cistatic_assert(sizeof(once_flag) == sizeof(INIT_ONCE), "The size of once_flag must equal to INIT_ONCE"); 73bf215546Sopenharmony_ci 74bf215546Sopenharmony_ci/* 75bf215546Sopenharmony_ciImplementation limits: 76bf215546Sopenharmony_ci - Conditionally emulation for "Initialization functions" 77bf215546Sopenharmony_ci (see EMULATED_THREADS_USE_NATIVE_CALL_ONCE macro) 78bf215546Sopenharmony_ci - Emulated `mtx_timelock()' with mtx_trylock() + *busy loop* 79bf215546Sopenharmony_ci*/ 80bf215546Sopenharmony_cistatic void impl_tss_dtor_invoke(void); // forward decl. 81bf215546Sopenharmony_ci 82bf215546Sopenharmony_cistruct impl_thrd_param { 83bf215546Sopenharmony_ci thrd_start_t func; 84bf215546Sopenharmony_ci void *arg; 85bf215546Sopenharmony_ci}; 86bf215546Sopenharmony_ci 87bf215546Sopenharmony_cistatic unsigned __stdcall impl_thrd_routine(void *p) 88bf215546Sopenharmony_ci{ 89bf215546Sopenharmony_ci struct impl_thrd_param pack; 90bf215546Sopenharmony_ci int code; 91bf215546Sopenharmony_ci memcpy(&pack, p, sizeof(struct impl_thrd_param)); 92bf215546Sopenharmony_ci free(p); 93bf215546Sopenharmony_ci code = pack.func(pack.arg); 94bf215546Sopenharmony_ci impl_tss_dtor_invoke(); 95bf215546Sopenharmony_ci return (unsigned)code; 96bf215546Sopenharmony_ci} 97bf215546Sopenharmony_ci 98bf215546Sopenharmony_cistatic time_t impl_timespec2msec(const struct timespec *ts) 99bf215546Sopenharmony_ci{ 100bf215546Sopenharmony_ci return (ts->tv_sec * 1000U) + (ts->tv_nsec / 1000000L); 101bf215546Sopenharmony_ci} 102bf215546Sopenharmony_ci 103bf215546Sopenharmony_cistatic DWORD impl_abs2relmsec(const struct timespec *abs_time) 104bf215546Sopenharmony_ci{ 105bf215546Sopenharmony_ci const time_t abs_ms = impl_timespec2msec(abs_time); 106bf215546Sopenharmony_ci struct timespec now; 107bf215546Sopenharmony_ci timespec_get(&now, TIME_UTC); 108bf215546Sopenharmony_ci const time_t now_ms = impl_timespec2msec(&now); 109bf215546Sopenharmony_ci const DWORD rel_ms = (abs_ms > now_ms) ? (DWORD)(abs_ms - now_ms) : 0; 110bf215546Sopenharmony_ci return rel_ms; 111bf215546Sopenharmony_ci} 112bf215546Sopenharmony_ci 113bf215546Sopenharmony_ci#ifdef EMULATED_THREADS_USE_NATIVE_CALL_ONCE 114bf215546Sopenharmony_cistruct impl_call_once_param { void (*func)(void); }; 115bf215546Sopenharmony_cistatic BOOL CALLBACK impl_call_once_callback(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context) 116bf215546Sopenharmony_ci{ 117bf215546Sopenharmony_ci struct impl_call_once_param *param = (struct impl_call_once_param*)Parameter; 118bf215546Sopenharmony_ci (param->func)(); 119bf215546Sopenharmony_ci ((void)InitOnce); ((void)Context); // suppress warning 120bf215546Sopenharmony_ci return TRUE; 121bf215546Sopenharmony_ci} 122bf215546Sopenharmony_ci#endif // ifdef EMULATED_THREADS_USE_NATIVE_CALL_ONCE 123bf215546Sopenharmony_ci 124bf215546Sopenharmony_cistatic struct impl_tss_dtor_entry { 125bf215546Sopenharmony_ci tss_t key; 126bf215546Sopenharmony_ci tss_dtor_t dtor; 127bf215546Sopenharmony_ci} impl_tss_dtor_tbl[EMULATED_THREADS_TSS_DTOR_SLOTNUM]; 128bf215546Sopenharmony_ci 129bf215546Sopenharmony_cistatic int impl_tss_dtor_register(tss_t key, tss_dtor_t dtor) 130bf215546Sopenharmony_ci{ 131bf215546Sopenharmony_ci int i; 132bf215546Sopenharmony_ci for (i = 0; i < EMULATED_THREADS_TSS_DTOR_SLOTNUM; i++) { 133bf215546Sopenharmony_ci if (!impl_tss_dtor_tbl[i].dtor) 134bf215546Sopenharmony_ci break; 135bf215546Sopenharmony_ci } 136bf215546Sopenharmony_ci if (i == EMULATED_THREADS_TSS_DTOR_SLOTNUM) 137bf215546Sopenharmony_ci return 1; 138bf215546Sopenharmony_ci impl_tss_dtor_tbl[i].key = key; 139bf215546Sopenharmony_ci impl_tss_dtor_tbl[i].dtor = dtor; 140bf215546Sopenharmony_ci return 0; 141bf215546Sopenharmony_ci} 142bf215546Sopenharmony_ci 143bf215546Sopenharmony_cistatic void impl_tss_dtor_invoke(void) 144bf215546Sopenharmony_ci{ 145bf215546Sopenharmony_ci int i; 146bf215546Sopenharmony_ci for (i = 0; i < EMULATED_THREADS_TSS_DTOR_SLOTNUM; i++) { 147bf215546Sopenharmony_ci if (impl_tss_dtor_tbl[i].dtor) { 148bf215546Sopenharmony_ci void* val = tss_get(impl_tss_dtor_tbl[i].key); 149bf215546Sopenharmony_ci if (val) 150bf215546Sopenharmony_ci (impl_tss_dtor_tbl[i].dtor)(val); 151bf215546Sopenharmony_ci } 152bf215546Sopenharmony_ci } 153bf215546Sopenharmony_ci} 154bf215546Sopenharmony_ci 155bf215546Sopenharmony_ci 156bf215546Sopenharmony_ci/*--------------- 7.25.2 Initialization functions ---------------*/ 157bf215546Sopenharmony_ci// 7.25.2.1 158bf215546Sopenharmony_civoid 159bf215546Sopenharmony_cicall_once(once_flag *flag, void (*func)(void)) 160bf215546Sopenharmony_ci{ 161bf215546Sopenharmony_ci assert(flag && func); 162bf215546Sopenharmony_ci#ifdef EMULATED_THREADS_USE_NATIVE_CALL_ONCE 163bf215546Sopenharmony_ci { 164bf215546Sopenharmony_ci struct impl_call_once_param param; 165bf215546Sopenharmony_ci param.func = func; 166bf215546Sopenharmony_ci InitOnceExecuteOnce((PINIT_ONCE)flag, impl_call_once_callback, (PVOID)¶m, NULL); 167bf215546Sopenharmony_ci } 168bf215546Sopenharmony_ci#else 169bf215546Sopenharmony_ci if (InterlockedCompareExchangePointer((PVOID volatile *)&flag->status, (PVOID)1, (PVOID)0) == 0) { 170bf215546Sopenharmony_ci (func)(); 171bf215546Sopenharmony_ci InterlockedExchangePointer((PVOID volatile *)&flag->status, (PVOID)2); 172bf215546Sopenharmony_ci } else { 173bf215546Sopenharmony_ci while (flag->status == 1) { 174bf215546Sopenharmony_ci // busy loop! 175bf215546Sopenharmony_ci thrd_yield(); 176bf215546Sopenharmony_ci } 177bf215546Sopenharmony_ci } 178bf215546Sopenharmony_ci#endif 179bf215546Sopenharmony_ci} 180bf215546Sopenharmony_ci 181bf215546Sopenharmony_ci 182bf215546Sopenharmony_ci/*------------- 7.25.3 Condition variable functions -------------*/ 183bf215546Sopenharmony_ci// 7.25.3.1 184bf215546Sopenharmony_ciint 185bf215546Sopenharmony_cicnd_broadcast(cnd_t *cond) 186bf215546Sopenharmony_ci{ 187bf215546Sopenharmony_ci assert(cond != NULL); 188bf215546Sopenharmony_ci WakeAllConditionVariable((PCONDITION_VARIABLE)cond); 189bf215546Sopenharmony_ci return thrd_success; 190bf215546Sopenharmony_ci} 191bf215546Sopenharmony_ci 192bf215546Sopenharmony_ci// 7.25.3.2 193bf215546Sopenharmony_civoid 194bf215546Sopenharmony_cicnd_destroy(cnd_t *cond) 195bf215546Sopenharmony_ci{ 196bf215546Sopenharmony_ci (void)cond; 197bf215546Sopenharmony_ci assert(cond != NULL); 198bf215546Sopenharmony_ci // do nothing 199bf215546Sopenharmony_ci} 200bf215546Sopenharmony_ci 201bf215546Sopenharmony_ci// 7.25.3.3 202bf215546Sopenharmony_ciint 203bf215546Sopenharmony_cicnd_init(cnd_t *cond) 204bf215546Sopenharmony_ci{ 205bf215546Sopenharmony_ci assert(cond != NULL); 206bf215546Sopenharmony_ci InitializeConditionVariable((PCONDITION_VARIABLE)cond); 207bf215546Sopenharmony_ci return thrd_success; 208bf215546Sopenharmony_ci} 209bf215546Sopenharmony_ci 210bf215546Sopenharmony_ci// 7.25.3.4 211bf215546Sopenharmony_ciint 212bf215546Sopenharmony_cicnd_signal(cnd_t *cond) 213bf215546Sopenharmony_ci{ 214bf215546Sopenharmony_ci assert(cond != NULL); 215bf215546Sopenharmony_ci WakeConditionVariable((PCONDITION_VARIABLE)cond); 216bf215546Sopenharmony_ci return thrd_success; 217bf215546Sopenharmony_ci} 218bf215546Sopenharmony_ci 219bf215546Sopenharmony_ci// 7.25.3.5 220bf215546Sopenharmony_ciint 221bf215546Sopenharmony_cicnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *abs_time) 222bf215546Sopenharmony_ci{ 223bf215546Sopenharmony_ci assert(cond != NULL); 224bf215546Sopenharmony_ci assert(mtx != NULL); 225bf215546Sopenharmony_ci assert(abs_time != NULL); 226bf215546Sopenharmony_ci const DWORD timeout = impl_abs2relmsec(abs_time); 227bf215546Sopenharmony_ci if (SleepConditionVariableCS((PCONDITION_VARIABLE)cond, (PCRITICAL_SECTION)mtx, timeout)) 228bf215546Sopenharmony_ci return thrd_success; 229bf215546Sopenharmony_ci return (GetLastError() == ERROR_TIMEOUT) ? thrd_timedout : thrd_error; 230bf215546Sopenharmony_ci} 231bf215546Sopenharmony_ci 232bf215546Sopenharmony_ci// 7.25.3.6 233bf215546Sopenharmony_ciint 234bf215546Sopenharmony_cicnd_wait(cnd_t *cond, mtx_t *mtx) 235bf215546Sopenharmony_ci{ 236bf215546Sopenharmony_ci assert(cond != NULL); 237bf215546Sopenharmony_ci assert(mtx != NULL); 238bf215546Sopenharmony_ci SleepConditionVariableCS((PCONDITION_VARIABLE)cond, (PCRITICAL_SECTION)mtx, INFINITE); 239bf215546Sopenharmony_ci return thrd_success; 240bf215546Sopenharmony_ci} 241bf215546Sopenharmony_ci 242bf215546Sopenharmony_ci 243bf215546Sopenharmony_ci/*-------------------- 7.25.4 Mutex functions --------------------*/ 244bf215546Sopenharmony_ci// 7.25.4.1 245bf215546Sopenharmony_civoid 246bf215546Sopenharmony_cimtx_destroy(mtx_t *mtx) 247bf215546Sopenharmony_ci{ 248bf215546Sopenharmony_ci assert(mtx); 249bf215546Sopenharmony_ci DeleteCriticalSection((PCRITICAL_SECTION)mtx); 250bf215546Sopenharmony_ci} 251bf215546Sopenharmony_ci 252bf215546Sopenharmony_ci// 7.25.4.2 253bf215546Sopenharmony_ciint 254bf215546Sopenharmony_cimtx_init(mtx_t *mtx, int type) 255bf215546Sopenharmony_ci{ 256bf215546Sopenharmony_ci assert(mtx != NULL); 257bf215546Sopenharmony_ci if (type != mtx_plain && type != mtx_timed && type != mtx_try 258bf215546Sopenharmony_ci && type != (mtx_plain|mtx_recursive) 259bf215546Sopenharmony_ci && type != (mtx_timed|mtx_recursive) 260bf215546Sopenharmony_ci && type != (mtx_try|mtx_recursive)) 261bf215546Sopenharmony_ci return thrd_error; 262bf215546Sopenharmony_ci InitializeCriticalSection((PCRITICAL_SECTION)mtx); 263bf215546Sopenharmony_ci return thrd_success; 264bf215546Sopenharmony_ci} 265bf215546Sopenharmony_ci 266bf215546Sopenharmony_ci// 7.25.4.3 267bf215546Sopenharmony_ciint 268bf215546Sopenharmony_cimtx_lock(mtx_t *mtx) 269bf215546Sopenharmony_ci{ 270bf215546Sopenharmony_ci assert(mtx != NULL); 271bf215546Sopenharmony_ci EnterCriticalSection((PCRITICAL_SECTION)mtx); 272bf215546Sopenharmony_ci return thrd_success; 273bf215546Sopenharmony_ci} 274bf215546Sopenharmony_ci 275bf215546Sopenharmony_ci// 7.25.4.4 276bf215546Sopenharmony_ciint 277bf215546Sopenharmony_cimtx_timedlock(mtx_t *mtx, const struct timespec *ts) 278bf215546Sopenharmony_ci{ 279bf215546Sopenharmony_ci assert(mtx != NULL); 280bf215546Sopenharmony_ci assert(ts != NULL); 281bf215546Sopenharmony_ci while (mtx_trylock(mtx) != thrd_success) { 282bf215546Sopenharmony_ci if (impl_abs2relmsec(ts) == 0) 283bf215546Sopenharmony_ci return thrd_timedout; 284bf215546Sopenharmony_ci // busy loop! 285bf215546Sopenharmony_ci thrd_yield(); 286bf215546Sopenharmony_ci } 287bf215546Sopenharmony_ci return thrd_success; 288bf215546Sopenharmony_ci} 289bf215546Sopenharmony_ci 290bf215546Sopenharmony_ci// 7.25.4.5 291bf215546Sopenharmony_ciint 292bf215546Sopenharmony_cimtx_trylock(mtx_t *mtx) 293bf215546Sopenharmony_ci{ 294bf215546Sopenharmony_ci assert(mtx != NULL); 295bf215546Sopenharmony_ci return TryEnterCriticalSection((PCRITICAL_SECTION)mtx) ? thrd_success : thrd_busy; 296bf215546Sopenharmony_ci} 297bf215546Sopenharmony_ci 298bf215546Sopenharmony_ci// 7.25.4.6 299bf215546Sopenharmony_ciint 300bf215546Sopenharmony_cimtx_unlock(mtx_t *mtx) 301bf215546Sopenharmony_ci{ 302bf215546Sopenharmony_ci assert(mtx != NULL); 303bf215546Sopenharmony_ci LeaveCriticalSection((PCRITICAL_SECTION)mtx); 304bf215546Sopenharmony_ci return thrd_success; 305bf215546Sopenharmony_ci} 306bf215546Sopenharmony_ci 307bf215546Sopenharmony_ci 308bf215546Sopenharmony_ci/*------------------- 7.25.5 Thread functions -------------------*/ 309bf215546Sopenharmony_ci// 7.25.5.1 310bf215546Sopenharmony_ciint 311bf215546Sopenharmony_cithrd_create(thrd_t *thr, thrd_start_t func, void *arg) 312bf215546Sopenharmony_ci{ 313bf215546Sopenharmony_ci struct impl_thrd_param *pack; 314bf215546Sopenharmony_ci uintptr_t handle; 315bf215546Sopenharmony_ci assert(thr != NULL); 316bf215546Sopenharmony_ci pack = (struct impl_thrd_param *)malloc(sizeof(struct impl_thrd_param)); 317bf215546Sopenharmony_ci if (!pack) return thrd_nomem; 318bf215546Sopenharmony_ci pack->func = func; 319bf215546Sopenharmony_ci pack->arg = arg; 320bf215546Sopenharmony_ci handle = _beginthreadex(NULL, 0, impl_thrd_routine, pack, 0, NULL); 321bf215546Sopenharmony_ci if (handle == 0) { 322bf215546Sopenharmony_ci free(pack); 323bf215546Sopenharmony_ci if (errno == EAGAIN || errno == EACCES) 324bf215546Sopenharmony_ci return thrd_nomem; 325bf215546Sopenharmony_ci return thrd_error; 326bf215546Sopenharmony_ci } 327bf215546Sopenharmony_ci *thr = (thrd_t)handle; 328bf215546Sopenharmony_ci return thrd_success; 329bf215546Sopenharmony_ci} 330bf215546Sopenharmony_ci 331bf215546Sopenharmony_ci#if 0 332bf215546Sopenharmony_ci// 7.25.5.2 333bf215546Sopenharmony_cistatic inline thrd_t 334bf215546Sopenharmony_cithrd_current(void) 335bf215546Sopenharmony_ci{ 336bf215546Sopenharmony_ci HANDLE hCurrentThread; 337bf215546Sopenharmony_ci BOOL bRet; 338bf215546Sopenharmony_ci 339bf215546Sopenharmony_ci /* GetCurrentThread() returns a pseudo-handle, which we need 340bf215546Sopenharmony_ci * to pass to DuplicateHandle(). Only the resulting handle can be used 341bf215546Sopenharmony_ci * from other threads. 342bf215546Sopenharmony_ci * 343bf215546Sopenharmony_ci * Note that neither handle can be compared to the one by thread_create. 344bf215546Sopenharmony_ci * Only the thread IDs - as returned by GetThreadId() and GetCurrentThreadId() 345bf215546Sopenharmony_ci * can be compared directly. 346bf215546Sopenharmony_ci * 347bf215546Sopenharmony_ci * Other potential solutions would be: 348bf215546Sopenharmony_ci * - define thrd_t as a thread Ids, but this would mean we'd need to OpenThread for many operations 349bf215546Sopenharmony_ci * - use malloc'ed memory for thrd_t. This would imply using TLS for current thread. 350bf215546Sopenharmony_ci * 351bf215546Sopenharmony_ci * Neither is particularly nice. 352bf215546Sopenharmony_ci * 353bf215546Sopenharmony_ci * Life would be much easier if C11 threads had different abstractions for 354bf215546Sopenharmony_ci * threads and thread IDs, just like C++11 threads does... 355bf215546Sopenharmony_ci */ 356bf215546Sopenharmony_ci 357bf215546Sopenharmony_ci bRet = DuplicateHandle(GetCurrentProcess(), // source process (pseudo) handle 358bf215546Sopenharmony_ci GetCurrentThread(), // source (pseudo) handle 359bf215546Sopenharmony_ci GetCurrentProcess(), // target process 360bf215546Sopenharmony_ci &hCurrentThread, // target handle 361bf215546Sopenharmony_ci 0, 362bf215546Sopenharmony_ci FALSE, 363bf215546Sopenharmony_ci DUPLICATE_SAME_ACCESS); 364bf215546Sopenharmony_ci assert(bRet); 365bf215546Sopenharmony_ci if (!bRet) { 366bf215546Sopenharmony_ci hCurrentThread = GetCurrentThread(); 367bf215546Sopenharmony_ci } 368bf215546Sopenharmony_ci return hCurrentThread; 369bf215546Sopenharmony_ci} 370bf215546Sopenharmony_ci#endif 371bf215546Sopenharmony_ci 372bf215546Sopenharmony_ci// 7.25.5.3 373bf215546Sopenharmony_ciint 374bf215546Sopenharmony_cithrd_detach(thrd_t thr) 375bf215546Sopenharmony_ci{ 376bf215546Sopenharmony_ci CloseHandle(thr); 377bf215546Sopenharmony_ci return thrd_success; 378bf215546Sopenharmony_ci} 379bf215546Sopenharmony_ci 380bf215546Sopenharmony_ci// 7.25.5.4 381bf215546Sopenharmony_ciint 382bf215546Sopenharmony_cithrd_equal(thrd_t thr0, thrd_t thr1) 383bf215546Sopenharmony_ci{ 384bf215546Sopenharmony_ci return GetThreadId(thr0) == GetThreadId(thr1); 385bf215546Sopenharmony_ci} 386bf215546Sopenharmony_ci 387bf215546Sopenharmony_ci// 7.25.5.5 388bf215546Sopenharmony_ci_Noreturn 389bf215546Sopenharmony_civoid 390bf215546Sopenharmony_cithrd_exit(int res) 391bf215546Sopenharmony_ci{ 392bf215546Sopenharmony_ci impl_tss_dtor_invoke(); 393bf215546Sopenharmony_ci _endthreadex((unsigned)res); 394bf215546Sopenharmony_ci} 395bf215546Sopenharmony_ci 396bf215546Sopenharmony_ci// 7.25.5.6 397bf215546Sopenharmony_ciint 398bf215546Sopenharmony_cithrd_join(thrd_t thr, int *res) 399bf215546Sopenharmony_ci{ 400bf215546Sopenharmony_ci DWORD w, code; 401bf215546Sopenharmony_ci w = WaitForSingleObject(thr, INFINITE); 402bf215546Sopenharmony_ci if (w != WAIT_OBJECT_0) 403bf215546Sopenharmony_ci return thrd_error; 404bf215546Sopenharmony_ci if (res) { 405bf215546Sopenharmony_ci if (!GetExitCodeThread(thr, &code)) { 406bf215546Sopenharmony_ci CloseHandle(thr); 407bf215546Sopenharmony_ci return thrd_error; 408bf215546Sopenharmony_ci } 409bf215546Sopenharmony_ci *res = (int)code; 410bf215546Sopenharmony_ci } 411bf215546Sopenharmony_ci CloseHandle(thr); 412bf215546Sopenharmony_ci return thrd_success; 413bf215546Sopenharmony_ci} 414bf215546Sopenharmony_ci 415bf215546Sopenharmony_ci// 7.25.5.7 416bf215546Sopenharmony_ciint 417bf215546Sopenharmony_cithrd_sleep(const struct timespec *time_point, struct timespec *remaining) 418bf215546Sopenharmony_ci{ 419bf215546Sopenharmony_ci (void)remaining; 420bf215546Sopenharmony_ci assert(time_point); 421bf215546Sopenharmony_ci assert(!remaining); /* not implemented */ 422bf215546Sopenharmony_ci Sleep((DWORD)impl_timespec2msec(time_point)); 423bf215546Sopenharmony_ci return 0; 424bf215546Sopenharmony_ci} 425bf215546Sopenharmony_ci 426bf215546Sopenharmony_ci// 7.25.5.8 427bf215546Sopenharmony_civoid 428bf215546Sopenharmony_cithrd_yield(void) 429bf215546Sopenharmony_ci{ 430bf215546Sopenharmony_ci SwitchToThread(); 431bf215546Sopenharmony_ci} 432bf215546Sopenharmony_ci 433bf215546Sopenharmony_ci 434bf215546Sopenharmony_ci/*----------- 7.25.6 Thread-specific storage functions -----------*/ 435bf215546Sopenharmony_ci// 7.25.6.1 436bf215546Sopenharmony_ciint 437bf215546Sopenharmony_citss_create(tss_t *key, tss_dtor_t dtor) 438bf215546Sopenharmony_ci{ 439bf215546Sopenharmony_ci assert(key != NULL); 440bf215546Sopenharmony_ci *key = TlsAlloc(); 441bf215546Sopenharmony_ci if (dtor) { 442bf215546Sopenharmony_ci if (impl_tss_dtor_register(*key, dtor)) { 443bf215546Sopenharmony_ci TlsFree(*key); 444bf215546Sopenharmony_ci return thrd_error; 445bf215546Sopenharmony_ci } 446bf215546Sopenharmony_ci } 447bf215546Sopenharmony_ci return (*key != 0xFFFFFFFF) ? thrd_success : thrd_error; 448bf215546Sopenharmony_ci} 449bf215546Sopenharmony_ci 450bf215546Sopenharmony_ci// 7.25.6.2 451bf215546Sopenharmony_civoid 452bf215546Sopenharmony_citss_delete(tss_t key) 453bf215546Sopenharmony_ci{ 454bf215546Sopenharmony_ci TlsFree(key); 455bf215546Sopenharmony_ci} 456bf215546Sopenharmony_ci 457bf215546Sopenharmony_ci// 7.25.6.3 458bf215546Sopenharmony_civoid * 459bf215546Sopenharmony_citss_get(tss_t key) 460bf215546Sopenharmony_ci{ 461bf215546Sopenharmony_ci return TlsGetValue(key); 462bf215546Sopenharmony_ci} 463bf215546Sopenharmony_ci 464bf215546Sopenharmony_ci// 7.25.6.4 465bf215546Sopenharmony_ciint 466bf215546Sopenharmony_citss_set(tss_t key, void *val) 467bf215546Sopenharmony_ci{ 468bf215546Sopenharmony_ci return TlsSetValue(key, val) ? thrd_success : thrd_error; 469bf215546Sopenharmony_ci} 470