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