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