master
1/*
2 Copyright (c) 2011-2016 mingw-w64 project
3
4 Permission is hereby granted, free of charge, to any person obtaining a
5 copy of this software and associated documentation files (the "Software"),
6 to deal in the Software without restriction, including without limitation
7 the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 and/or sell copies of the Software, and to permit persons to whom the
9 Software is furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 DEALINGS IN THE SOFTWARE.
21*/
22
23#ifdef HAVE_CONFIG_H
24#include "config.h"
25#endif
26
27#include <malloc.h>
28#include <signal.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <wchar.h>
32
33#define WIN32_LEAN_AND_MEAN
34#include <windows.h>
35#include <strsafe.h>
36
37#define WINPTHREAD_THREAD_DECL WINPTHREAD_API
38
39/* public header files */
40#include "pthread.h"
41/* internal header files */
42#include "misc.h"
43#include "thread.h"
44
45static _pthread_v *__pthread_self_lite (void);
46
47void (**_pthread_key_dest)(void *) = NULL;
48
49static volatile long _pthread_cancelling;
50static int _pthread_concur;
51
52/* FIXME Will default to zero as needed */
53static pthread_once_t _pthread_tls_once;
54static DWORD _pthread_tls = 0xffffffff;
55
56static pthread_rwlock_t _pthread_key_lock = PTHREAD_RWLOCK_INITIALIZER;
57static unsigned long _pthread_key_max=0L;
58static unsigned long _pthread_key_sch=0L;
59
60static _pthread_v *pthr_root = NULL, *pthr_last = NULL;
61static pthread_mutex_t mtx_pthr_locked = PTHREAD_RECURSIVE_MUTEX_INITIALIZER;
62
63static __pthread_idlist *idList = NULL;
64static size_t idListCnt = 0;
65static size_t idListMax = 0;
66static pthread_t idListNextId = 0;
67
68#if !defined(_MSC_VER)
69#define USE_VEH_FOR_MSC_SETTHREADNAME
70#endif
71#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
72/* forbidden RemoveVectoredExceptionHandler/AddVectoredExceptionHandler APIs */
73#undef USE_VEH_FOR_MSC_SETTHREADNAME
74#endif
75
76#if defined(USE_VEH_FOR_MSC_SETTHREADNAME)
77static void *SetThreadName_VEH_handle = NULL;
78
79static LONG __stdcall
80SetThreadName_VEH (PEXCEPTION_POINTERS ExceptionInfo)
81{
82 if (ExceptionInfo->ExceptionRecord != NULL &&
83 ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_SET_THREAD_NAME)
84 return EXCEPTION_CONTINUE_EXECUTION;
85
86 return EXCEPTION_CONTINUE_SEARCH;
87}
88
89static PVOID (WINAPI *AddVectoredExceptionHandlerFuncPtr) (ULONG, PVECTORED_EXCEPTION_HANDLER);
90static ULONG (WINAPI *RemoveVectoredExceptionHandlerFuncPtr) (PVOID);
91
92static void __attribute__((constructor))
93ctor (void)
94{
95 HMODULE module = GetModuleHandleA("kernel32.dll");
96 if (module) {
97 AddVectoredExceptionHandlerFuncPtr = (__typeof__(AddVectoredExceptionHandlerFuncPtr)) GetProcAddress(module, "AddVectoredExceptionHandler");
98 RemoveVectoredExceptionHandlerFuncPtr = (__typeof__(RemoveVectoredExceptionHandlerFuncPtr)) GetProcAddress(module, "RemoveVectoredExceptionHandler");
99 }
100}
101#endif
102
103typedef struct _THREADNAME_INFO
104{
105 DWORD dwType; /* must be 0x1000 */
106 LPCSTR szName; /* pointer to name (in user addr space) */
107 DWORD dwThreadID; /* thread ID (-1=caller thread) */
108 DWORD dwFlags; /* reserved for future use, must be zero */
109} THREADNAME_INFO;
110
111static void
112SetThreadName (DWORD dwThreadID, LPCSTR szThreadName)
113{
114 THREADNAME_INFO info;
115 DWORD infosize;
116
117 info.dwType = 0x1000;
118 info.szName = szThreadName;
119 info.dwThreadID = dwThreadID;
120 info.dwFlags = 0;
121
122 infosize = sizeof (info) / sizeof (ULONG_PTR);
123
124#if defined(_MSC_VER) && !defined (USE_VEH_FOR_MSC_SETTHREADNAME)
125 __try
126 {
127 RaiseException (EXCEPTION_SET_THREAD_NAME, 0, infosize, (ULONG_PTR *)&info);
128 }
129 __except (EXCEPTION_EXECUTE_HANDLER)
130 {
131 }
132#else
133 /* Without a debugger we *must* have an exception handler,
134 * otherwise raising an exception will crash the process.
135 */
136#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
137 if ((!IsDebuggerPresent ()) && (SetThreadName_VEH_handle == NULL))
138#else
139 if (!IsDebuggerPresent ())
140#endif
141 return;
142
143 RaiseException (EXCEPTION_SET_THREAD_NAME, 0, infosize, (ULONG_PTR *) &info);
144#endif
145}
146
147/* Search the list idList for an element with identifier ID. If
148 found, its associated _pthread_v pointer is returned, otherwise
149 NULL.
150 NOTE: This method is not locked. */
151static struct _pthread_v *
152__pthread_get_pointer (pthread_t id)
153{
154 size_t l, r, p;
155 if (!idListCnt)
156 return NULL;
157 if (idListCnt == 1)
158 return (idList[0].id == id ? idList[0].ptr : NULL);
159 l = 0; r = idListCnt - 1;
160 while (l <= r)
161 {
162 p = (l + r) >> 1;
163 if (idList[p].id == id)
164 return idList[p].ptr;
165 else if (idList[p].id > id)
166 {
167 if (p == l)
168 return NULL;
169 r = p - 1;
170 }
171 else
172 {
173 l = p + 1;
174 }
175 }
176
177 return NULL;
178}
179
180static void
181__pth_remove_use_for_key (pthread_key_t key)
182{
183 int i;
184
185 pthread_mutex_lock (&mtx_pthr_locked);
186 for (i = 0; i < idListCnt; i++)
187 {
188 if (idList[i].ptr != NULL
189 && idList[i].ptr->keyval != NULL
190 && key < idList[i].ptr->keymax)
191 {
192 idList[i].ptr->keyval[key] = NULL;
193 idList[i].ptr->keyval_set[key] = 0;
194 }
195 }
196 pthread_mutex_unlock (&mtx_pthr_locked);
197}
198
199/* Search the list idList for an element with identifier ID. If
200 found, its associated _pthread_v pointer is returned, otherwise
201 NULL.
202 NOTE: This method uses lock mtx_pthr_locked. */
203struct _pthread_v *
204__pth_gpointer_locked (pthread_t id)
205{
206 struct _pthread_v *ret;
207 if (!id)
208 return NULL;
209 pthread_mutex_lock (&mtx_pthr_locked);
210 ret = __pthread_get_pointer (id);
211 pthread_mutex_unlock (&mtx_pthr_locked);
212 return ret;
213}
214
215/* Registers in the list idList an element with _pthread_v pointer
216 and creates and unique identifier ID. If successful created the
217 ID of this element is returned, otherwise on failure zero ID gets
218 returned.
219 NOTE: This method is not locked. */
220static pthread_t
221__pthread_register_pointer (struct _pthread_v *ptr)
222{
223 __pthread_idlist *e;
224 size_t i;
225
226 if (!ptr)
227 return 0;
228 /* Check if a resize of list is necessary. */
229 if (idListCnt >= idListMax)
230 {
231 if (!idListCnt)
232 {
233 e = (__pthread_idlist *) malloc (sizeof (__pthread_idlist) * 16);
234 if (!e)
235 return 0;
236 idListMax = 16;
237 idList = e;
238 }
239 else
240 {
241 e = (__pthread_idlist *) realloc (idList, sizeof (__pthread_idlist) * (idListMax + 16));
242 if (!e)
243 return 0;
244 idListMax += 16;
245 idList = e;
246 }
247 }
248 do
249 {
250 ++idListNextId;
251 /* If two MSB are set we reset to id 1. We need to check here bits
252 to avoid gcc's no-overflow issue on increment. Additionally we
253 need to handle different size of pthread_t on 32-bit/64-bit. */
254 if ((idListNextId & ( ((pthread_t) 1) << ((sizeof (pthread_t) * 8) - 2))) != 0)
255 idListNextId = 1;
256 }
257 while (idListNextId == 0 || __pthread_get_pointer (idListNextId));
258 /* We assume insert at end of list. */
259 i = idListCnt;
260 if (i != 0)
261 {
262 /* Find position we can actual insert sorted. */
263 while (i > 0 && idList[i - 1].id > idListNextId)
264 --i;
265 if (i != idListCnt)
266 memmove (&idList[i + 1], &idList[i], sizeof (__pthread_idlist) * (idListCnt - i));
267 }
268 idList[i].id = idListNextId;
269 idList[i].ptr = ptr;
270 ++idListCnt;
271 return idListNextId;
272}
273
274/* Deregisters in the list idList an element with identifier ID and
275 returns its _pthread_v pointer on success. Otherwise NULL is returned.
276 NOTE: This method is not locked. */
277static struct _pthread_v *
278__pthread_deregister_pointer (pthread_t id)
279{
280 size_t l, r, p;
281 if (!idListCnt)
282 return NULL;
283 l = 0; r = idListCnt - 1;
284 while (l <= r)
285 {
286 p = (l + r) >> 1;
287 if (idList[p].id == id)
288 {
289 struct _pthread_v *ret = idList[p].ptr;
290 p++;
291 if (p < idListCnt)
292 memmove (&idList[p - 1], &idList[p], sizeof (__pthread_idlist) * (idListCnt - p));
293 --idListCnt;
294 /* Is this last element in list then free list. */
295 if (idListCnt == 0)
296 {
297 free (idList);
298 idListCnt = idListMax = 0;
299 }
300 return ret;
301 }
302 else if (idList[p].id > id)
303 {
304 if (p == l)
305 return NULL;
306 r = p - 1;
307 }
308 else
309 {
310 l = p + 1;
311 }
312 }
313 return NULL;
314}
315
316/* Save a _pthread_v element for reuse in pool. */
317static void
318push_pthread_mem (_pthread_v *sv)
319{
320 if (!sv || sv->next != NULL)
321 return;
322 pthread_mutex_lock (&mtx_pthr_locked);
323 if (sv->x != 0)
324 __pthread_deregister_pointer (sv->x);
325 if (sv->keyval)
326 free (sv->keyval);
327 if (sv->keyval_set)
328 free (sv->keyval_set);
329 if (sv->thread_name)
330 free (sv->thread_name);
331 memset (sv, 0, sizeof(struct _pthread_v));
332 if (pthr_last == NULL)
333 pthr_root = pthr_last = sv;
334 else
335 {
336 pthr_last->next = sv;
337 pthr_last = sv;
338 }
339 pthread_mutex_unlock (&mtx_pthr_locked);
340}
341
342/* Get a _pthread_v element from pool, or allocate it.
343 Note the unique identifier is created for the element here, too. */
344static _pthread_v *
345pop_pthread_mem (void)
346{
347 _pthread_v *r = NULL;
348
349 pthread_mutex_lock (&mtx_pthr_locked);
350 if ((r = pthr_root) == NULL)
351 {
352 if ((r = (_pthread_v *)calloc (1,sizeof(struct _pthread_v))) != NULL)
353 {
354 r->x = __pthread_register_pointer (r);
355 if (r->x == 0)
356 {
357 free (r);
358 r = NULL;
359 }
360 }
361 pthread_mutex_unlock (&mtx_pthr_locked);
362 return r;
363 }
364 r->x = __pthread_register_pointer (r);
365 if (r->x == 0)
366 r = NULL;
367 else
368 {
369 if((pthr_root = r->next) == NULL)
370 pthr_last = NULL;
371
372 r->next = NULL;
373 }
374 pthread_mutex_unlock (&mtx_pthr_locked);
375 return r;
376}
377
378/* Free memory consumed in _pthread_v pointer pool. */
379static void
380free_pthread_mem (void)
381{
382#if 0
383 _pthread_v *t;
384
385 pthread_mutex_lock (&mtx_pthr_locked);
386 t = pthr_root;
387 while (t != NULL)
388 {
389 _pthread_v *sv = t;
390 t = t->next;
391 if (sv->x != 0 && sv->ended == 0 && sv->valid != DEAD_THREAD)
392 {
393 pthread_mutex_unlock (&mtx_pthr_locked);
394 pthread_cancel (t->x);
395 Sleep (0);
396 pthread_mutex_lock (&mtx_pthr_locked);
397 t = pthr_root;
398 continue;
399 }
400 else if (sv->x != 0 && sv->valid != DEAD_THREAD)
401 {
402 pthread_mutex_unlock (&mtx_pthr_locked);
403 Sleep (0);
404 pthread_mutex_lock (&mtx_pthr_locked);
405 continue;
406 }
407 if (sv->x != 0)
408 __pthread_deregister_pointer (sv->x);
409 sv->x = 0;
410 free (sv);
411 pthr_root = t;
412 }
413 pthread_mutex_unlock (&mtx_pthr_locked);
414#endif
415 return;
416}
417
418static void
419replace_spin_keys (pthread_spinlock_t *old, pthread_spinlock_t new)
420{
421 if (old == NULL)
422 return;
423
424 if (EPERM == pthread_spin_destroy (old))
425 {
426#define THREADERR "Error cleaning up spin_keys for thread %lu.\n"
427 char threaderr[sizeof(THREADERR) + 8] = { 0 };
428 snprintf(threaderr, sizeof(threaderr), THREADERR, GetCurrentThreadId());
429#undef THREADERR
430 OutputDebugStringA (threaderr);
431 abort ();
432 }
433
434 *old = new;
435}
436
437/* Hook for TLS-based deregistration/registration of thread. */
438static void WINAPI
439__dyn_tls_pthread (HANDLE hDllHandle, DWORD dwReason, LPVOID lpreserved)
440{
441 _pthread_v *t = NULL;
442 pthread_spinlock_t new_spin_keys = PTHREAD_SPINLOCK_INITIALIZER;
443
444 if (dwReason == DLL_PROCESS_DETACH)
445 {
446#if defined(USE_VEH_FOR_MSC_SETTHREADNAME)
447 if (lpreserved == NULL && SetThreadName_VEH_handle != NULL)
448 {
449 if (RemoveVectoredExceptionHandlerFuncPtr != NULL)
450 RemoveVectoredExceptionHandlerFuncPtr (SetThreadName_VEH_handle);
451 SetThreadName_VEH_handle = NULL;
452 }
453#endif
454 free_pthread_mem ();
455 }
456 else if (dwReason == DLL_PROCESS_ATTACH)
457 {
458#if defined(USE_VEH_FOR_MSC_SETTHREADNAME)
459 if (AddVectoredExceptionHandlerFuncPtr != NULL)
460 SetThreadName_VEH_handle = AddVectoredExceptionHandlerFuncPtr (1, &SetThreadName_VEH);
461 else
462 SetThreadName_VEH_handle = NULL;
463 /* Can't do anything on error anyway, check for NULL later */
464#endif
465 }
466 else if (dwReason == DLL_THREAD_DETACH)
467 {
468 if (_pthread_tls != 0xffffffff)
469 t = (_pthread_v *)TlsGetValue(_pthread_tls);
470 if (t && t->thread_noposix != 0)
471 {
472 _pthread_cleanup_dest (t->x);
473 if (t->h != NULL)
474 {
475 CloseHandle (t->h);
476 if (t->evStart)
477 CloseHandle (t->evStart);
478 t->evStart = NULL;
479 t->h = NULL;
480 }
481 pthread_mutex_destroy (&t->p_clock);
482 replace_spin_keys (&t->spin_keys, new_spin_keys);
483 push_pthread_mem (t);
484 t = NULL;
485 TlsSetValue (_pthread_tls, t);
486 }
487 else if (t && t->ended == 0)
488 {
489 if (t->evStart)
490 CloseHandle(t->evStart);
491 t->evStart = NULL;
492 t->ended = 1;
493 _pthread_cleanup_dest (t->x);
494 if ((t->p_state & PTHREAD_CREATE_DETACHED) == PTHREAD_CREATE_DETACHED)
495 {
496 t->valid = DEAD_THREAD;
497 if (t->h != NULL)
498 CloseHandle (t->h);
499 t->h = NULL;
500 pthread_mutex_destroy(&t->p_clock);
501 replace_spin_keys (&t->spin_keys, new_spin_keys);
502 push_pthread_mem (t);
503 t = NULL;
504 TlsSetValue (_pthread_tls, t);
505 return;
506 }
507 pthread_mutex_destroy(&t->p_clock);
508 replace_spin_keys (&t->spin_keys, new_spin_keys);
509 }
510 else if (t)
511 {
512 if (t->evStart)
513 CloseHandle (t->evStart);
514 t->evStart = NULL;
515 pthread_mutex_destroy (&t->p_clock);
516 replace_spin_keys (&t->spin_keys, new_spin_keys);
517 }
518 }
519}
520
521/* TLS-runtime section variable. */
522
523#if defined(_MSC_VER)
524/* Force a reference to _tls_used to make the linker create the TLS
525 * directory if it's not already there. (e.g. if __declspec(thread)
526 * is not used).
527 * Force a reference to __xl_f to prevent whole program optimization
528 * from discarding the variable. */
529
530/* On x86, symbols are prefixed with an underscore. */
531# if defined(_M_IX86)
532# pragma comment(linker, "/include:__tls_used")
533# pragma comment(linker, "/include:___xl_f")
534# else
535# pragma comment(linker, "/include:_tls_used")
536# pragma comment(linker, "/include:__xl_f")
537# endif
538
539/* .CRT$XLA to .CRT$XLZ is an array of PIMAGE_TLS_CALLBACK
540 * pointers. Pick an arbitrary location for our callback.
541 *
542 * See VC\...\crt\src\vcruntime\tlssup.cpp for reference. */
543
544# pragma section(".CRT$XLF", long, read)
545#endif
546
547WINPTHREADS_ATTRIBUTE((WINPTHREADS_SECTION(".CRT$XLF")))
548extern const PIMAGE_TLS_CALLBACK __xl_f;
549const PIMAGE_TLS_CALLBACK __xl_f = __dyn_tls_pthread;
550
551/* Internal collect-once structure. */
552typedef struct collect_once_t {
553 pthread_once_t *o;
554 pthread_mutex_t m;
555 int count;
556 struct collect_once_t *next;
557} collect_once_t;
558
559static collect_once_t *once_obj = NULL;
560
561static pthread_spinlock_t once_global = PTHREAD_SPINLOCK_INITIALIZER;
562
563static collect_once_t *
564enterOnceObject (pthread_once_t *o)
565{
566 collect_once_t *c, *p = NULL;
567 pthread_spin_lock (&once_global);
568 c = once_obj;
569 while (c != NULL && c->o != o)
570 {
571 c = (p = c)->next;
572 }
573 if (!c)
574 {
575 c = (collect_once_t *) calloc(1,sizeof(collect_once_t));
576 c->o = o;
577 c->count = 1;
578 if (!p)
579 once_obj = c;
580 else
581 p->next = c;
582 pthread_mutex_init(&c->m, NULL);
583 }
584 else
585 c->count += 1;
586 pthread_spin_unlock (&once_global);
587 return c;
588}
589
590static void
591leaveOnceObject (collect_once_t *c)
592{
593 collect_once_t *h, *p = NULL;
594 if (!c)
595 return;
596 pthread_spin_lock (&once_global);
597 h = once_obj;
598 while (h != NULL && c != h)
599 h = (p = h)->next;
600
601 if (h)
602 {
603 c->count -= 1;
604 if (c->count == 0)
605 {
606 pthread_mutex_destroy(&c->m);
607 if (!p)
608 once_obj = c->next;
609 else
610 p->next = c->next;
611 free (c);
612 }
613 }
614 else
615 fprintf(stderr, "%p not found?!?!\n", (void *) c);
616 pthread_spin_unlock (&once_global);
617}
618
619static void
620_pthread_once_cleanup (void *o)
621{
622 collect_once_t *co = (collect_once_t *) o;
623 pthread_mutex_unlock (&co->m);
624 leaveOnceObject (co);
625}
626
627static int
628_pthread_once_raw (pthread_once_t *o, void (*func)(void))
629{
630 collect_once_t *co;
631 long state = *o;
632
633 CHECK_PTR(o);
634 CHECK_PTR(func);
635
636 if (state == 1)
637 return 0;
638 co = enterOnceObject(o);
639 pthread_mutex_lock(&co->m);
640 if (*o == 0)
641 {
642 func();
643 *o = 1;
644 }
645 else if (*o != 1)
646 fprintf (stderr," once %p is %ld\n", (void *) o, (long) *o);
647 pthread_mutex_unlock(&co->m);
648 leaveOnceObject(co);
649
650 /* Done */
651 return 0;
652}
653
654/* Unimplemented. */
655void *
656pthread_timechange_handler_np(void *dummy)
657{
658 return NULL;
659}
660
661/* Compatibility routine for pthread-win32. It waits for ellapse of
662 interval and additionally checks for possible thread-cancelation. */
663static int
664__pthread_delay_np (const struct _timespec64 *interval)
665{
666 DWORD to = (!interval ? 0 : dwMilliSecs (_pthread_time_in_ms_from_timespec (interval)));
667 struct _pthread_v *s = __pthread_self_lite ();
668
669 if (!to)
670 {
671 pthread_testcancel ();
672 Sleep (0);
673 pthread_testcancel ();
674 return 0;
675 }
676 pthread_testcancel ();
677 if (s->evStart)
678 _pthread_wait_for_single_object (s->evStart, to);
679 else
680 Sleep (to);
681 pthread_testcancel ();
682 return 0;
683}
684
685int
686pthread_delay64_np (const struct _timespec64 *interval)
687{
688 return __pthread_delay_np(interval);
689}
690
691int
692pthread_delay32_np (const struct _timespec32 *interval)
693{
694 struct _timespec64 interval64 = {.tv_sec = interval->tv_sec, .tv_nsec = interval->tv_nsec};
695 return __pthread_delay_np(&interval64);
696}
697
698int
699_pthread_delay_np_ms (DWORD to)
700{
701 struct _pthread_v *s = __pthread_self_lite ();
702
703 if (!to)
704 {
705 pthread_testcancel ();
706 Sleep (0);
707 pthread_testcancel ();
708 return 0;
709 }
710 pthread_testcancel ();
711 if (s->evStart)
712 _pthread_wait_for_single_object (s->evStart, to);
713 else
714 Sleep (to);
715 pthread_testcancel ();
716 return 0;
717}
718
719/* Compatibility routine for pthread-win32. It returns the
720 amount of available CPUs on system. */
721int
722pthread_num_processors_np(void)
723{
724 int r = 0;
725 DWORD_PTR ProcessAffinityMask, SystemAffinityMask;
726
727 if (GetProcessAffinityMask(GetCurrentProcess(), &ProcessAffinityMask, &SystemAffinityMask))
728 {
729 for(; ProcessAffinityMask != 0; ProcessAffinityMask >>= 1)
730 r += (ProcessAffinityMask & 1) != 0;
731 }
732 /* assume at least 1 */
733 return r ? r : 1;
734}
735
736/* Compatiblity routine for pthread-win32. Allows to set amount of used
737 CPUs for process. */
738int
739pthread_set_num_processors_np(int n)
740{
741 DWORD_PTR ProcessAffinityMask, ProcessNewAffinityMask = 0, SystemAffinityMask;
742 int r = 0;
743 /* need at least 1 */
744 n = n ? n : 1;
745 if (GetProcessAffinityMask (GetCurrentProcess (), &ProcessAffinityMask, &SystemAffinityMask))
746 {
747 for (; ProcessAffinityMask != 0; ProcessAffinityMask >>= 1)
748 {
749 ProcessNewAffinityMask <<= 1;
750 if ((ProcessAffinityMask & 1) != 0 && r < n)
751 {
752 ProcessNewAffinityMask |= 1;
753 r++;
754 }
755 }
756 SetProcessAffinityMask (GetCurrentProcess (),ProcessNewAffinityMask);
757 }
758 return r;
759}
760
761int
762pthread_once (pthread_once_t *o, void (*func)(void))
763{
764 collect_once_t *co;
765 long state = *o;
766
767 CHECK_PTR(o);
768 CHECK_PTR(func);
769
770 if (state == 1)
771 return 0;
772 co = enterOnceObject(o);
773 pthread_mutex_lock(&co->m);
774 if (*o == 0)
775 {
776 pthread_cleanup_push(_pthread_once_cleanup, co);
777 func();
778 pthread_cleanup_pop(0);
779 *o = 1;
780 }
781 else if (*o != 1)
782 fprintf (stderr," once %p is %ld\n", (void *) o, (long) *o);
783 pthread_mutex_unlock(&co->m);
784 leaveOnceObject(co);
785
786 return 0;
787}
788
789int
790pthread_key_create (pthread_key_t *key, void (* dest)(void *))
791{
792 unsigned int i;
793 long nmax;
794 void (**d)(void *);
795
796 if (!key)
797 return EINVAL;
798
799 pthread_rwlock_wrlock (&_pthread_key_lock);
800
801 for (i = _pthread_key_sch; i < _pthread_key_max; i++)
802 {
803 if (!_pthread_key_dest[i])
804 {
805 *key = i;
806 if (dest)
807 _pthread_key_dest[i] = dest;
808 else
809 _pthread_key_dest[i] = (void(*)(void *))1;
810 pthread_rwlock_unlock (&_pthread_key_lock);
811 return 0;
812 }
813 }
814
815 for (i = 0; i < _pthread_key_sch; i++)
816 {
817 if (!_pthread_key_dest[i])
818 {
819 *key = i;
820 if (dest)
821 _pthread_key_dest[i] = dest;
822 else
823 _pthread_key_dest[i] = (void(*)(void *))1;
824 pthread_rwlock_unlock (&_pthread_key_lock);
825
826 return 0;
827 }
828 }
829
830 if (_pthread_key_max == PTHREAD_KEYS_MAX)
831 {
832 pthread_rwlock_unlock(&_pthread_key_lock);
833 return ENOMEM;
834 }
835
836 nmax = _pthread_key_max * 2;
837 if (nmax == 0)
838 nmax = _pthread_key_max + 1;
839 if (nmax > PTHREAD_KEYS_MAX)
840 nmax = PTHREAD_KEYS_MAX;
841
842 /* No spare room anywhere */
843 d = (void (__cdecl **)(void *))realloc(_pthread_key_dest, nmax * sizeof(*d));
844 if (!d)
845 {
846 pthread_rwlock_unlock (&_pthread_key_lock);
847 return ENOMEM;
848 }
849
850 /* Clear new region */
851 memset ((void *) &d[_pthread_key_max], 0, (nmax-_pthread_key_max)*sizeof(void *));
852
853 /* Use new region */
854 _pthread_key_dest = d;
855 _pthread_key_sch = _pthread_key_max + 1;
856 *key = _pthread_key_max;
857 _pthread_key_max = nmax;
858
859 if (dest)
860 _pthread_key_dest[*key] = dest;
861 else
862 _pthread_key_dest[*key] = (void(*)(void *))1;
863
864 pthread_rwlock_unlock (&_pthread_key_lock);
865 return 0;
866}
867
868int
869pthread_key_delete (pthread_key_t key)
870{
871 if (key >= _pthread_key_max || !_pthread_key_dest)
872 return EINVAL;
873
874 pthread_rwlock_wrlock (&_pthread_key_lock);
875
876 _pthread_key_dest[key] = NULL;
877
878 /* Start next search from our location */
879 if (_pthread_key_sch > key)
880 _pthread_key_sch = key;
881 /* So now we need to walk the complete list of threads
882 and remove key's reference for it. */
883 __pth_remove_use_for_key (key);
884
885 pthread_rwlock_unlock (&_pthread_key_lock);
886 return 0;
887}
888
889void *
890pthread_getspecific (pthread_key_t key)
891{
892 DWORD lasterr = GetLastError ();
893 void *r;
894 _pthread_v *t = __pthread_self_lite ();
895 pthread_spin_lock (&t->spin_keys);
896 r = (key >= t->keymax || t->keyval_set[key] == 0 ? NULL : t->keyval[key]);
897 pthread_spin_unlock (&t->spin_keys);
898 SetLastError (lasterr);
899 return r;
900}
901
902int
903pthread_setspecific (pthread_key_t key, const void *value)
904{
905 DWORD lasterr = GetLastError ();
906 _pthread_v *t = __pthread_self_lite ();
907
908 pthread_spin_lock (&t->spin_keys);
909
910 if (key >= t->keymax)
911 {
912 int keymax = (key + 1);
913 void **kv;
914 unsigned char *kv_set;
915
916 kv = (void **) realloc (t->keyval, keymax * sizeof (void *));
917
918 if (!kv)
919 {
920 pthread_spin_unlock (&t->spin_keys);
921 return ENOMEM;
922 }
923 kv_set = (unsigned char *) realloc (t->keyval_set, keymax);
924 if (!kv_set)
925 {
926 pthread_spin_unlock (&t->spin_keys);
927 return ENOMEM;
928 }
929
930 /* Clear new region */
931 memset (&kv[t->keymax], 0, (keymax - t->keymax)*sizeof(void *));
932 memset (&kv_set[t->keymax], 0, (keymax - t->keymax));
933
934 t->keyval = kv;
935 t->keyval_set = kv_set;
936 t->keymax = keymax;
937 }
938
939 t->keyval[key] = (void *) value;
940 t->keyval_set[key] = 1;
941 pthread_spin_unlock (&t->spin_keys);
942 SetLastError (lasterr);
943
944 return 0;
945}
946
947int
948pthread_equal (pthread_t t1, pthread_t t2)
949{
950 return (t1 == t2);
951}
952
953void
954pthread_tls_init (void)
955{
956 _pthread_tls = TlsAlloc();
957
958 /* Cannot continue if out of indexes */
959 if (_pthread_tls == TLS_OUT_OF_INDEXES)
960 abort();
961}
962
963void
964_pthread_cleanup_dest (pthread_t t)
965{
966 _pthread_v *tv;
967 unsigned int j;
968 int i;
969
970 if (!t)
971 return;
972 tv = __pth_gpointer_locked (t);
973 if (!tv)
974 return;
975
976 for (j = 0; j < PTHREAD_DESTRUCTOR_ITERATIONS; j++)
977 {
978 int flag = 0;
979
980 pthread_spin_lock (&tv->spin_keys);
981 for (i = tv->keymax - 1; i >= 0; i--)
982 {
983 void *val = tv->keyval[i];
984
985 if (tv->keyval_set[i])
986 {
987 pthread_rwlock_rdlock (&_pthread_key_lock);
988 if ((uintptr_t) _pthread_key_dest[i] > 1)
989 {
990 /* Call destructor */
991 tv->keyval[i] = NULL;
992 tv->keyval_set[i] = 0;
993 pthread_spin_unlock (&tv->spin_keys);
994 _pthread_key_dest[i](val);
995 pthread_spin_lock (&tv->spin_keys);
996 flag = 1;
997 }
998 else
999 {
1000 tv->keyval[i] = NULL;
1001 tv->keyval_set[i] = 0;
1002 }
1003 pthread_rwlock_unlock(&_pthread_key_lock);
1004 }
1005 }
1006 pthread_spin_unlock (&tv->spin_keys);
1007 /* Nothing to do? */
1008 if (!flag)
1009 return;
1010 }
1011}
1012
1013static _pthread_v *
1014__pthread_self_lite (void)
1015{
1016 _pthread_v *t;
1017 pthread_spinlock_t new_spin_keys = PTHREAD_SPINLOCK_INITIALIZER;
1018
1019 _pthread_once_raw (&_pthread_tls_once, pthread_tls_init);
1020
1021 t = (_pthread_v *) TlsGetValue (_pthread_tls);
1022 if (t)
1023 return t;
1024 /* Main thread? */
1025 t = (struct _pthread_v *) pop_pthread_mem ();
1026
1027 /* If cannot initialize main thread, then the only thing we can do is return null pthread_t */
1028 if (!__xl_f || !t)
1029 return 0;
1030
1031 t->p_state = PTHREAD_DEFAULT_ATTR /*| PTHREAD_CREATE_DETACHED*/;
1032 t->tid = GetCurrentThreadId();
1033 t->evStart = CreateEvent (NULL, 1, 0, NULL);
1034 t->p_clock = PTHREAD_MUTEX_INITIALIZER;
1035 replace_spin_keys (&t->spin_keys, new_spin_keys);
1036 t->sched_pol = SCHED_OTHER;
1037 t->h = NULL; //GetCurrentThread();
1038 if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &t->h, 0, FALSE, DUPLICATE_SAME_ACCESS))
1039 abort ();
1040 t->sched.sched_priority = GetThreadPriority(t->h);
1041 t->ended = 0;
1042 t->thread_noposix = 1;
1043
1044 /* Save for later */
1045 if (!TlsSetValue(_pthread_tls, t))
1046 abort ();
1047 return t;
1048}
1049
1050pthread_t
1051pthread_self (void)
1052{
1053 _pthread_v *t = __pthread_self_lite ();
1054
1055 if (!t)
1056 return 0;
1057 return t->x;
1058}
1059
1060/* Internal helper for getting event handle of thread T. */
1061void *
1062pthread_getevent (void)
1063{
1064 _pthread_v *t = __pthread_self_lite ();
1065 return (!t ? NULL : t->evStart);
1066}
1067
1068/* Internal helper for getting thread handle of thread T. */
1069void *
1070pthread_gethandle (pthread_t t)
1071{
1072 struct _pthread_v *tv = __pth_gpointer_locked (t);
1073 return (!tv ? NULL : tv->h);
1074}
1075
1076/* Internal helper for getting pointer of clean of current thread. */
1077struct _pthread_cleanup **
1078pthread_getclean (void)
1079{
1080 struct _pthread_v *t = __pthread_self_lite ();
1081 if (!t) return NULL;
1082 return &t->clean;
1083}
1084
1085int
1086pthread_get_concurrency (int *val)
1087{
1088 *val = _pthread_concur;
1089 return 0;
1090}
1091
1092int
1093pthread_set_concurrency (int val)
1094{
1095 _pthread_concur = val;
1096 return 0;
1097}
1098
1099void
1100pthread_exit (void *res)
1101{
1102 _pthread_v *t = NULL;
1103 unsigned rslt = (unsigned) ((intptr_t) res);
1104 struct _pthread_v *id = __pthread_self_lite ();
1105
1106 id->ret_arg = res;
1107
1108 _pthread_cleanup_dest (id->x);
1109 if (id->thread_noposix == 0)
1110 longjmp(id->jb, 1);
1111
1112 /* Make sure we free ourselves if we are detached */
1113 if ((t = (_pthread_v *)TlsGetValue(_pthread_tls)) != NULL)
1114 {
1115 if (!t->h)
1116 {
1117 t->valid = DEAD_THREAD;
1118 if (t->evStart)
1119 CloseHandle (t->evStart);
1120 t->evStart = NULL;
1121 rslt = (unsigned) (size_t) t->ret_arg;
1122 push_pthread_mem(t);
1123 t = NULL;
1124 TlsSetValue (_pthread_tls, t);
1125 }
1126 else
1127 {
1128 rslt = (unsigned) (size_t) t->ret_arg;
1129 t->ended = 1;
1130 if (t->evStart)
1131 CloseHandle (t->evStart);
1132 t->evStart = NULL;
1133 if ((t->p_state & PTHREAD_CREATE_DETACHED) == PTHREAD_CREATE_DETACHED)
1134 {
1135 t->valid = DEAD_THREAD;
1136 CloseHandle (t->h);
1137 t->h = NULL;
1138 push_pthread_mem(t);
1139 t = NULL;
1140 TlsSetValue(_pthread_tls, t);
1141 }
1142 }
1143 }
1144 /* Time to die */
1145 _endthreadex(rslt);
1146}
1147
1148void
1149_pthread_invoke_cancel (void)
1150{
1151 _pthread_cleanup *pcup;
1152 struct _pthread_v *se = __pthread_self_lite ();
1153 se->in_cancel = 1;
1154 _pthread_setnobreak (1);
1155 InterlockedDecrement(&_pthread_cancelling);
1156
1157 /* Call cancel queue */
1158 for (pcup = se->clean; pcup; pcup = pcup->next)
1159 {
1160 pcup->func((pthread_once_t *)pcup->arg);
1161 }
1162
1163 _pthread_setnobreak (0);
1164 pthread_exit(PTHREAD_CANCELED);
1165}
1166
1167int
1168__pthread_shallcancel (void)
1169{
1170 struct _pthread_v *t;
1171 if (!_pthread_cancelling)
1172 return 0;
1173 t = __pthread_self_lite ();
1174 if (t == NULL)
1175 return 0;
1176 if (t->nobreak <= 0 && t->cancelled && (t->p_state & PTHREAD_CANCEL_ENABLE))
1177 return 1;
1178 return 0;
1179}
1180
1181void
1182_pthread_setnobreak (int v)
1183{
1184 struct _pthread_v *t = __pthread_self_lite ();
1185 if (t == NULL)
1186 return;
1187 if (v > 0)
1188 InterlockedIncrement ((long*)&t->nobreak);
1189 else
1190 InterlockedDecrement((long*)&t->nobreak);
1191}
1192
1193void
1194pthread_testcancel (void)
1195{
1196 struct _pthread_v *self = __pthread_self_lite ();
1197
1198 if (!self || self->in_cancel)
1199 return;
1200 if (!_pthread_cancelling)
1201 return;
1202 pthread_mutex_lock (&self->p_clock);
1203
1204 if (self->cancelled && (self->p_state & PTHREAD_CANCEL_ENABLE) && self->nobreak <= 0)
1205 {
1206 self->in_cancel = 1;
1207 self->p_state &= ~PTHREAD_CANCEL_ENABLE;
1208 if (self->evStart)
1209 ResetEvent (self->evStart);
1210 pthread_mutex_unlock (&self->p_clock);
1211 _pthread_invoke_cancel ();
1212 }
1213 pthread_mutex_unlock (&self->p_clock);
1214}
1215
1216int
1217pthread_cancel (pthread_t t)
1218{
1219 struct _pthread_v *tv = __pth_gpointer_locked (t);
1220
1221 if (tv == NULL)
1222 return ESRCH;
1223 CHECK_OBJECT(tv, ESRCH);
1224 /*if (tv->ended) return ESRCH;*/
1225 pthread_mutex_lock(&tv->p_clock);
1226 if (pthread_equal(pthread_self(), t))
1227 {
1228 if(tv->cancelled)
1229 {
1230 pthread_mutex_unlock(&tv->p_clock);
1231 return (tv->in_cancel ? ESRCH : 0);
1232 }
1233 tv->cancelled = 1;
1234 InterlockedIncrement(&_pthread_cancelling);
1235 if(tv->evStart) SetEvent(tv->evStart);
1236 if ((tv->p_state & PTHREAD_CANCEL_ASYNCHRONOUS) != 0 && (tv->p_state & PTHREAD_CANCEL_ENABLE) != 0)
1237 {
1238 tv->p_state &= ~PTHREAD_CANCEL_ENABLE;
1239 tv->in_cancel = 1;
1240 pthread_mutex_unlock(&tv->p_clock);
1241 _pthread_invoke_cancel();
1242 }
1243 else
1244 pthread_mutex_unlock(&tv->p_clock);
1245 return 0;
1246 }
1247
1248 if ((tv->p_state & PTHREAD_CANCEL_ASYNCHRONOUS) != 0 && (tv->p_state & PTHREAD_CANCEL_ENABLE) != 0)
1249 {
1250 /* Dangerous asynchronous cancelling */
1251 CONTEXT ctxt;
1252
1253 if(tv->in_cancel)
1254 {
1255 pthread_mutex_unlock(&tv->p_clock);
1256 return (tv->in_cancel ? ESRCH : 0);
1257 }
1258 /* Already done? */
1259 if(tv->cancelled || tv->in_cancel)
1260 {
1261 /* ??? pthread_mutex_unlock (&tv->p_clock); */
1262 return ESRCH;
1263 }
1264
1265 ctxt.ContextFlags = CONTEXT_CONTROL;
1266
1267 SuspendThread (tv->h);
1268 if (WaitForSingleObject (tv->h, 0) == WAIT_TIMEOUT)
1269 {
1270 GetThreadContext(tv->h, &ctxt);
1271#ifdef _M_X64
1272 ctxt.Rip = (uintptr_t) _pthread_invoke_cancel;
1273#elif defined(_M_IX86)
1274 ctxt.Eip = (uintptr_t) _pthread_invoke_cancel;
1275#elif defined(_M_ARM) || defined(_M_ARM64)
1276 ctxt.Pc = (uintptr_t) _pthread_invoke_cancel;
1277#else
1278#error Unsupported architecture
1279#endif
1280#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
1281 SetThreadContext (tv->h, &ctxt);
1282#endif
1283
1284 /* Also try deferred Cancelling */
1285 tv->cancelled = 1;
1286 tv->p_state &= ~PTHREAD_CANCEL_ENABLE;
1287 tv->in_cancel = 1;
1288
1289 /* Notify everyone to look */
1290 InterlockedIncrement (&_pthread_cancelling);
1291 if (tv->evStart)
1292 SetEvent (tv->evStart);
1293 pthread_mutex_unlock (&tv->p_clock);
1294
1295 ResumeThread (tv->h);
1296 }
1297 }
1298 else
1299 {
1300 if (tv->cancelled == 0)
1301 {
1302 /* Safe deferred Cancelling */
1303 tv->cancelled = 1;
1304
1305 /* Notify everyone to look */
1306 InterlockedIncrement (&_pthread_cancelling);
1307 if (tv->evStart)
1308 SetEvent (tv->evStart);
1309 }
1310 else
1311 {
1312 pthread_mutex_unlock (&tv->p_clock);
1313 return (tv->in_cancel ? ESRCH : 0);
1314 }
1315 }
1316 pthread_mutex_unlock (&tv->p_clock);
1317 return 0;
1318}
1319
1320/* half-stubbed version as we don't really well support signals */
1321int
1322pthread_kill (pthread_t t, int sig)
1323{
1324 struct _pthread_v *tv;
1325
1326 pthread_mutex_lock (&mtx_pthr_locked);
1327 tv = __pthread_get_pointer (t);
1328 if (!tv || t != tv->x || tv->in_cancel || tv->ended || tv->h == NULL
1329 || tv->h == INVALID_HANDLE_VALUE)
1330 {
1331 pthread_mutex_unlock (&mtx_pthr_locked);
1332 return ESRCH;
1333 }
1334 pthread_mutex_unlock (&mtx_pthr_locked);
1335 if (!sig)
1336 return 0;
1337 if (sig < SIGINT || sig > NSIG)
1338 return EINVAL;
1339 return pthread_cancel(t);
1340}
1341
1342unsigned
1343_pthread_get_state (const pthread_attr_t *attr, unsigned flag)
1344{
1345 return (attr->p_state & flag);
1346}
1347
1348int
1349_pthread_set_state (pthread_attr_t *attr, unsigned flag, unsigned val)
1350{
1351 if (~flag & val)
1352 return EINVAL;
1353 attr->p_state &= ~flag;
1354 attr->p_state |= val;
1355
1356 return 0;
1357}
1358
1359int
1360pthread_attr_init (pthread_attr_t *attr)
1361{
1362 memset (attr, 0, sizeof (pthread_attr_t));
1363 attr->p_state = PTHREAD_DEFAULT_ATTR;
1364 attr->stack = NULL;
1365 attr->s_size = 0;
1366 return 0;
1367}
1368
1369int
1370pthread_attr_destroy (pthread_attr_t *attr)
1371{
1372 /* No need to do anything */
1373 memset (attr, 0, sizeof(pthread_attr_t));
1374 return 0;
1375}
1376
1377int
1378pthread_attr_setdetachstate (pthread_attr_t *a, int flag)
1379{
1380 return _pthread_set_state(a, PTHREAD_CREATE_DETACHED, flag);
1381}
1382
1383int
1384pthread_attr_getdetachstate (const pthread_attr_t *a, int *flag)
1385{
1386 *flag = _pthread_get_state(a, PTHREAD_CREATE_DETACHED);
1387 return 0;
1388}
1389
1390int
1391pthread_attr_setinheritsched (pthread_attr_t *a, int flag)
1392{
1393 if (!a || (flag != PTHREAD_INHERIT_SCHED && flag != PTHREAD_EXPLICIT_SCHED))
1394 return EINVAL;
1395 return _pthread_set_state(a, PTHREAD_INHERIT_SCHED, flag);
1396}
1397
1398int
1399pthread_attr_getinheritsched (const pthread_attr_t *a, int *flag)
1400{
1401 *flag = _pthread_get_state(a, PTHREAD_INHERIT_SCHED);
1402 return 0;
1403}
1404
1405int
1406pthread_attr_setscope (pthread_attr_t *a, int flag)
1407{
1408 return _pthread_set_state(a, PTHREAD_SCOPE_SYSTEM, flag);
1409}
1410
1411int
1412pthread_attr_getscope (const pthread_attr_t *a, int *flag)
1413{
1414 *flag = _pthread_get_state(a, PTHREAD_SCOPE_SYSTEM);
1415 return 0;
1416}
1417
1418int
1419pthread_attr_getstack (const pthread_attr_t *attr, void **stack, size_t *size)
1420{
1421 *stack = (char *) attr->stack - attr->s_size;
1422 *size = attr->s_size;
1423 return 0;
1424}
1425
1426int
1427pthread_attr_setstack (pthread_attr_t *attr, void *stack, size_t size)
1428{
1429 attr->s_size = size;
1430 attr->stack = (char *) stack + size;
1431 return 0;
1432}
1433
1434int
1435pthread_attr_getstackaddr (const pthread_attr_t *attr, void **stack)
1436{
1437 *stack = attr->stack;
1438 return 0;
1439}
1440
1441int
1442pthread_attr_setstackaddr (pthread_attr_t *attr, void *stack)
1443{
1444 attr->stack = stack;
1445 return 0;
1446}
1447
1448int
1449pthread_attr_getstacksize (const pthread_attr_t *attr, size_t *size)
1450{
1451 *size = attr->s_size;
1452 return 0;
1453}
1454
1455int
1456pthread_attr_setstacksize (pthread_attr_t *attr, size_t size)
1457{
1458 attr->s_size = size;
1459 return 0;
1460}
1461
1462static void
1463test_cancel_locked (pthread_t t)
1464{
1465 struct _pthread_v *tv = __pth_gpointer_locked (t);
1466
1467 if (!tv || tv->in_cancel || tv->ended != 0 || (tv->p_state & PTHREAD_CANCEL_ENABLE) == 0)
1468 return;
1469 if ((tv->p_state & PTHREAD_CANCEL_ASYNCHRONOUS) == 0)
1470 return;
1471 if (WaitForSingleObject(tv->evStart, 0) != WAIT_OBJECT_0)
1472 return;
1473 pthread_mutex_unlock (&tv->p_clock);
1474 _pthread_invoke_cancel();
1475}
1476
1477int
1478pthread_setcancelstate (int state, int *oldstate)
1479{
1480 _pthread_v *t = __pthread_self_lite ();
1481
1482 if (!t || (state & PTHREAD_CANCEL_ENABLE) != state)
1483 return EINVAL;
1484
1485 pthread_mutex_lock (&t->p_clock);
1486 if (oldstate)
1487 *oldstate = t->p_state & PTHREAD_CANCEL_ENABLE;
1488 t->p_state &= ~PTHREAD_CANCEL_ENABLE;
1489 t->p_state |= state;
1490 test_cancel_locked (t->x);
1491 pthread_mutex_unlock (&t->p_clock);
1492
1493 return 0;
1494}
1495
1496int
1497pthread_setcanceltype (int type, int *oldtype)
1498{
1499 _pthread_v *t = __pthread_self_lite ();
1500
1501 if (!t || (type & PTHREAD_CANCEL_ASYNCHRONOUS) != type)
1502 return EINVAL;
1503
1504 pthread_mutex_lock (&t->p_clock);
1505 if (oldtype)
1506 *oldtype = t->p_state & PTHREAD_CANCEL_ASYNCHRONOUS;
1507 t->p_state &= ~PTHREAD_CANCEL_ASYNCHRONOUS;
1508 t->p_state |= type;
1509 test_cancel_locked (t->x);
1510 pthread_mutex_unlock (&t->p_clock);
1511
1512 return 0;
1513}
1514
1515void _fpreset (void);
1516
1517#if defined(__i386__)
1518/* Align ESP on 16-byte boundaries. */
1519# if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2))
1520__attribute__((force_align_arg_pointer))
1521# endif
1522#endif
1523unsigned __stdcall
1524pthread_create_wrapper (void *args)
1525{
1526 unsigned rslt = 0;
1527 struct _pthread_v *tv = (struct _pthread_v *)args;
1528
1529 _fpreset();
1530
1531 pthread_mutex_lock (&mtx_pthr_locked);
1532 pthread_mutex_lock (&tv->p_clock);
1533 _pthread_once_raw(&_pthread_tls_once, pthread_tls_init);
1534 TlsSetValue(_pthread_tls, tv);
1535 tv->tid = GetCurrentThreadId();
1536 pthread_mutex_unlock (&tv->p_clock);
1537
1538
1539 if (!setjmp(tv->jb))
1540 {
1541 intptr_t trslt = (intptr_t) 128;
1542 /* Provide to this thread a default exception handler. */
1543 #ifdef __SEH__
1544 asm ("\t.tl_start:\n");
1545 #endif /* Call function and save return value */
1546 pthread_mutex_unlock (&mtx_pthr_locked);
1547 if (tv->func)
1548 trslt = (intptr_t) tv->func(tv->ret_arg);
1549 #ifdef __SEH__
1550 asm ("\tnop\n\t.tl_end: nop\n");
1551 #endif
1552 pthread_mutex_lock (&mtx_pthr_locked);
1553 tv->ret_arg = (void*) trslt;
1554 /* Clean up destructors */
1555 _pthread_cleanup_dest(tv->x);
1556 }
1557 else
1558 pthread_mutex_lock (&mtx_pthr_locked);
1559
1560 pthread_mutex_lock (&tv->p_clock);
1561 rslt = (unsigned) (size_t) tv->ret_arg;
1562 /* Make sure we free ourselves if we are detached */
1563 if (tv->evStart)
1564 CloseHandle (tv->evStart);
1565 tv->evStart = NULL;
1566 if (!tv->h)
1567 {
1568 tv->valid = DEAD_THREAD;
1569 pthread_mutex_unlock (&tv->p_clock);
1570 pthread_mutex_destroy (&tv->p_clock);
1571 push_pthread_mem (tv);
1572 tv = NULL;
1573 TlsSetValue (_pthread_tls, tv);
1574 }
1575 else
1576 {
1577 pthread_mutex_unlock (&tv->p_clock);
1578 pthread_mutex_destroy (&tv->p_clock);
1579 /* Reinitialise p_clock, since there may be attempts at
1580 destroying it again in __dyn_tls_thread later on. */
1581 tv->p_clock = PTHREAD_MUTEX_INITIALIZER;
1582 tv->ended = 1;
1583 }
1584 while (pthread_mutex_unlock (&mtx_pthr_locked) == 0)
1585 Sleep (0);
1586 _endthreadex (rslt);
1587 return rslt;
1588
1589#if defined(__SEH__)
1590 asm(
1591#ifdef __arm__
1592 "\t.seh_handler __C_specific_handler, %except\n"
1593#else
1594 "\t.seh_handler __C_specific_handler, @except\n"
1595#endif
1596 "\t.seh_handlerdata\n"
1597 "\t.long 1\n"
1598 "\t.rva .tl_start, .tl_end, _gnu_exception_handler ,.tl_end\n"
1599 "\t.text\n");
1600#endif
1601}
1602
1603int
1604pthread_create (pthread_t *th, const pthread_attr_t *attr, void *(* func)(void *), void *arg)
1605{
1606 HANDLE thrd = NULL;
1607 int redo = 0;
1608 struct _pthread_v *tv;
1609 unsigned int ssize = 0;
1610 pthread_spinlock_t new_spin_keys = PTHREAD_SPINLOCK_INITIALIZER;
1611
1612 if (attr && attr->s_size > UINT_MAX)
1613 return EINVAL;
1614
1615 if ((tv = pop_pthread_mem ()) == NULL)
1616 return EAGAIN;
1617
1618 if (th)
1619 *th = tv->x;
1620
1621 /* Save data in pthread_t */
1622 tv->ended = 0;
1623 tv->ret_arg = arg;
1624 tv->func = func;
1625 tv->p_state = PTHREAD_DEFAULT_ATTR;
1626 tv->h = INVALID_HANDLE_VALUE;
1627 /* We retry it here a few times, as events are a limited resource ... */
1628 do
1629 {
1630 tv->evStart = CreateEvent (NULL, 1, 0, NULL);
1631 if (tv->evStart != NULL)
1632 break;
1633 Sleep ((!redo ? 0 : 20));
1634 }
1635 while (++redo <= 4);
1636
1637 tv->p_clock = PTHREAD_MUTEX_INITIALIZER;
1638 replace_spin_keys (&tv->spin_keys, new_spin_keys);
1639 tv->valid = LIFE_THREAD;
1640 tv->sched.sched_priority = THREAD_PRIORITY_NORMAL;
1641 tv->sched_pol = SCHED_OTHER;
1642 if (tv->evStart == NULL)
1643 {
1644 if (th)
1645 memset (th, 0, sizeof (pthread_t));
1646 push_pthread_mem (tv);
1647 return EAGAIN;
1648 }
1649
1650 if (attr)
1651 {
1652 int inh = 0;
1653 tv->p_state = attr->p_state;
1654 ssize = (unsigned int)attr->s_size;
1655 pthread_attr_getinheritsched (attr, &inh);
1656 if (inh)
1657 {
1658 tv->sched.sched_priority = __pthread_self_lite ()->sched.sched_priority;
1659 }
1660 else
1661 tv->sched.sched_priority = attr->param.sched_priority;
1662 }
1663
1664 /* Make sure tv->h has value of INVALID_HANDLE_VALUE */
1665 _ReadWriteBarrier();
1666
1667 thrd = (HANDLE) _beginthreadex(NULL, ssize, pthread_create_wrapper, tv, 0x4/*CREATE_SUSPEND*/, NULL);
1668 if (thrd == INVALID_HANDLE_VALUE)
1669 thrd = 0;
1670 /* Failed */
1671 if (!thrd)
1672 {
1673 if (tv->evStart)
1674 CloseHandle (tv->evStart);
1675 pthread_mutex_destroy (&tv->p_clock);
1676 replace_spin_keys (&tv->spin_keys, new_spin_keys);
1677 tv->evStart = NULL;
1678 tv->h = 0;
1679 if (th)
1680 memset (th, 0, sizeof (pthread_t));
1681 push_pthread_mem (tv);
1682 return EAGAIN;
1683 }
1684 {
1685 int pr = tv->sched.sched_priority;
1686 if (pr <= THREAD_PRIORITY_IDLE) {
1687 pr = THREAD_PRIORITY_IDLE;
1688 } else if (pr <= THREAD_PRIORITY_LOWEST) {
1689 pr = THREAD_PRIORITY_LOWEST;
1690 } else if (pr >= THREAD_PRIORITY_TIME_CRITICAL) {
1691 pr = THREAD_PRIORITY_TIME_CRITICAL;
1692 } else if (pr >= THREAD_PRIORITY_HIGHEST) {
1693 pr = THREAD_PRIORITY_HIGHEST;
1694 }
1695 SetThreadPriority (thrd, pr);
1696 }
1697 ResetEvent (tv->evStart);
1698 if ((tv->p_state & PTHREAD_CREATE_DETACHED) != 0)
1699 {
1700 tv->h = 0;
1701 ResumeThread (thrd);
1702 CloseHandle (thrd);
1703 }
1704 else
1705 {
1706 tv->h = thrd;
1707 ResumeThread (thrd);
1708 }
1709 Sleep (0);
1710 return 0;
1711}
1712
1713int
1714pthread_join (pthread_t t, void **res)
1715{
1716 DWORD dwFlags;
1717 struct _pthread_v *tv = __pth_gpointer_locked (t);
1718 pthread_spinlock_t new_spin_keys = PTHREAD_SPINLOCK_INITIALIZER;
1719
1720 if (!tv || tv->h == NULL || !GetHandleInformation(tv->h, &dwFlags))
1721 return ESRCH;
1722 if ((tv->p_state & PTHREAD_CREATE_DETACHED) != 0)
1723 return EINVAL;
1724 if (pthread_equal(pthread_self(), t))
1725 return EDEADLK;
1726
1727 /* pthread_testcancel (); */
1728 if (tv->ended == 0 || (tv->h != NULL && tv->h != INVALID_HANDLE_VALUE))
1729 WaitForSingleObject (tv->h, INFINITE);
1730 CloseHandle (tv->h);
1731 if (tv->evStart)
1732 CloseHandle (tv->evStart);
1733 tv->evStart = NULL;
1734 /* Obtain return value */
1735 if (res)
1736 *res = tv->ret_arg;
1737 pthread_mutex_destroy (&tv->p_clock);
1738 replace_spin_keys (&tv->spin_keys, new_spin_keys);
1739 push_pthread_mem (tv);
1740
1741 return 0;
1742}
1743
1744int
1745_pthread_tryjoin (pthread_t t, void **res)
1746{
1747 DWORD dwFlags;
1748 struct _pthread_v *tv;
1749 pthread_spinlock_t new_spin_keys = PTHREAD_SPINLOCK_INITIALIZER;
1750
1751 pthread_mutex_lock (&mtx_pthr_locked);
1752 tv = __pthread_get_pointer (t);
1753
1754 if (!tv || tv->h == NULL || !GetHandleInformation(tv->h, &dwFlags))
1755 {
1756 pthread_mutex_unlock (&mtx_pthr_locked);
1757 return ESRCH;
1758 }
1759
1760 if ((tv->p_state & PTHREAD_CREATE_DETACHED) != 0)
1761 {
1762 pthread_mutex_unlock (&mtx_pthr_locked);
1763 return EINVAL;
1764 }
1765 if (pthread_equal(pthread_self(), t))
1766 {
1767 pthread_mutex_unlock (&mtx_pthr_locked);
1768 return EDEADLK;
1769 }
1770 if(tv->ended == 0 && WaitForSingleObject(tv->h, 0))
1771 {
1772 if (tv->ended == 0)
1773 {
1774 pthread_mutex_unlock (&mtx_pthr_locked);
1775 /* pthread_testcancel (); */
1776 return EBUSY;
1777 }
1778 }
1779 CloseHandle (tv->h);
1780 if (tv->evStart)
1781 CloseHandle (tv->evStart);
1782 tv->evStart = NULL;
1783
1784 /* Obtain return value */
1785 if (res)
1786 *res = tv->ret_arg;
1787 pthread_mutex_destroy (&tv->p_clock);
1788 replace_spin_keys (&tv->spin_keys, new_spin_keys);
1789
1790 push_pthread_mem (tv);
1791
1792 pthread_mutex_unlock (&mtx_pthr_locked);
1793 /* pthread_testcancel (); */
1794 return 0;
1795}
1796
1797int
1798pthread_detach (pthread_t t)
1799{
1800 int r = 0;
1801 DWORD dwFlags;
1802 struct _pthread_v *tv = __pth_gpointer_locked (t);
1803 HANDLE dw;
1804 pthread_spinlock_t new_spin_keys = PTHREAD_SPINLOCK_INITIALIZER;
1805
1806 pthread_mutex_lock (&mtx_pthr_locked);
1807 if (!tv || tv->h == NULL || !GetHandleInformation(tv->h, &dwFlags))
1808 {
1809 pthread_mutex_unlock (&mtx_pthr_locked);
1810 return ESRCH;
1811 }
1812 if ((tv->p_state & PTHREAD_CREATE_DETACHED) != 0)
1813 {
1814 pthread_mutex_unlock (&mtx_pthr_locked);
1815 return EINVAL;
1816 }
1817 /* if (tv->ended) r = ESRCH; */
1818 dw = tv->h;
1819 tv->h = 0;
1820 tv->p_state |= PTHREAD_CREATE_DETACHED;
1821 _ReadWriteBarrier();
1822 if (dw)
1823 {
1824 CloseHandle (dw);
1825 if (tv->ended)
1826 {
1827 if (tv->evStart)
1828 CloseHandle (tv->evStart);
1829 tv->evStart = NULL;
1830 pthread_mutex_destroy (&tv->p_clock);
1831 replace_spin_keys (&tv->spin_keys, new_spin_keys);
1832 push_pthread_mem (tv);
1833 }
1834 }
1835 pthread_mutex_unlock (&mtx_pthr_locked);
1836
1837 return r;
1838}
1839
1840static int dummy_concurrency_level = 0;
1841
1842int
1843pthread_getconcurrency (void)
1844{
1845 return dummy_concurrency_level;
1846}
1847
1848int
1849pthread_setconcurrency (int new_level)
1850{
1851 dummy_concurrency_level = new_level;
1852 return 0;
1853}
1854
1855int
1856pthread_setname_np (pthread_t thread, const char *name)
1857{
1858 struct _pthread_v *tv;
1859 char *stored_name;
1860
1861 if (name == NULL)
1862 return EINVAL;
1863
1864 tv = __pth_gpointer_locked (thread);
1865 if (!tv || thread != tv->x || tv->in_cancel || tv->ended || tv->h == NULL
1866 || tv->h == INVALID_HANDLE_VALUE)
1867 return ESRCH;
1868
1869 stored_name = strdup (name);
1870 if (stored_name == NULL)
1871 return ENOMEM;
1872
1873 if (tv->thread_name != NULL)
1874 free (tv->thread_name);
1875
1876 tv->thread_name = stored_name;
1877 SetThreadName (tv->tid, name);
1878
1879 if (_pthread_set_thread_description != NULL)
1880 {
1881 mbstate_t mbs = {0};
1882 size_t required_size = mbsrtowcs(NULL, &name, 0, &mbs);
1883 if (required_size != (size_t)-1)
1884 {
1885 wchar_t *wname = malloc((required_size + 1) * sizeof(wchar_t));
1886 if (wname != NULL)
1887 {
1888 mbsrtowcs(wname, &name, required_size + 1, &mbs);
1889 _pthread_set_thread_description(tv->h, wname);
1890 free(wname);
1891 }
1892 }
1893 }
1894 return 0;
1895}
1896
1897int
1898pthread_getname_np (pthread_t thread, char *name, size_t len)
1899{
1900 HRESULT result;
1901 struct _pthread_v *tv;
1902
1903 if (name == NULL)
1904 return EINVAL;
1905
1906 tv = __pth_gpointer_locked (thread);
1907 if (!tv || thread != tv->x || tv->in_cancel || tv->ended || tv->h == NULL
1908 || tv->h == INVALID_HANDLE_VALUE)
1909 return ESRCH;
1910
1911 if (len < 1)
1912 return ERANGE;
1913
1914 if (tv->thread_name == NULL)
1915 {
1916 name[0] = '\0';
1917 return 0;
1918 }
1919
1920 if (strlen (tv->thread_name) >= len)
1921 return ERANGE;
1922
1923 result = StringCchCopyNA (name, len, tv->thread_name, len - 1);
1924 if (SUCCEEDED (result))
1925 return 0;
1926
1927 return ERANGE;
1928}