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