1af69d88dSmrg/* 2af69d88dSmrg * C11 <threads.h> emulation library 3af69d88dSmrg * 4af69d88dSmrg * (C) Copyright yohhoy 2012. 5af69d88dSmrg * Distributed under the Boost Software License, Version 1.0. 6af69d88dSmrg * 7af69d88dSmrg * Permission is hereby granted, free of charge, to any person or organization 8af69d88dSmrg * obtaining a copy of the software and accompanying documentation covered by 9af69d88dSmrg * this license (the "Software") to use, reproduce, display, distribute, 10af69d88dSmrg * execute, and transmit the Software, and to prepare [[derivative work]]s of the 11af69d88dSmrg * Software, and to permit third-parties to whom the Software is furnished to 12af69d88dSmrg * do so, all subject to the following: 13af69d88dSmrg * 14af69d88dSmrg * The copyright notices in the Software and this entire statement, including 15af69d88dSmrg * the above license grant, this restriction and the following disclaimer, 16af69d88dSmrg * must be included in all copies of the Software, in whole or in part, and 17af69d88dSmrg * all derivative works of the Software, unless such copies or derivative 18af69d88dSmrg * works are solely in the form of machine-executable object code generated by 19af69d88dSmrg * a source language processor. 20af69d88dSmrg * 21af69d88dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22af69d88dSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23af69d88dSmrg * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 24af69d88dSmrg * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 25af69d88dSmrg * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 26af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 27af69d88dSmrg * DEALINGS IN THE SOFTWARE. 28af69d88dSmrg */ 29af69d88dSmrg#ifndef assert 30af69d88dSmrg#include <assert.h> 31af69d88dSmrg#endif 32af69d88dSmrg#include <limits.h> 33af69d88dSmrg#include <errno.h> 34af69d88dSmrg#include <process.h> // MSVCRT 35af69d88dSmrg#include <stdlib.h> 36af69d88dSmrg 37af69d88dSmrg/* 38af69d88dSmrgConfiguration macro: 39af69d88dSmrg 40af69d88dSmrg EMULATED_THREADS_USE_NATIVE_CALL_ONCE 41af69d88dSmrg Use native WindowsAPI one-time initialization function. 42af69d88dSmrg (requires WinVista or later) 43af69d88dSmrg Otherwise emulate by mtx_trylock() + *busy loop* for WinXP. 44af69d88dSmrg 45af69d88dSmrg EMULATED_THREADS_TSS_DTOR_SLOTNUM 46af69d88dSmrg Max registerable TSS dtor number. 47af69d88dSmrg*/ 48af69d88dSmrg 49af69d88dSmrg#if _WIN32_WINNT >= 0x0600 50af69d88dSmrg// Prefer native WindowsAPI on newer environment. 51af69d88dSmrg#if !defined(__MINGW32__) 527ec681f3Smrg#define EMULATED_THREADS_USE_NATIVE_CALL_ONCE 53af69d88dSmrg#endif 54af69d88dSmrg#endif 55af69d88dSmrg#define EMULATED_THREADS_TSS_DTOR_SLOTNUM 64 // see TLS_MINIMUM_AVAILABLE 56af69d88dSmrg 57af69d88dSmrg 58af69d88dSmrg#include <windows.h> 59af69d88dSmrg 60af69d88dSmrg// check configuration 61af69d88dSmrg#if defined(EMULATED_THREADS_USE_NATIVE_CALL_ONCE) && (_WIN32_WINNT < 0x0600) 62af69d88dSmrg#error EMULATED_THREADS_USE_NATIVE_CALL_ONCE requires _WIN32_WINNT>=0x0600 63af69d88dSmrg#endif 64af69d88dSmrg 6501e04c3fSmrg/* Visual Studio 2015 and later */ 6601e04c3fSmrg#ifdef _MSC_VER 6701e04c3fSmrg#define HAVE_TIMESPEC_GET 6801e04c3fSmrg#endif 69af69d88dSmrg 70af69d88dSmrg/*---------------------------- macros ----------------------------*/ 71af69d88dSmrg#ifdef EMULATED_THREADS_USE_NATIVE_CALL_ONCE 72af69d88dSmrg#define ONCE_FLAG_INIT INIT_ONCE_STATIC_INIT 73af69d88dSmrg#else 74af69d88dSmrg#define ONCE_FLAG_INIT {0} 75af69d88dSmrg#endif 76af69d88dSmrg#define TSS_DTOR_ITERATIONS 1 77af69d88dSmrg 78af69d88dSmrg// FIXME: temporary non-standard hack to ease transition 79af69d88dSmrg#define _MTX_INITIALIZER_NP {(PCRITICAL_SECTION_DEBUG)-1, -1, 0, 0, 0, 0} 80af69d88dSmrg 81af69d88dSmrg/*---------------------------- types ----------------------------*/ 827ec681f3Smrgtypedef CONDITION_VARIABLE cnd_t; 83af69d88dSmrg 84af69d88dSmrgtypedef HANDLE thrd_t; 85af69d88dSmrg 86af69d88dSmrgtypedef DWORD tss_t; 87af69d88dSmrg 88af69d88dSmrgtypedef CRITICAL_SECTION mtx_t; 89af69d88dSmrg 90af69d88dSmrg#ifdef EMULATED_THREADS_USE_NATIVE_CALL_ONCE 91af69d88dSmrgtypedef INIT_ONCE once_flag; 92af69d88dSmrg#else 93af69d88dSmrgtypedef struct once_flag_t { 94af69d88dSmrg volatile LONG status; 95af69d88dSmrg} once_flag; 96af69d88dSmrg#endif 97af69d88dSmrg 98af69d88dSmrg 99af69d88dSmrgstatic inline void * tss_get(tss_t key); 100af69d88dSmrgstatic inline void thrd_yield(void); 101af69d88dSmrgstatic inline int mtx_trylock(mtx_t *mtx); 102af69d88dSmrgstatic inline int mtx_lock(mtx_t *mtx); 103af69d88dSmrgstatic inline int mtx_unlock(mtx_t *mtx); 104af69d88dSmrg 105af69d88dSmrg/* 106af69d88dSmrgImplementation limits: 107af69d88dSmrg - Conditionally emulation for "Initialization functions" 108af69d88dSmrg (see EMULATED_THREADS_USE_NATIVE_CALL_ONCE macro) 109af69d88dSmrg - Emulated `mtx_timelock()' with mtx_trylock() + *busy loop* 110af69d88dSmrg*/ 111af69d88dSmrgstatic void impl_tss_dtor_invoke(void); // forward decl. 112af69d88dSmrg 113af69d88dSmrgstruct impl_thrd_param { 114af69d88dSmrg thrd_start_t func; 115af69d88dSmrg void *arg; 116af69d88dSmrg}; 117af69d88dSmrg 118af69d88dSmrgstatic unsigned __stdcall impl_thrd_routine(void *p) 119af69d88dSmrg{ 120af69d88dSmrg struct impl_thrd_param pack; 121af69d88dSmrg int code; 122af69d88dSmrg memcpy(&pack, p, sizeof(struct impl_thrd_param)); 123af69d88dSmrg free(p); 124af69d88dSmrg code = pack.func(pack.arg); 125af69d88dSmrg impl_tss_dtor_invoke(); 126af69d88dSmrg return (unsigned)code; 127af69d88dSmrg} 128af69d88dSmrg 1297ec681f3Smrgstatic time_t impl_timespec2msec(const struct timespec *ts) 1307ec681f3Smrg{ 1317ec681f3Smrg return (ts->tv_sec * 1000U) + (ts->tv_nsec / 1000000L); 1327ec681f3Smrg} 1337ec681f3Smrg 1347ec681f3Smrg#ifdef HAVE_TIMESPEC_GET 1357ec681f3Smrgstatic DWORD impl_abs2relmsec(const struct timespec *abs_time) 136af69d88dSmrg{ 1377ec681f3Smrg const time_t abs_ms = impl_timespec2msec(abs_time); 1387ec681f3Smrg struct timespec now; 1397ec681f3Smrg timespec_get(&now, TIME_UTC); 1407ec681f3Smrg const time_t now_ms = impl_timespec2msec(&now); 1417ec681f3Smrg const DWORD rel_ms = (abs_ms > now_ms) ? (DWORD)(abs_ms - now_ms) : 0; 1427ec681f3Smrg return rel_ms; 143af69d88dSmrg} 1447ec681f3Smrg#endif 145af69d88dSmrg 146af69d88dSmrg#ifdef EMULATED_THREADS_USE_NATIVE_CALL_ONCE 147af69d88dSmrgstruct impl_call_once_param { void (*func)(void); }; 148af69d88dSmrgstatic BOOL CALLBACK impl_call_once_callback(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context) 149af69d88dSmrg{ 150af69d88dSmrg struct impl_call_once_param *param = (struct impl_call_once_param*)Parameter; 151af69d88dSmrg (param->func)(); 152af69d88dSmrg ((void)InitOnce); ((void)Context); // suppress warning 153af69d88dSmrg return TRUE; 154af69d88dSmrg} 155af69d88dSmrg#endif // ifdef EMULATED_THREADS_USE_NATIVE_CALL_ONCE 156af69d88dSmrg 157af69d88dSmrgstatic struct impl_tss_dtor_entry { 158af69d88dSmrg tss_t key; 159af69d88dSmrg tss_dtor_t dtor; 160af69d88dSmrg} impl_tss_dtor_tbl[EMULATED_THREADS_TSS_DTOR_SLOTNUM]; 161af69d88dSmrg 162af69d88dSmrgstatic int impl_tss_dtor_register(tss_t key, tss_dtor_t dtor) 163af69d88dSmrg{ 164af69d88dSmrg int i; 165af69d88dSmrg for (i = 0; i < EMULATED_THREADS_TSS_DTOR_SLOTNUM; i++) { 166af69d88dSmrg if (!impl_tss_dtor_tbl[i].dtor) 167af69d88dSmrg break; 168af69d88dSmrg } 169af69d88dSmrg if (i == EMULATED_THREADS_TSS_DTOR_SLOTNUM) 170af69d88dSmrg return 1; 171af69d88dSmrg impl_tss_dtor_tbl[i].key = key; 172af69d88dSmrg impl_tss_dtor_tbl[i].dtor = dtor; 173af69d88dSmrg return 0; 174af69d88dSmrg} 175af69d88dSmrg 176af69d88dSmrgstatic void impl_tss_dtor_invoke() 177af69d88dSmrg{ 178af69d88dSmrg int i; 179af69d88dSmrg for (i = 0; i < EMULATED_THREADS_TSS_DTOR_SLOTNUM; i++) { 180af69d88dSmrg if (impl_tss_dtor_tbl[i].dtor) { 181af69d88dSmrg void* val = tss_get(impl_tss_dtor_tbl[i].key); 182af69d88dSmrg if (val) 183af69d88dSmrg (impl_tss_dtor_tbl[i].dtor)(val); 184af69d88dSmrg } 185af69d88dSmrg } 186af69d88dSmrg} 187af69d88dSmrg 188af69d88dSmrg 189af69d88dSmrg/*--------------- 7.25.2 Initialization functions ---------------*/ 190af69d88dSmrg// 7.25.2.1 191af69d88dSmrgstatic inline void 192af69d88dSmrgcall_once(once_flag *flag, void (*func)(void)) 193af69d88dSmrg{ 194af69d88dSmrg assert(flag && func); 195af69d88dSmrg#ifdef EMULATED_THREADS_USE_NATIVE_CALL_ONCE 196af69d88dSmrg { 197af69d88dSmrg struct impl_call_once_param param; 198af69d88dSmrg param.func = func; 199af69d88dSmrg InitOnceExecuteOnce(flag, impl_call_once_callback, (PVOID)¶m, NULL); 200af69d88dSmrg } 201af69d88dSmrg#else 202af69d88dSmrg if (InterlockedCompareExchange(&flag->status, 1, 0) == 0) { 203af69d88dSmrg (func)(); 204af69d88dSmrg InterlockedExchange(&flag->status, 2); 205af69d88dSmrg } else { 206af69d88dSmrg while (flag->status == 1) { 207af69d88dSmrg // busy loop! 208af69d88dSmrg thrd_yield(); 209af69d88dSmrg } 210af69d88dSmrg } 211af69d88dSmrg#endif 212af69d88dSmrg} 213af69d88dSmrg 214af69d88dSmrg 215af69d88dSmrg/*------------- 7.25.3 Condition variable functions -------------*/ 216af69d88dSmrg// 7.25.3.1 217af69d88dSmrgstatic inline int 218af69d88dSmrgcnd_broadcast(cnd_t *cond) 219af69d88dSmrg{ 2207ec681f3Smrg assert(cond != NULL); 2217ec681f3Smrg WakeAllConditionVariable(cond); 222af69d88dSmrg return thrd_success; 223af69d88dSmrg} 224af69d88dSmrg 225af69d88dSmrg// 7.25.3.2 226af69d88dSmrgstatic inline void 227af69d88dSmrgcnd_destroy(cnd_t *cond) 228af69d88dSmrg{ 2297ec681f3Smrg assert(cond != NULL); 230af69d88dSmrg // do nothing 231af69d88dSmrg} 232af69d88dSmrg 233af69d88dSmrg// 7.25.3.3 234af69d88dSmrgstatic inline int 235af69d88dSmrgcnd_init(cnd_t *cond) 236af69d88dSmrg{ 2377ec681f3Smrg assert(cond != NULL); 2387ec681f3Smrg InitializeConditionVariable(cond); 239af69d88dSmrg return thrd_success; 240af69d88dSmrg} 241af69d88dSmrg 242af69d88dSmrg// 7.25.3.4 243af69d88dSmrgstatic inline int 244af69d88dSmrgcnd_signal(cnd_t *cond) 245af69d88dSmrg{ 2467ec681f3Smrg assert(cond != NULL); 2477ec681f3Smrg WakeConditionVariable(cond); 248af69d88dSmrg return thrd_success; 249af69d88dSmrg} 250af69d88dSmrg 251af69d88dSmrg// 7.25.3.5 252af69d88dSmrgstatic inline int 25301e04c3fSmrgcnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *abs_time) 254af69d88dSmrg{ 2557ec681f3Smrg assert(cond != NULL); 2567ec681f3Smrg assert(mtx != NULL); 2577ec681f3Smrg assert(abs_time != NULL); 2587ec681f3Smrg#ifdef HAVE_TIMESPEC_GET 2597ec681f3Smrg const DWORD timeout = impl_abs2relmsec(abs_time); 2607ec681f3Smrg if (SleepConditionVariableCS(cond, mtx, timeout)) 261af69d88dSmrg return thrd_success; 262af69d88dSmrg return (GetLastError() == ERROR_TIMEOUT) ? thrd_busy : thrd_error; 263af69d88dSmrg#else 2647ec681f3Smrg return thrd_error; 265af69d88dSmrg#endif 266af69d88dSmrg} 267af69d88dSmrg 268af69d88dSmrg// 7.25.3.6 269af69d88dSmrgstatic inline int 270af69d88dSmrgcnd_wait(cnd_t *cond, mtx_t *mtx) 271af69d88dSmrg{ 2727ec681f3Smrg assert(cond != NULL); 2737ec681f3Smrg assert(mtx != NULL); 2747ec681f3Smrg SleepConditionVariableCS(cond, mtx, INFINITE); 275af69d88dSmrg return thrd_success; 276af69d88dSmrg} 277af69d88dSmrg 278af69d88dSmrg 279af69d88dSmrg/*-------------------- 7.25.4 Mutex functions --------------------*/ 280af69d88dSmrg// 7.25.4.1 281af69d88dSmrgstatic inline void 282af69d88dSmrgmtx_destroy(mtx_t *mtx) 283af69d88dSmrg{ 284af69d88dSmrg assert(mtx); 285af69d88dSmrg DeleteCriticalSection(mtx); 286af69d88dSmrg} 287af69d88dSmrg 288af69d88dSmrg// 7.25.4.2 289af69d88dSmrgstatic inline int 290af69d88dSmrgmtx_init(mtx_t *mtx, int type) 291af69d88dSmrg{ 2927ec681f3Smrg assert(mtx != NULL); 293af69d88dSmrg if (type != mtx_plain && type != mtx_timed && type != mtx_try 294af69d88dSmrg && type != (mtx_plain|mtx_recursive) 295af69d88dSmrg && type != (mtx_timed|mtx_recursive) 296af69d88dSmrg && type != (mtx_try|mtx_recursive)) 297af69d88dSmrg return thrd_error; 298af69d88dSmrg InitializeCriticalSection(mtx); 299af69d88dSmrg return thrd_success; 300af69d88dSmrg} 301af69d88dSmrg 302af69d88dSmrg// 7.25.4.3 303af69d88dSmrgstatic inline int 304af69d88dSmrgmtx_lock(mtx_t *mtx) 305af69d88dSmrg{ 3067ec681f3Smrg assert(mtx != NULL); 307af69d88dSmrg EnterCriticalSection(mtx); 308af69d88dSmrg return thrd_success; 309af69d88dSmrg} 310af69d88dSmrg 311af69d88dSmrg// 7.25.4.4 312af69d88dSmrgstatic inline int 31301e04c3fSmrgmtx_timedlock(mtx_t *mtx, const struct timespec *ts) 314af69d88dSmrg{ 3157ec681f3Smrg assert(mtx != NULL); 3167ec681f3Smrg assert(ts != NULL); 3177ec681f3Smrg#ifdef HAVE_TIMESPEC_GET 318af69d88dSmrg while (mtx_trylock(mtx) != thrd_success) { 3197ec681f3Smrg if (impl_abs2relmsec(ts) == 0) 320af69d88dSmrg return thrd_busy; 321af69d88dSmrg // busy loop! 322af69d88dSmrg thrd_yield(); 323af69d88dSmrg } 324af69d88dSmrg return thrd_success; 3257ec681f3Smrg#else 3267ec681f3Smrg return thrd_error; 3277ec681f3Smrg#endif 328af69d88dSmrg} 329af69d88dSmrg 330af69d88dSmrg// 7.25.4.5 331af69d88dSmrgstatic inline int 332af69d88dSmrgmtx_trylock(mtx_t *mtx) 333af69d88dSmrg{ 3347ec681f3Smrg assert(mtx != NULL); 335af69d88dSmrg return TryEnterCriticalSection(mtx) ? thrd_success : thrd_busy; 336af69d88dSmrg} 337af69d88dSmrg 338af69d88dSmrg// 7.25.4.6 339af69d88dSmrgstatic inline int 340af69d88dSmrgmtx_unlock(mtx_t *mtx) 341af69d88dSmrg{ 3427ec681f3Smrg assert(mtx != NULL); 343af69d88dSmrg LeaveCriticalSection(mtx); 344af69d88dSmrg return thrd_success; 345af69d88dSmrg} 346af69d88dSmrg 347af69d88dSmrg 348af69d88dSmrg/*------------------- 7.25.5 Thread functions -------------------*/ 349af69d88dSmrg// 7.25.5.1 350af69d88dSmrgstatic inline int 351af69d88dSmrgthrd_create(thrd_t *thr, thrd_start_t func, void *arg) 352af69d88dSmrg{ 353af69d88dSmrg struct impl_thrd_param *pack; 354af69d88dSmrg uintptr_t handle; 3557ec681f3Smrg assert(thr != NULL); 356af69d88dSmrg pack = (struct impl_thrd_param *)malloc(sizeof(struct impl_thrd_param)); 357af69d88dSmrg if (!pack) return thrd_nomem; 358af69d88dSmrg pack->func = func; 359af69d88dSmrg pack->arg = arg; 360af69d88dSmrg handle = _beginthreadex(NULL, 0, impl_thrd_routine, pack, 0, NULL); 361af69d88dSmrg if (handle == 0) { 362af69d88dSmrg if (errno == EAGAIN || errno == EACCES) 363af69d88dSmrg return thrd_nomem; 364af69d88dSmrg return thrd_error; 365af69d88dSmrg } 366af69d88dSmrg *thr = (thrd_t)handle; 367af69d88dSmrg return thrd_success; 368af69d88dSmrg} 369af69d88dSmrg 370af69d88dSmrg#if 0 371af69d88dSmrg// 7.25.5.2 372af69d88dSmrgstatic inline thrd_t 373af69d88dSmrgthrd_current(void) 374af69d88dSmrg{ 375af69d88dSmrg HANDLE hCurrentThread; 376af69d88dSmrg BOOL bRet; 377af69d88dSmrg 37801e04c3fSmrg /* GetCurrentThread() returns a pseudo-handle, which we need 37901e04c3fSmrg * to pass to DuplicateHandle(). Only the resulting handle can be used 38001e04c3fSmrg * from other threads. 38101e04c3fSmrg * 38201e04c3fSmrg * Note that neither handle can be compared to the one by thread_create. 38301e04c3fSmrg * Only the thread IDs - as returned by GetThreadId() and GetCurrentThreadId() 38401e04c3fSmrg * can be compared directly. 385af69d88dSmrg * 386af69d88dSmrg * Other potential solutions would be: 387af69d88dSmrg * - define thrd_t as a thread Ids, but this would mean we'd need to OpenThread for many operations 388af69d88dSmrg * - use malloc'ed memory for thrd_t. This would imply using TLS for current thread. 389af69d88dSmrg * 390af69d88dSmrg * Neither is particularly nice. 391af69d88dSmrg * 392af69d88dSmrg * Life would be much easier if C11 threads had different abstractions for 393af69d88dSmrg * threads and thread IDs, just like C++11 threads does... 394af69d88dSmrg */ 395af69d88dSmrg 396af69d88dSmrg bRet = DuplicateHandle(GetCurrentProcess(), // source process (pseudo) handle 397af69d88dSmrg GetCurrentThread(), // source (pseudo) handle 398af69d88dSmrg GetCurrentProcess(), // target process 399af69d88dSmrg &hCurrentThread, // target handle 400af69d88dSmrg 0, 401af69d88dSmrg FALSE, 402af69d88dSmrg DUPLICATE_SAME_ACCESS); 403af69d88dSmrg assert(bRet); 404af69d88dSmrg if (!bRet) { 405af69d88dSmrg hCurrentThread = GetCurrentThread(); 406af69d88dSmrg } 407af69d88dSmrg return hCurrentThread; 408af69d88dSmrg} 409af69d88dSmrg#endif 410af69d88dSmrg 411af69d88dSmrg// 7.25.5.3 412af69d88dSmrgstatic inline int 413af69d88dSmrgthrd_detach(thrd_t thr) 414af69d88dSmrg{ 415af69d88dSmrg CloseHandle(thr); 416af69d88dSmrg return thrd_success; 417af69d88dSmrg} 418af69d88dSmrg 419af69d88dSmrg// 7.25.5.4 420af69d88dSmrgstatic inline int 421af69d88dSmrgthrd_equal(thrd_t thr0, thrd_t thr1) 422af69d88dSmrg{ 423af69d88dSmrg return GetThreadId(thr0) == GetThreadId(thr1); 424af69d88dSmrg} 425af69d88dSmrg 426af69d88dSmrg// 7.25.5.5 427af69d88dSmrgstatic inline void 428af69d88dSmrgthrd_exit(int res) 429af69d88dSmrg{ 430af69d88dSmrg impl_tss_dtor_invoke(); 431af69d88dSmrg _endthreadex((unsigned)res); 432af69d88dSmrg} 433af69d88dSmrg 434af69d88dSmrg// 7.25.5.6 435af69d88dSmrgstatic inline int 436af69d88dSmrgthrd_join(thrd_t thr, int *res) 437af69d88dSmrg{ 438af69d88dSmrg DWORD w, code; 439af69d88dSmrg w = WaitForSingleObject(thr, INFINITE); 440af69d88dSmrg if (w != WAIT_OBJECT_0) 441af69d88dSmrg return thrd_error; 442af69d88dSmrg if (res) { 443af69d88dSmrg if (!GetExitCodeThread(thr, &code)) { 444af69d88dSmrg CloseHandle(thr); 445af69d88dSmrg return thrd_error; 446af69d88dSmrg } 447af69d88dSmrg *res = (int)code; 448af69d88dSmrg } 449af69d88dSmrg CloseHandle(thr); 450af69d88dSmrg return thrd_success; 451af69d88dSmrg} 452af69d88dSmrg 453af69d88dSmrg// 7.25.5.7 454af69d88dSmrgstatic inline void 45501e04c3fSmrgthrd_sleep(const struct timespec *time_point, struct timespec *remaining) 456af69d88dSmrg{ 45701e04c3fSmrg assert(time_point); 45801e04c3fSmrg assert(!remaining); /* not implemented */ 4597ec681f3Smrg Sleep((DWORD)impl_timespec2msec(time_point)); 460af69d88dSmrg} 461af69d88dSmrg 462af69d88dSmrg// 7.25.5.8 463af69d88dSmrgstatic inline void 464af69d88dSmrgthrd_yield(void) 465af69d88dSmrg{ 466af69d88dSmrg SwitchToThread(); 467af69d88dSmrg} 468af69d88dSmrg 469af69d88dSmrg 470af69d88dSmrg/*----------- 7.25.6 Thread-specific storage functions -----------*/ 471af69d88dSmrg// 7.25.6.1 472af69d88dSmrgstatic inline int 473af69d88dSmrgtss_create(tss_t *key, tss_dtor_t dtor) 474af69d88dSmrg{ 4757ec681f3Smrg assert(key != NULL); 476af69d88dSmrg *key = TlsAlloc(); 477af69d88dSmrg if (dtor) { 478af69d88dSmrg if (impl_tss_dtor_register(*key, dtor)) { 479af69d88dSmrg TlsFree(*key); 480af69d88dSmrg return thrd_error; 481af69d88dSmrg } 482af69d88dSmrg } 483af69d88dSmrg return (*key != 0xFFFFFFFF) ? thrd_success : thrd_error; 484af69d88dSmrg} 485af69d88dSmrg 486af69d88dSmrg// 7.25.6.2 487af69d88dSmrgstatic inline void 488af69d88dSmrgtss_delete(tss_t key) 489af69d88dSmrg{ 490af69d88dSmrg TlsFree(key); 491af69d88dSmrg} 492af69d88dSmrg 493af69d88dSmrg// 7.25.6.3 494af69d88dSmrgstatic inline void * 495af69d88dSmrgtss_get(tss_t key) 496af69d88dSmrg{ 497af69d88dSmrg return TlsGetValue(key); 498af69d88dSmrg} 499af69d88dSmrg 500af69d88dSmrg// 7.25.6.4 501af69d88dSmrgstatic inline int 502af69d88dSmrgtss_set(tss_t key, void *val) 503af69d88dSmrg{ 504af69d88dSmrg return TlsSetValue(key, val) ? thrd_success : thrd_error; 505af69d88dSmrg} 506af69d88dSmrg 507af69d88dSmrg 508af69d88dSmrg/*-------------------- 7.25.7 Time functions --------------------*/ 509af69d88dSmrg// 7.25.6.1 51001e04c3fSmrg#ifndef HAVE_TIMESPEC_GET 511af69d88dSmrgstatic inline int 51201e04c3fSmrgtimespec_get(struct timespec *ts, int base) 513af69d88dSmrg{ 5147ec681f3Smrg assert(ts != NULL); 515af69d88dSmrg if (base == TIME_UTC) { 51601e04c3fSmrg ts->tv_sec = time(NULL); 51701e04c3fSmrg ts->tv_nsec = 0; 518af69d88dSmrg return base; 519af69d88dSmrg } 520af69d88dSmrg return 0; 521af69d88dSmrg} 52201e04c3fSmrg#endif 523