Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
wpthread.cpp
Go to the documentation of this file.
1 /* Copyright (c) 2010 Wildfire Games
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining
4  * a copy of this software and associated documentation files (the
5  * "Software"), to deal in the Software without restriction, including
6  * without limitation the rights to use, copy, modify, merge, publish,
7  * distribute, sublicense, and/or sell copies of the Software, and to
8  * permit persons to whom the Software is furnished to do so, subject to
9  * the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22 
23 /*
24  * emulate pthreads on Windows.
25  */
26 
27 #include "precompiled.h"
29 
30 #include <new>
31 #include <process.h>
32 
33 #include "lib/sysdep/cpu.h" // cpu_CAS
34 #include "lib/posix/posix_filesystem.h" // O_CREAT
36 #include "lib/sysdep/os/win/wposix/wtime.h" // timespec
37 #include "lib/sysdep/os/win/wseh.h" // wseh_ExceptionFilter
39 
41 
42 
44 {
45  return (HANDLE)((char*)0 + p);
46 }
47 
49 {
50  return (pthread_t)(uintptr_t)h;
51 }
52 
53 
54 //-----------------------------------------------------------------------------
55 // misc
56 //-----------------------------------------------------------------------------
57 
58 // non-pseudo handle so that pthread_self value is unique for each thread
59 static __declspec(thread) HANDLE hCurrentThread;
60 
61 static void NotifyCurrentThread()
62 {
63  // (we leave it to the OS to clean these up at process exit - threads are not created often)
64  WARN_IF_FALSE(DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &hCurrentThread, 0, FALSE, DUPLICATE_SAME_ACCESS));
65 }
66 
67 
68 
70 {
71  return t1 == t2;
72 }
73 
75 {
76  return pthread_from_HANDLE(hCurrentThread);
77 }
78 
79 
80 int pthread_once(pthread_once_t* once, void (*init_routine)())
81 {
82  if(cpu_CAS((volatile intptr_t*)once, 0, 1))
83  init_routine();
84  return 0;
85 }
86 
87 
88 int pthread_getschedparam(pthread_t thread, int* policy, struct sched_param* param)
89 {
90  if(policy)
91  {
92  DWORD pc = GetPriorityClass(GetCurrentProcess());
93  *policy = (pc >= HIGH_PRIORITY_CLASS)? SCHED_FIFO : SCHED_RR;
94  }
95  if(param)
96  {
97  const HANDLE hThread = HANDLE_from_pthread(thread);
98  param->sched_priority = GetThreadPriority(hThread);
99  }
100 
101  return 0;
102 }
103 
104 int pthread_setschedparam(pthread_t thread, int policy, const struct sched_param* param)
105 {
106  const int pri = param->sched_priority;
107 
108  // additional boost for policy == SCHED_FIFO
109  DWORD pri_class = NORMAL_PRIORITY_CLASS;
110  if(policy == SCHED_FIFO)
111  {
112  pri_class = HIGH_PRIORITY_CLASS;
113  if(pri == 2)
114  pri_class = REALTIME_PRIORITY_CLASS;
115  }
116  SetPriorityClass(GetCurrentProcess(), pri_class);
117 
118  // choose fixed Windows values from pri
119  const HANDLE hThread = HANDLE_from_pthread(thread);
120  SetThreadPriority(hThread, pri);
121  return 0;
122 }
123 
124 
125 //-----------------------------------------------------------------------------
126 // thread-local storage
127 //-----------------------------------------------------------------------------
128 
129 // minimum amount of TLS slots every Windows version provides;
130 // used to validate indices.
131 static const size_t TLS_LIMIT = 64;
132 
133 // rationale: don't use an array of dtors for every possible TLS slot.
134 // other DLLs may allocate any number of them in their DllMain, so the
135 // array would have to be quite large. instead, store both key and dtor -
136 // we are thus limited only by pthread_key_create calls (which we control).
137 static const size_t MAX_DTORS = 4;
138 static struct
139 {
141  void (*dtor)(void*);
142 }
144 
145 
147 {
148  DWORD idx = TlsAlloc();
149  if(idx == TLS_OUT_OF_INDEXES)
150  return -ENOMEM;
151 
152  ENSURE(idx < TLS_LIMIT);
153  *key = (pthread_key_t)idx;
154 
155  // acquire a free dtor slot
156  size_t i;
157  for(i = 0; i < MAX_DTORS; i++)
158  {
159  if(cpu_CAS((volatile intptr_t*)&dtors[i].dtor, (intptr_t)0, (intptr_t)dtor))
160  goto have_slot;
161  }
162 
163  // not enough slots; we have a valid key, but its dtor won't be called.
165  return -1;
166 
167 have_slot:
168  dtors[i].key = *key;
169  return 0;
170 }
171 
172 
174 {
175  DWORD idx = (DWORD)key;
176  ENSURE(idx < TLS_LIMIT);
177 
178  BOOL ret = TlsFree(idx);
179  ENSURE(ret != 0);
180  return 0;
181 }
182 
183 
185 {
186  DWORD idx = (DWORD)key;
187  ENSURE(idx < TLS_LIMIT);
188 
189  // TlsGetValue sets last error to 0 on success (boo).
190  // we don't want this to hide previous errors, so it's restored below.
191  DWORD last_err = GetLastError();
192 
193  void* data = TlsGetValue(idx);
194 
195  // no error
196  if(GetLastError() == 0)
197  {
198  // we care about performance here. SetLastError is low overhead,
199  // but last error = 0 is expected.
200  if(last_err != 0)
201  SetLastError(last_err);
202  }
203  else
205 
206  return data;
207 }
208 
209 
210 int pthread_setspecific(pthread_key_t key, const void* value)
211 {
212  DWORD idx = (DWORD)key;
213  ENSURE(idx < TLS_LIMIT);
214 
215  BOOL ret = TlsSetValue(idx, (void*)value);
216  ENSURE(ret != 0);
217  return 0;
218 }
219 
220 
221 static void call_tls_dtors()
222 {
223 again:
224  bool had_valid_tls = false;
225 
226  // for each registered dtor: (call order unspecified by SUSv3)
227  for(size_t i = 0; i < MAX_DTORS; i++)
228  {
229  // is slot #i in use?
230  void (*dtor)(void*) = dtors[i].dtor;
231  if(!dtor)
232  continue;
233 
234  // clear slot and call dtor with its previous value.
235  const pthread_key_t key = dtors[i].key;
236  void* tls = pthread_getspecific(key);
237  if(tls)
238  {
240 
241  dtor(tls);
242  had_valid_tls = true;
243  }
244  }
245 
246  // rationale: SUSv3 says we're allowed to loop infinitely. we do so to
247  // expose any dtor bugs - this shouldn't normally happen.
248  if(had_valid_tls)
249  goto again;
250 }
251 
252 
253 //-----------------------------------------------------------------------------
254 // mutex
255 //-----------------------------------------------------------------------------
256 
257 // rationale: CRITICAL_SECTIONS have less overhead than Win32 Mutex.
258 // disadvantage is that pthread_mutex_timedlock isn't supported, but
259 // the user can switch to semaphores if this facility is important.
260 
261 // DeleteCriticalSection currently doesn't complain if we double-free
262 // (e.g. user calls destroy() and static initializer atexit runs),
263 // and dox are ambiguous.
264 
265 // note: pthread_mutex_t must not be an opaque struct, because the
266 // initializer returns pthread_mutex_t directly and CRITICAL_SECTIONS
267 // shouldn't be copied.
268 //
269 // note: we use wutil_Allocate instead of new because the (no longer extant)
270 // memory manager used a pthread_mutex.
271 
272 
274 {
275  return 0;
276 }
277 
279 {
280  return 0;
281 }
282 
284 {
285  *type = PTHREAD_MUTEX_RECURSIVE;
286  return 0;
287 }
288 
290 {
291  return (type == PTHREAD_MUTEX_RECURSIVE)? 0 : -ENOSYS;
292 }
293 
294 
296 {
297  if(!m)
298  {
300  return 0;
301  }
302  return (CRITICAL_SECTION*)*m;
303 }
304 
306 {
307  CRITICAL_SECTION* cs = (CRITICAL_SECTION*)wutil_Allocate(sizeof(CRITICAL_SECTION));
308  InitializeCriticalSection(cs);
309  return (pthread_mutex_t)cs;
310 }
311 
313 {
314  CRITICAL_SECTION* cs = CRITICAL_SECTION_from_pthread_mutex_t(m);
315  if(!cs)
316  return -1;
317  DeleteCriticalSection(cs);
318  wutil_Free(cs);
319  *m = 0; // cause double-frees to be noticed
320  return 0;
321 }
322 
324 {
326  return 0;
327 }
328 
330 {
331  CRITICAL_SECTION* cs = CRITICAL_SECTION_from_pthread_mutex_t(m);
332  if(!cs)
333  return -1;
334  EnterCriticalSection(cs);
335  return 0;
336 }
337 
339 {
340  CRITICAL_SECTION* cs = CRITICAL_SECTION_from_pthread_mutex_t(m);
341  if(!cs)
342  return -1;
343  const BOOL successfullyEnteredOrAlreadyOwns = TryEnterCriticalSection(cs);
344  return successfullyEnteredOrAlreadyOwns? 0 : -1;
345 }
346 
348 {
349  CRITICAL_SECTION* cs = CRITICAL_SECTION_from_pthread_mutex_t(m);
350  if(!cs)
351  return -1;
352  LeaveCriticalSection(cs);
353  return 0;
354 }
355 
356 // not implemented - pthread_mutex is based on CRITICAL_SECTION,
357 // which doesn't support timeouts. use sem_timedwait instead.
358 int pthread_mutex_timedlock(pthread_mutex_t* UNUSED(m), const struct timespec* UNUSED(abs_timeout))
359 {
360  return -ENOSYS;
361 }
362 
363 
364 //-----------------------------------------------------------------------------
365 // semaphore
366 //-----------------------------------------------------------------------------
367 
369 {
370  return (HANDLE)*sem;
371 }
372 
373 sem_t* sem_open(const char* name, int oflag, ...)
374 {
376 
377  const bool create = (oflag & O_CREAT) != 0;
378  const bool exclusive = (oflag & O_EXCL) != 0;
379 
380  // SUSv3 parameter requirements:
381  ENSURE(name[0] == '/');
382  ENSURE((oflag & ~(O_CREAT|O_EXCL)) == 0); // no other bits
383  ENSURE(!exclusive || create); // excl implies creat
384 
385  // if creating, get additional parameters
386  unsigned initialValue = 0;
387  if(create)
388  {
389  va_list args;
390  va_start(args, oflag);
391  const mode_t mode = va_arg(args, mode_t);
392  initialValue = va_arg(args, unsigned);
393  va_end(args);
394  ENSURE(mode == 0700 && "this implementation ignores mode_t");
395  }
396 
397  // create or open
398  SetLastError(0);
399  const LONG maxValue = 0x7fffffff;
400  const HANDLE hSemaphore = CreateSemaphore(0, (LONG)initialValue, maxValue, 0);
401  if(hSemaphore == 0)
402  return SEM_FAILED;
403  const bool existed = (GetLastError() == ERROR_ALREADY_EXISTS);
404 
405  // caller insisted on creating anew, but it already existed
406  if(exclusive && existed)
407  {
408  CloseHandle(hSemaphore);
409  errno = EEXIST;
410  return SEM_FAILED;
411  }
412 
413  // caller wanted to open semaphore, but it didn't exist
414  if(!create && !existed)
415  {
416  CloseHandle(hSemaphore);
417  errno = ENOENT;
418  return SEM_FAILED;
419  }
420 
421  // we have to return a pointer to sem_t, and the sem_init interface
422  // requires sem_t to be usable as the handle, so we'll have to
423  // allocate memory here (ugh).
424  sem_t* sem = new sem_t;
425  *sem = (sem_t)hSemaphore;
426  return sem;
427 }
428 
429 int sem_close(sem_t* sem)
430 {
431  // jw: not sure if this is correct according to SUSv3, but it's
432  // certainly enough for MessagePasserImpl's needs.
433  sem_destroy(sem);
434  delete sem;
435  return 0; // success
436 }
437 
438 int sem_unlink(const char* UNUSED(name))
439 {
440  // see sem_close
441  return 0; // success
442 }
443 
444 int sem_init(sem_t* sem, int pshared, unsigned value)
445 {
446  SECURITY_ATTRIBUTES sec = { sizeof(SECURITY_ATTRIBUTES) };
447  sec.bInheritHandle = (BOOL)pshared;
448  HANDLE h = CreateSemaphore(&sec, (LONG)value, 0x7fffffff, 0);
449  WARN_IF_FALSE(h);
450  *sem = (sem_t)h;
451  return 0;
452 }
453 
455 {
456  HANDLE h = HANDLE_from_sem_t(sem);
457  WARN_IF_FALSE(CloseHandle(h));
458  return 0;
459 }
460 
461 int sem_post(sem_t* sem)
462 {
463  HANDLE h = HANDLE_from_sem_t(sem);
464  WARN_IF_FALSE(ReleaseSemaphore(h, 1, 0));
465  return 0;
466 }
467 
468 int sem_wait(sem_t* sem)
469 {
470  HANDLE h = HANDLE_from_sem_t(sem);
471  DWORD ret = WaitForSingleObject(h, INFINITE);
472  ENSURE(ret == WAIT_OBJECT_0);
473  return 0;
474 }
475 
476 
477 // helper function for sem_timedwait - multiple return is convenient.
478 // converts an absolute timeout deadline into a relative length for use with
479 // WaitForSingleObject with the following peculiarity: if the semaphore
480 // could be locked immediately, abs_timeout must be ignored (see SUS).
481 // to that end, we return a timeout of 0 and pass back <valid> = false if
482 // abs_timeout is invalid.
483 static DWORD calc_timeout_length_ms(const struct timespec* abs_timeout,
484  bool& timeout_is_valid)
485 {
486  timeout_is_valid = false;
487 
488  if(!abs_timeout)
489  return 0;
490 
491  // SUS requires we fail if not normalized
492  if(abs_timeout->tv_nsec >= 1000000000)
493  return 0;
494 
495  struct timespec cur_time;
496  if(clock_gettime(CLOCK_REALTIME, &cur_time) != 0)
497  return 0;
498 
499  timeout_is_valid = true;
500 
501  // convert absolute deadline to relative length, rounding up to [ms].
502  // note: use i64 to avoid overflow in multiply.
503  const i64 ds = abs_timeout->tv_sec - cur_time.tv_sec;
504  const long dn = abs_timeout->tv_nsec - cur_time.tv_nsec;
505  i64 length_ms = ds*1000 + (dn+500000)/1000000;
506  // .. deadline already reached; we'll still attempt to lock once
507  if(length_ms < 0)
508  return 0;
509  // .. length > 49 days => result won't fit in 32 bits. most likely bogus.
510  // note: we're careful to avoid returning exactly -1 since
511  // that's the Win32 INFINITE value.
512  if(length_ms >= 0xFFFFFFFF)
513  {
515  length_ms = 0xfffffffe;
516  }
517  return (DWORD)(length_ms & 0xFFFFFFFF);
518 }
519 
520 int sem_timedwait(sem_t* sem, const struct timespec* abs_timeout)
521 {
522  bool timeout_is_valid;
523  DWORD timeout_ms = calc_timeout_length_ms(abs_timeout, timeout_is_valid);
524 
525  HANDLE h = HANDLE_from_sem_t(sem);
526  DWORD ret = WaitForSingleObject(h, timeout_ms);
527  // successfully decremented semaphore; bail.
528  if(ret == WAIT_OBJECT_0)
529  return 0;
530 
531  // we're going to return -1. decide what happened:
532  // .. abs_timeout was invalid (must not check this before trying to lock)
533  if(!timeout_is_valid)
534  errno = EINVAL;
535  // .. timeout reached (not a failure)
536  else if(ret == WAIT_TIMEOUT)
537  errno = ETIMEDOUT;
538 
539  return -1;
540 }
541 
542 
543 // wait until semaphore is locked or a message arrives. non-portable.
544 //
545 // background: on Win32, UI threads must periodically pump messages, or
546 // else deadlock may result (see WaitForSingleObject docs). that entails
547 // avoiding any blocking functions. when event waiting is needed,
548 // one cheap workaround would be to time out periodically and pump messages.
549 // that would work, but either wastes CPU time waiting, or introduces
550 // message latency. to avoid this, we provide an API similar to sem_wait and
551 // sem_timedwait that gives MsgWaitForMultipleObjects functionality.
552 //
553 // return value: 0 if the semaphore has been locked (SUS terminology),
554 // -1 otherwise. errno differentiates what happened: ETIMEDOUT if a
555 // message arrived (this is to ease switching between message waiting and
556 // periodic timeout), or an error indication.
558 {
559  HANDLE h = HANDLE_from_sem_t(sem);
560  DWORD ret = MsgWaitForMultipleObjects(1, &h, FALSE, INFINITE, QS_ALLEVENTS);
561  // semaphore is signalled
562  if(ret == WAIT_OBJECT_0)
563  return 0;
564 
565  // something else:
566  // .. message came up
567  if(ret == WAIT_OBJECT_0+1)
568  errno = ETIMEDOUT;
569  // .. error
570  else
571  {
572  errno = EINVAL;
574  }
575  return -1;
576 }
577 
578 
579 //-----------------------------------------------------------------------------
580 // threads
581 //-----------------------------------------------------------------------------
582 
583 // _beginthreadex cannot call the user's thread function directly due to
584 // differences in calling convention; we need to pass its address and
585 // the user-specified data pointer to our trampoline.
586 //
587 // rationale:
588 // - a local variable in pthread_create isn't safe because the
589 // new thread might not start before pthread_create returns.
590 // - using one static FuncAndArg protected by critical section doesn't
591 // work. wutil_Lock allows recursive locking, so if creating 2 threads,
592 // the parent thread may create both without being stopped and thus
593 // stomp on the first thread's func_and_arg.
594 // - blocking pthread_create until the trampoline has latched func_and_arg
595 // would work. this is a bit easier to understand than nonrecursive CS.
596 // deadlock is impossible because thread_start allows the parent to
597 // continue before doing anything dangerous. however, this requires
598 // initializing a semaphore, which leads to init order problems.
599 // - stashing func and arg in TLS would work, but it is a very limited
600 // resource and __declspec(thread) is documented as possibly
601 // interfering with delay loading.
602 // - heap allocations are the obvious safe solution. we'd like to
603 // minimize them, but it's the least painful way.
604 
606 {
607  void* (*func)(void*);
608  void* arg;
609 };
610 
611 // bridge calling conventions required by _beginthreadex and POSIX.
612 static unsigned __stdcall thread_start(void* param)
613 {
614  const FuncAndArg* func_and_arg = (const FuncAndArg*)param;
615  void* (*func)(void*) = func_and_arg->func;
616  void* arg = func_and_arg->arg;
617  wutil_Free(param);
618 
620 
621  void* ret = 0;
622  __try
623  {
624  ret = func(arg);
625  call_tls_dtors();
626  }
627  __except(wseh_ExceptionFilter(GetExceptionInformation()))
628  {
629  ret = 0;
630  }
631 
632  return (unsigned)(uintptr_t)ret;
633 }
634 
635 
636 int pthread_create(pthread_t* thread_id, const void* UNUSED(attr), void* (*func)(void*), void* arg)
637 {
638  // notes:
639  // - use wutil_Allocate instead of the normal heap because we /might/
640  // potentially be called before _cinit.
641  // - placement new is more trouble than it's worth
642  // (see REDEFINED_NEW), so we don't bother with a ctor.
643  FuncAndArg* func_and_arg = (FuncAndArg*)wutil_Allocate(sizeof(FuncAndArg));
644  if(!func_and_arg)
645  {
647  return -1;
648  }
649  func_and_arg->func = func;
650  func_and_arg->arg = arg;
651 
652  // _beginthreadex has more overhead and no value added vs.
653  // CreateThread, but it avoids small memory leaks in
654  // ExitThread when using the statically-linked CRT (-> MSDN).
655  HANDLE hThread = (HANDLE)_beginthreadex(0, 0, thread_start, func_and_arg, 0, 0);
656  if(!hThread)
657  {
659  return -1;
660  }
661 
662  // SUSv3 doesn't specify whether this is optional - go the safe route.
663  if(thread_id)
664  *thread_id = pthread_from_HANDLE(hThread);
665 
666  return 0;
667 }
668 
669 
671 {
672  HANDLE hThread = HANDLE_from_pthread(thread);
673  TerminateThread(hThread, 0);
674  debug_printf(L"WARNING: pthread_cancel is unsafe\n");
675  return 0;
676 }
677 
678 
679 int pthread_join(pthread_t thread, void** value_ptr)
680 {
681  HANDLE hThread = HANDLE_from_pthread(thread);
682 
683  // note: pthread_join doesn't call for a timeout. if this wait
684  // locks up the process, at least it'll be easy to see why.
685  DWORD ret = WaitForSingleObject(hThread, INFINITE);
686  if(ret != WAIT_OBJECT_0)
687  {
689  return -1;
690  }
691 
692  // pass back the code that was passed to pthread_exit.
693  // SUS says <*value_ptr> need only be set on success!
694  if(value_ptr)
695  GetExitCodeThread(hThread, (LPDWORD)value_ptr);
696 
697  CloseHandle(hThread);
698  return 0;
699 }
700 
701 
703 {
705  return INFO::OK;
706 }
const Status LOGIC
Definition: status.h:409
void * pthread_mutex_t
Definition: wpthread.h:82
static const size_t TLS_LIMIT
Definition: wpthread.cpp:131
int pthread_setschedparam(pthread_t thread, int policy, const struct sched_param *param)
Definition: wpthread.cpp:104
int sem_post(sem_t *sem)
Definition: wpthread.cpp:461
#define UNUSED(param)
mark a function parameter as unused and avoid the corresponding compiler warning. ...
int sched_priority
Definition: wpthread.h:37
#define WARN_IF_ERR(expression)
Definition: status.h:265
intptr_t pthread_once_t
Definition: wpthread.h:57
static __declspec(align(64)) TimerState timerStates[2]
const Status OK
Definition: status.h:386
some WinAPI functions SetLastError(0) on success, which is bad because it can hide previous errors...
Definition: wutil.h:119
void * wutil_Allocate(size_t size)
Definition: wutil.cpp:54
#define ETIMEDOUT
Definition: werrno.h:106
int clock_gettime(clockid_t clock, struct timespec *ts)
Definition: wtime.cpp:121
int sem_close(sem_t *sem)
Definition: wpthread.cpp:429
static struct @29 dtors[MAX_DTORS]
int sem_unlink(const char *name)
Definition: wpthread.cpp:438
pthread_mutex_t pthread_mutex_initializer()
Definition: wpthread.cpp:305
static void NotifyCurrentThread()
Definition: wpthread.cpp:61
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout)
Definition: wpthread.cpp:520
int pthread_key_create(pthread_key_t *key, void(*dtor)(void *))
Definition: wpthread.cpp:146
int BOOL
Definition: wgl.h:51
time_t tv_sec
Definition: wtime.h:64
pthread_t pthread_self()
Definition: wpthread.cpp:74
static pthread_t pthread_from_HANDLE(HANDLE h)
Definition: wpthread.cpp:48
static HANDLE HANDLE_from_pthread(pthread_t p)
Definition: wpthread.cpp:43
#define ENSURE(expr)
ensure the expression &lt;expr&gt; evaluates to non-zero.
Definition: debug.h:282
void * pthread_mutexattr_t
Definition: wpthread.h:75
int pthread_create(pthread_t *thread_id, const void *attr, void *(*func)(void *), void *arg)
Definition: wpthread.cpp:636
long tv_nsec
Definition: wtime.h:65
#define WINIT_REGISTER_CRITICAL_INIT(func)
Definition: winit.h:136
int sem_msgwait_np(sem_t *sem)
Definition: wpthread.cpp:557
const Status LIMIT
Definition: status.h:428
void * HANDLE
Definition: wgl.h:62
int sem_destroy(sem_t *sem)
Definition: wpthread.cpp:454
void(* dtor)(void *)
Definition: wpthread.cpp:141
unsigned long DWORD
Definition: wgl.h:56
int pthread_mutex_trylock(pthread_mutex_t *m)
Definition: wpthread.cpp:338
pthread_key_t key
Definition: wpthread.cpp:140
int pthread_mutex_lock(pthread_mutex_t *m)
Definition: wpthread.cpp:329
int pthread_mutex_timedlock(pthread_mutex_t *m, const struct timespec *abs_timeout)
Definition: wpthread.cpp:358
int sem_init(sem_t *sem, int pshared, unsigned value)
Definition: wpthread.cpp:444
int pthread_key_delete(pthread_key_t key)
Definition: wpthread.cpp:173
i64 Status
Error handling system.
Definition: status.h:171
uintptr_t sem_t
Definition: wpthread.h:105
static CRITICAL_SECTION * CRITICAL_SECTION_from_pthread_mutex_t(pthread_mutex_t *m)
Definition: wpthread.cpp:295
int pthread_mutex_init(pthread_mutex_t *m, const pthread_mutexattr_t *)
Definition: wpthread.cpp:323
static CRITICAL_SECTION cs[NUM_CS]
Definition: wutil.cpp:74
int pthread_getschedparam(pthread_t thread, int *policy, struct sched_param *param)
Definition: wpthread.cpp:88
static const size_t MAX_DTORS
Definition: wpthread.cpp:137
void * pthread_getspecific(pthread_key_t key)
Definition: wpthread.cpp:184
#define DEBUG_WARN_ERR(status)
display the error dialog with text corresponding to the given error code.
Definition: debug.h:331
static HANDLE HANDLE_from_sem_t(sem_t *sem)
Definition: wpthread.cpp:368
#define SEM_FAILED
Definition: wpthread.h:107
static void call_tls_dtors()
Definition: wpthread.cpp:221
void * arg
Definition: wpthread.cpp:608
uintptr_t pthread_t
Definition: wpthread.h:63
#define i64
Definition: types.h:37
int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
Definition: wpthread.cpp:289
void *(* func)(void *)
Definition: wpthread.cpp:607
int pthread_setspecific(pthread_key_t key, const void *value)
Definition: wpthread.cpp:210
bool cpu_CAS(volatile intptr_t *location, intptr_t expected, intptr_t newValue)
atomic &quot;compare and swap&quot;.
Definition: arm.cpp:36
#define WARN_IF_FALSE(expression)
Definition: status.h:360
int pthread_mutex_unlock(pthread_mutex_t *m)
Definition: wpthread.cpp:347
int pthread_once(pthread_once_t *once, void(*init_routine)())
Definition: wpthread.cpp:80
int pthread_equal(pthread_t t1, pthread_t t2)
Definition: wpthread.cpp:69
int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type)
Definition: wpthread.cpp:283
static unsigned __stdcall thread_start(void *param)
Definition: wpthread.cpp:612
int sem_wait(sem_t *sem)
Definition: wpthread.cpp:468
const Status FAIL
Definition: status.h:406
Definition: wtime.h:62
int pthread_join(pthread_t thread, void **value_ptr)
Definition: wpthread.cpp:679
int pthread_mutex_destroy(pthread_mutex_t *m)
Definition: wpthread.cpp:312
long LONG
Definition: wgl.h:55
sem_t * sem_open(const char *name, int oflag,...)
Definition: wpthread.cpp:373
long __stdcall wseh_ExceptionFilter(struct _EXCEPTION_POINTERS *ep)
Definition: wseh.cpp:239
const Status NO_MEM
Definition: status.h:430
unsigned int pthread_key_t
Definition: wpthread.h:93
static Status wpthread_Init()
Definition: wpthread.cpp:702
int pthread_cancel(pthread_t thread)
Definition: wpthread.cpp:670
void debug_printf(const wchar_t *fmt,...)
write a formatted string to the debug channel, subject to filtering (see below).
Definition: debug.cpp:142
static DWORD calc_timeout_length_ms(const struct timespec *abs_timeout, bool &timeout_is_valid)
Definition: wpthread.cpp:483
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
Definition: wpthread.cpp:278
int pthread_mutexattr_init(pthread_mutexattr_t *attr)
Definition: wpthread.cpp:273
void wutil_Free(void *p)
Definition: wutil.cpp:60