• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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