(root)/
gcc-13.2.0/
libgcc/
config/
i386/
gthr-win32.h
       1  /* Threads compatibility routines for libgcc2 and libobjc.  */
       2  /* Compile this one with gcc.  */
       3  
       4  /* Copyright (C) 1999-2023 Free Software Foundation, Inc.
       5     Contributed by Mumit Khan <khan@xraylith.wisc.edu>.
       6  
       7  This file is part of GCC.
       8  
       9  GCC is free software; you can redistribute it and/or modify it under
      10  the terms of the GNU General Public License as published by the Free
      11  Software Foundation; either version 3, or (at your option) any later
      12  version.
      13  
      14  GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      15  WARRANTY; without even the implied warranty of MERCHANTABILITY or
      16  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      17  for more details.
      18  
      19  Under Section 7 of GPL version 3, you are granted additional
      20  permissions described in the GCC Runtime Library Exception, version
      21  3.1, as published by the Free Software Foundation.
      22  
      23  You should have received a copy of the GNU General Public License and
      24  a copy of the GCC Runtime Library Exception along with this program;
      25  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
      26  <http://www.gnu.org/licenses/>.  */
      27  
      28  #ifndef GCC_GTHR_WIN32_H
      29  #define GCC_GTHR_WIN32_H
      30  
      31  /* So we can test Windows version numbers.  */
      32  #include <stdlib.h>
      33  
      34  /* The Windows threading model does not map well into the POSIX inspired
      35     GCC threading model, so there are caveats one needs to be aware of.
      36  
      37     1. The destructor supplied to __gthread_key_create is ignored for
      38        generic Windows ports.  This will certainly cause memory leaks
      39        due to unreclaimed EH contexts (sizeof (eh_context) is at least
      40        24 bytes for x86 currently).
      41  
      42        This memory leak may be significant for long-running applications
      43        that make heavy use of C++ EH.
      44  
      45        However, Mingw runtime (version 0.3 or newer) provides a mechanism
      46        to emulate pthreads key dtors; the runtime provides a special DLL,
      47        linked in if -mthreads option is specified, that runs the dtors in
      48        the reverse order of registration when each thread exits. If
      49        -mthreads option is not given, a stub is linked in instead of the
      50        DLL, which results in memory leak.  Other Windows ports can use
      51        the same technique of course to avoid the leak.
      52  
      53     2. The error codes returned are non-POSIX like, and cast into ints.
      54        This may cause incorrect error return due to truncation values on
      55        hw where sizeof (DWORD) > sizeof (int).
      56  
      57     3. POSIX-like condition variables are supported, but only on Vista and
      58        Server 2008 or later versions.
      59  
      60     4. Timed lock primitives are not supported.  */
      61  
      62  #define __GTHREADS 1
      63  
      64  /* Condition variables are supported on Vista and Server 2008 or later.  */
      65  #if _WIN32_WINNT >= 0x0600
      66  #define __GTHREAD_HAS_COND 1
      67  #define __GTHREADS_CXX0X 1
      68  #endif
      69  
      70  #if _GTHREAD_USE_MUTEX_TIMEDLOCK
      71  #error Timed lock primitives are not supported on Windows targets
      72  #endif
      73  
      74  /* Make sure CONST_CAST2 (origin in system.h) is declared.  */
      75  #ifndef CONST_CAST2
      76  #ifdef __cplusplus
      77  #define CONST_CAST2(TOTYPE,FROMTYPE,X) (const_cast<TOTYPE> (X))
      78  #else
      79  #define CONST_CAST2(TOTYPE,FROMTYPE,X) ((__extension__(union {FROMTYPE _q; TOTYPE _nq;})(X))._nq)
      80  #endif
      81  #endif
      82  
      83  #ifndef ATTRIBUTE_UNUSED
      84  #define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
      85  #endif
      86  
      87  #ifdef _LIBOBJC
      88  
      89  /* This is necessary to prevent windef.h (included from windows.h) from
      90     defining its own BOOL as a typedef.  */
      91  #ifndef __OBJC__
      92  #define __OBJC__
      93  #endif
      94  #define WIN32_LEAN_AND_MEAN
      95  #include <windows.h>
      96  /* Now undef the windows BOOL and CC_NONE */
      97  #undef BOOL
      98  #undef CC_NONE
      99  
     100  /* Key structure for maintaining thread specific storage */
     101  static DWORD __gthread_objc_data_tls = TLS_OUT_OF_INDEXES;
     102  
     103  /* Backend initialization functions */
     104  
     105  /* Initialize the threads subsystem.  */
     106  int
     107  __gthread_objc_init_thread_system (void)
     108  {
     109    /* Initialize the thread storage key.  */
     110    if ((__gthread_objc_data_tls = TlsAlloc ()) != TLS_OUT_OF_INDEXES)
     111      return 0;
     112    else
     113      return -1;
     114  }
     115  
     116  /* Close the threads subsystem.  */
     117  int
     118  __gthread_objc_close_thread_system (void)
     119  {
     120    if (__gthread_objc_data_tls != TLS_OUT_OF_INDEXES)
     121      TlsFree (__gthread_objc_data_tls);
     122    return 0;
     123  }
     124  
     125  /* Backend thread functions */
     126  
     127  /* Create a new thread of execution.  */
     128  objc_thread_t
     129  __gthread_objc_thread_detach (void (*func)(void *arg), void *arg)
     130  {
     131    DWORD	thread_id = 0;
     132    HANDLE win32_handle;
     133  
     134    if (!(win32_handle = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) func,
     135  				     arg, 0, &thread_id)))
     136      thread_id = 0;
     137  
     138    return (objc_thread_t) (INT_PTR) thread_id;
     139  }
     140  
     141  /* Set the current thread's priority.  */
     142  int
     143  __gthread_objc_thread_set_priority (int priority)
     144  {
     145    int sys_priority = 0;
     146  
     147    switch (priority)
     148      {
     149      case OBJC_THREAD_INTERACTIVE_PRIORITY:
     150        sys_priority = THREAD_PRIORITY_NORMAL;
     151        break;
     152      default:
     153      case OBJC_THREAD_BACKGROUND_PRIORITY:
     154        sys_priority = THREAD_PRIORITY_BELOW_NORMAL;
     155        break;
     156      case OBJC_THREAD_LOW_PRIORITY:
     157        sys_priority = THREAD_PRIORITY_LOWEST;
     158        break;
     159      }
     160  
     161    /* Change priority */
     162    if (SetThreadPriority (GetCurrentThread (), sys_priority))
     163      return 0;
     164    else
     165      return -1;
     166  }
     167  
     168  /* Return the current thread's priority.  */
     169  int
     170  __gthread_objc_thread_get_priority (void)
     171  {
     172    int sys_priority;
     173  
     174    sys_priority = GetThreadPriority (GetCurrentThread ());
     175  
     176    switch (sys_priority)
     177      {
     178      case THREAD_PRIORITY_HIGHEST:
     179      case THREAD_PRIORITY_TIME_CRITICAL:
     180      case THREAD_PRIORITY_ABOVE_NORMAL:
     181      case THREAD_PRIORITY_NORMAL:
     182        return OBJC_THREAD_INTERACTIVE_PRIORITY;
     183  
     184      default:
     185      case THREAD_PRIORITY_BELOW_NORMAL:
     186        return OBJC_THREAD_BACKGROUND_PRIORITY;
     187  
     188      case THREAD_PRIORITY_IDLE:
     189      case THREAD_PRIORITY_LOWEST:
     190        return OBJC_THREAD_LOW_PRIORITY;
     191      }
     192  
     193    /* Couldn't get priority.  */
     194    return -1;
     195  }
     196  
     197  /* Yield our process time to another thread.  */
     198  void
     199  __gthread_objc_thread_yield (void)
     200  {
     201    Sleep (0);
     202  }
     203  
     204  /* Terminate the current thread.  */
     205  int
     206  __gthread_objc_thread_exit (void)
     207  {
     208    /* exit the thread */
     209    ExitThread (__objc_thread_exit_status);
     210  
     211    /* Failed if we reached here */
     212    return -1;
     213  }
     214  
     215  /* Returns an integer value which uniquely describes a thread.  */
     216  objc_thread_t
     217  __gthread_objc_thread_id (void)
     218  {
     219    return (objc_thread_t) (INT_PTR) GetCurrentThreadId ();
     220  }
     221  
     222  /* Sets the thread's local storage pointer.  */
     223  int
     224  __gthread_objc_thread_set_data (void *value)
     225  {
     226    if (TlsSetValue (__gthread_objc_data_tls, value))
     227      return 0;
     228    else
     229      return -1;
     230  }
     231  
     232  /* Returns the thread's local storage pointer.  */
     233  void *
     234  __gthread_objc_thread_get_data (void)
     235  {
     236    DWORD lasterror = GetLastError ();
     237    void * ptr = TlsGetValue (__gthread_objc_data_tls);
     238    SetLastError (lasterror);
     239    return ptr;
     240  }
     241  
     242  /* Backend mutex functions */
     243  
     244  /* Allocate a mutex.  */
     245  int
     246  __gthread_objc_mutex_allocate (objc_mutex_t mutex)
     247  {
     248    if ((mutex->backend = (void *) CreateMutex (NULL, 0, NULL)) == NULL)
     249      return -1;
     250    else
     251      return 0;
     252  }
     253  
     254  /* Deallocate a mutex.  */
     255  int
     256  __gthread_objc_mutex_deallocate (objc_mutex_t mutex)
     257  {
     258    CloseHandle ((HANDLE) (mutex->backend));
     259    return 0;
     260  }
     261  
     262  /* Grab a lock on a mutex.  */
     263  int
     264  __gthread_objc_mutex_lock (objc_mutex_t mutex)
     265  {
     266    int status;
     267  
     268    status = WaitForSingleObject ((HANDLE) (mutex->backend), INFINITE);
     269    if (status != WAIT_OBJECT_0 && status != WAIT_ABANDONED)
     270      return -1;
     271    else
     272      return 0;
     273  }
     274  
     275  /* Try to grab a lock on a mutex.  */
     276  int
     277  __gthread_objc_mutex_trylock (objc_mutex_t mutex)
     278  {
     279    int status;
     280  
     281    status = WaitForSingleObject ((HANDLE) (mutex->backend), 0);
     282    if (status != WAIT_OBJECT_0 && status != WAIT_ABANDONED)
     283      return -1;
     284    else
     285      return 0;
     286  }
     287  
     288  /* Unlock the mutex */
     289  int
     290  __gthread_objc_mutex_unlock (objc_mutex_t mutex)
     291  {
     292    if (ReleaseMutex ((HANDLE) (mutex->backend)) == 0)
     293      return -1;
     294    else
     295      return 0;
     296  }
     297  
     298  /* Backend condition mutex functions */
     299  
     300  /* Allocate a condition.  */
     301  int
     302  __gthread_objc_condition_allocate (objc_condition_t condition ATTRIBUTE_UNUSED)
     303  {
     304    /* Unimplemented.  */
     305    return -1;
     306  }
     307  
     308  /* Deallocate a condition.  */
     309  int
     310  __gthread_objc_condition_deallocate (objc_condition_t condition ATTRIBUTE_UNUSED)
     311  {
     312    /* Unimplemented.  */
     313    return -1;
     314  }
     315  
     316  /* Wait on the condition */
     317  int
     318  __gthread_objc_condition_wait (objc_condition_t condition ATTRIBUTE_UNUSED,
     319  			       objc_mutex_t mutex ATTRIBUTE_UNUSED)
     320  {
     321    /* Unimplemented.  */
     322    return -1;
     323  }
     324  
     325  /* Wake up all threads waiting on this condition.  */
     326  int
     327  __gthread_objc_condition_broadcast (objc_condition_t condition ATTRIBUTE_UNUSED)
     328  {
     329    /* Unimplemented.  */
     330    return -1;
     331  }
     332  
     333  /* Wake up one thread waiting on this condition.  */
     334  int
     335  __gthread_objc_condition_signal (objc_condition_t condition ATTRIBUTE_UNUSED)
     336  {
     337    /* Unimplemented.  */
     338    return -1;
     339  }
     340  
     341  #else /* _LIBOBJC */
     342  
     343  /* For struct timespec.  Do not include <sys/time.h> here since Gnulib provides
     344     its own version which drags the Win32 API definitions.  */
     345  #include <sys/timeb.h>
     346  
     347  #ifdef __cplusplus
     348  extern "C" {
     349  #endif
     350  
     351  typedef unsigned int __gthr_win32_DWORD;
     352  typedef void *__gthr_win32_HANDLE;
     353  
     354  typedef struct {
     355    void *DebugInfo;
     356    int LockCount;
     357    int RecursionCount;
     358    __gthr_win32_HANDLE OwningThread;
     359    __gthr_win32_HANDLE LockSemaphore;
     360    void *SpinCount;
     361  } __gthr_win32_CRITICAL_SECTION;
     362  
     363  typedef struct {
     364    void *Ptr;
     365  } __gthr_win32_CONDITION_VARIABLE;
     366  
     367  typedef __gthr_win32_HANDLE __gthread_t;
     368  typedef __gthr_win32_DWORD __gthread_key_t;
     369  typedef struct { int done; long started; } __gthread_once_t;
     370  typedef __gthr_win32_CRITICAL_SECTION __gthread_mutex_t;
     371  typedef __gthr_win32_CRITICAL_SECTION __gthread_recursive_mutex_t;
     372  #if __GTHREAD_HAS_COND
     373  typedef __gthr_win32_CONDITION_VARIABLE __gthread_cond_t;
     374  #endif
     375  typedef struct timespec __gthread_time_t;
     376  
     377  #define __GTHREAD_ONCE_INIT {0, -1}
     378  #define __GTHREAD_MUTEX_INIT_FUNCTION __gthread_mutex_init_function
     379  #define __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION \
     380    __gthread_recursive_mutex_init_function
     381  #define __GTHREAD_COND_INIT_FUNCTION __gthread_cond_init_function
     382  #define __GTHREAD_TIME_INIT {0, 0}
     383  
     384  // Libstdc++ std::basic_filebuf needs the old definition of __gthread_mutex_t
     385  // for layout purposes, but doesn't actually use it.
     386  typedef struct {
     387    long __unused1;
     388    void *__unused2;
     389  } __gthr_win32_legacy_mutex_t;
     390  #define __GTHREAD_LEGACY_MUTEX_T __gthr_win32_legacy_mutex_t
     391  
     392  #if defined (_WIN32) && !defined(__CYGWIN__)
     393  #define MINGW32_SUPPORTS_MT_EH 1
     394  /* Mingw runtime >= v0.3 provides a magic variable that is set to nonzero
     395     if -mthreads option was specified, or 0 otherwise. This is to get around
     396     the lack of weak symbols in PE-COFF.  */
     397  extern int _CRT_MT;
     398  extern int __mingwthr_key_dtor (unsigned long, void (*) (void *));
     399  #endif /* _WIN32 && !__CYGWIN__ */
     400  
     401  /* __GTHR_W32_InterlockedCompareExchange is left over from win95,
     402     which did not support InterlockedCompareExchange. */
     403  #define __GTHR_W32_InterlockedCompareExchange InterlockedCompareExchange
     404  
     405  static inline int
     406  __gthread_active_p (void)
     407  {
     408  #ifdef MINGW32_SUPPORTS_MT_EH
     409    return _CRT_MT;
     410  #else
     411    return 1;
     412  #endif
     413  }
     414  
     415  extern int __gthr_win32_create (__gthread_t *, void *(*) (void*), void *);
     416  extern int __gthr_win32_join (__gthread_t, void **);
     417  extern __gthread_t __gthr_win32_self (void);
     418  extern int __gthr_win32_once (__gthread_once_t *, void (*) (void));
     419  extern int __gthr_win32_detach (__gthread_t);
     420  extern int __gthr_win32_equal (__gthread_t, __gthread_t);
     421  extern int __gthr_win32_yield (void);
     422  extern int __gthr_win32_key_create (__gthread_key_t *, void (*) (void*));
     423  extern int __gthr_win32_key_delete (__gthread_key_t);
     424  extern void * __gthr_win32_getspecific (__gthread_key_t);
     425  extern int __gthr_win32_setspecific (__gthread_key_t, const void *);
     426  extern void __gthr_win32_mutex_init_function (__gthread_mutex_t *);
     427  extern void __gthr_win32_mutex_destroy (__gthread_mutex_t *);
     428  extern int __gthr_win32_mutex_lock (__gthread_mutex_t *);
     429  extern int __gthr_win32_mutex_trylock (__gthread_mutex_t *);
     430  extern int __gthr_win32_mutex_unlock (__gthread_mutex_t *);
     431  extern int __gthr_win32_recursive_mutex_trylock (__gthread_recursive_mutex_t *);
     432  #if __GTHREAD_HAS_COND
     433  extern void __gthr_win32_cond_init_function (__gthread_cond_t *);
     434  extern int __gthr_win32_cond_broadcast (__gthread_cond_t *);
     435  extern int __gthr_win32_cond_signal (__gthread_cond_t *);
     436  extern int __gthr_win32_cond_wait (__gthread_cond_t *, __gthread_mutex_t *);
     437  extern int __gthr_win32_cond_timedwait (__gthread_cond_t *, __gthread_mutex_t *,
     438  					const __gthread_time_t *);
     439  #endif
     440  
     441  static inline int
     442  __gthread_create (__gthread_t *__thr, void *(*__func) (void*),
     443  		  void *__args)
     444  {
     445    return __gthr_win32_create (__thr, __func, __args);
     446  }
     447  
     448  static inline int
     449  __gthread_join (__gthread_t __thr, void **__value_ptr)
     450  {
     451    return __gthr_win32_join (__thr, __value_ptr);
     452  }
     453  
     454  static inline __gthread_t
     455  __gthread_self (void)
     456  {
     457    return __gthr_win32_self ();
     458  }
     459  
     460  #if __GTHREAD_HIDE_WIN32API
     461  
     462  /* The implementations are in config/i386/gthr-win32.c in libgcc.a.
     463     Only stubs are exposed to avoid polluting the C++ namespace with
     464     Win32 API definitions.  */
     465  
     466  static inline int
     467  __gthread_detach (__gthread_t __thr)
     468  {
     469    return __gthr_win32_detach (__thr);
     470  }
     471  
     472  static inline int
     473  __gthread_equal (__gthread_t __thr1, __gthread_t __thr2)
     474  {
     475    return __gthr_win32_equal (__thr1, __thr2);
     476  }
     477  
     478  static inline int
     479  __gthread_yield (void)
     480  {
     481    return __gthr_win32_yield ();
     482  }
     483  
     484  static inline int
     485  __gthread_once (__gthread_once_t *__once, void (*__func) (void))
     486  {
     487    if (__gthread_active_p ())
     488      return __gthr_win32_once (__once, __func);
     489    else
     490      return -1;
     491  }
     492  
     493  static inline int
     494  __gthread_key_create (__gthread_key_t *__key, void (*__dtor) (void *))
     495  {
     496    return __gthr_win32_key_create (__key, __dtor);
     497  }
     498  
     499  static inline int
     500  __gthread_key_delete (__gthread_key_t __key)
     501  {
     502    return __gthr_win32_key_delete (__key);
     503  }
     504  
     505  static inline void *
     506  __gthread_getspecific (__gthread_key_t __key)
     507  {
     508    return __gthr_win32_getspecific (__key);
     509  }
     510  
     511  static inline int
     512  __gthread_setspecific (__gthread_key_t __key, const void *__ptr)
     513  {
     514    return __gthr_win32_setspecific (__key, __ptr);
     515  }
     516  
     517  static inline void
     518  __gthread_mutex_init_function (__gthread_mutex_t *__mutex)
     519  {
     520    __gthr_win32_mutex_init_function (__mutex);
     521  }
     522  
     523  static inline void
     524  __gthread_mutex_destroy (__gthread_mutex_t *__mutex)
     525  {
     526    __gthr_win32_mutex_destroy (__mutex);
     527  }
     528  
     529  static inline int
     530  __gthread_mutex_lock (__gthread_mutex_t *__mutex)
     531  {
     532    if (__gthread_active_p ())
     533      return __gthr_win32_mutex_lock (__mutex);
     534    else
     535      return 0;
     536  }
     537  
     538  static inline int
     539  __gthread_mutex_trylock (__gthread_mutex_t *__mutex)
     540  {
     541    if (__gthread_active_p ())
     542      return __gthr_win32_mutex_trylock (__mutex);
     543    else
     544      return 0;
     545  }
     546  
     547  static inline int
     548  __gthread_mutex_unlock (__gthread_mutex_t *__mutex)
     549  {
     550    if (__gthread_active_p ())
     551      return __gthr_win32_mutex_unlock (__mutex);
     552    else
     553      return 0;
     554  }
     555  
     556  static inline int
     557  __gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *__mutex)
     558  {
     559    if (__gthread_active_p ())
     560      return __gthr_win32_recursive_mutex_trylock (__mutex);
     561    else
     562      return 0;
     563  }
     564  
     565  #if __GTHREAD_HAS_COND
     566  
     567  static inline void
     568  __gthread_cond_init_function (__gthread_cond_t *__cond)
     569  {
     570    __gthr_win32_cond_init_function (__cond);
     571  }
     572  
     573  static inline int
     574  __gthread_cond_broadcast (__gthread_cond_t *__cond)
     575  {
     576    return __gthr_win32_cond_broadcast (__cond);
     577  }
     578  
     579  static inline int
     580  __gthread_cond_signal (__gthread_cond_t *__cond)
     581  {
     582    return __gthr_win32_cond_signal (__cond);
     583  }
     584  
     585  static inline int
     586  __gthread_cond_wait (__gthread_cond_t *__cond, __gthread_mutex_t *__mutex)
     587  {
     588    return __gthr_win32_cond_wait (__cond, __mutex);
     589  }
     590  
     591  static inline int
     592  __gthread_cond_timedwait (__gthread_cond_t *__cond, __gthread_mutex_t *__mutex,
     593  			  const __gthread_time_t *__abs_time)
     594  {
     595    return __gthr_win32_cond_timedwait (__cond, __mutex, __abs_time);
     596  }
     597  
     598  #endif /* __GTHREAD_HAS_COND */
     599  
     600  #else /* ! __GTHREAD_HIDE_WIN32API */
     601  
     602  #ifndef __GTHREAD_WIN32_INLINE
     603  #define __GTHREAD_WIN32_INLINE static inline
     604  #endif
     605  
     606  #ifndef __GTHREAD_WIN32_COND_INLINE
     607  #define __GTHREAD_WIN32_COND_INLINE static inline
     608  #endif
     609  
     610  #ifndef __GTHREAD_WIN32_ACTIVE_P
     611  #define __GTHREAD_WIN32_ACTIVE_P __gthread_active_p
     612  #endif
     613  
     614  #define WIN32_LEAN_AND_MEAN
     615  #include <windows.h>
     616  #undef CC_NONE
     617  
     618  __GTHREAD_WIN32_INLINE int
     619  __gthread_detach (__gthread_t __thr)
     620  {
     621    CloseHandle ((HANDLE) __thr);
     622    return 0;
     623  }
     624  
     625  __GTHREAD_WIN32_INLINE int
     626  __gthread_equal (__gthread_t __t1, __gthread_t __t2)
     627  {
     628    return GetThreadId ((HANDLE) __t1) == GetThreadId ((HANDLE) __t2);
     629  }
     630  
     631  __GTHREAD_WIN32_INLINE int
     632  __gthread_yield (void)
     633  {
     634    Sleep (0);
     635    return 0;
     636  }
     637  
     638  __GTHREAD_WIN32_INLINE int
     639  __gthread_once (__gthread_once_t *__once, void (*__func) (void))
     640  {
     641    if (!__GTHREAD_WIN32_ACTIVE_P ())
     642      return -1;
     643  
     644    if (__builtin_expect (!__once->done, 0))
     645      {
     646        /* We rely on the memory model of the x86 architecture where every load
     647  	 has acquire semantics and every store has release semantics.  */
     648        if (__atomic_add_fetch (&__once->started, 1, __ATOMIC_ACQ_REL) == 0)
     649  	{
     650  	  (*__func) ();
     651  	  __once->done = 1;
     652  	}
     653        else
     654  	{
     655  	  /* Another thread is currently executing the code, so wait for it
     656  	     to finish and yield the CPU in the meantime.  If performance
     657  	     does become an issue, the solution is to use an Event that
     658  	     we wait on here (and set above), but that implies a place to
     659  	     create the event before this routine is called.  */
     660  	  while (!__once->done)
     661  	    __gthread_yield ();
     662  	}
     663      }
     664  
     665    return 0;
     666  }
     667  
     668  /* Windows thread local keys don't support destructors; this leads to
     669     leaks, especially in threaded applications making extensive use of
     670     C++ EH. Mingw uses a thread-support DLL to work-around this problem.  */
     671  __GTHREAD_WIN32_INLINE int
     672  __gthread_key_create (__gthread_key_t *__key,
     673  		      void (*__dtor) (void *) ATTRIBUTE_UNUSED)
     674  {
     675    DWORD __tls_index = TlsAlloc ();
     676    if (__tls_index != TLS_OUT_OF_INDEXES)
     677      {
     678        *__key = __tls_index;
     679  #ifdef MINGW32_SUPPORTS_MT_EH
     680        /* Mingw runtime will run the dtors in reverse order for each thread
     681           when the thread exits.  */
     682        return __mingwthr_key_dtor (*__key, __dtor);
     683  #else
     684        return 0;
     685  #endif
     686      }
     687    else
     688      return (int) GetLastError ();
     689  }
     690  
     691  __GTHREAD_WIN32_INLINE int
     692  __gthread_key_delete (__gthread_key_t __key)
     693  {
     694    if (TlsFree (__key))
     695      return 0;
     696    else
     697      return (int) GetLastError ();
     698  }
     699  
     700  __GTHREAD_WIN32_INLINE void *
     701  __gthread_getspecific (__gthread_key_t __key)
     702  {
     703    DWORD __lasterror = GetLastError ();
     704    void *__ptr = TlsGetValue (__key);
     705    SetLastError (__lasterror);
     706    return __ptr;
     707  }
     708  
     709  __GTHREAD_WIN32_INLINE int
     710  __gthread_setspecific (__gthread_key_t __key, const void *__ptr)
     711  {
     712    if (TlsSetValue (__key, CONST_CAST2(void *, const void *, __ptr)))
     713      return 0;
     714    else
     715      return (int) GetLastError ();
     716  }
     717  
     718  __GTHREAD_WIN32_INLINE void
     719  __gthread_mutex_init_function (__gthread_mutex_t *__mutex)
     720  {
     721    InitializeCriticalSection ((LPCRITICAL_SECTION) __mutex);
     722  }
     723  
     724  __GTHREAD_WIN32_INLINE void
     725  __gthread_mutex_destroy (__gthread_mutex_t *__mutex)
     726  {
     727    DeleteCriticalSection ((LPCRITICAL_SECTION) __mutex);
     728  }
     729  
     730  __GTHREAD_WIN32_INLINE int
     731  __gthread_mutex_lock (__gthread_mutex_t *__mutex)
     732  {
     733    if (__GTHREAD_WIN32_ACTIVE_P ())
     734      EnterCriticalSection ((LPCRITICAL_SECTION) __mutex);
     735    return 0;
     736  }
     737  
     738  __GTHREAD_WIN32_INLINE int
     739  __gthread_mutex_trylock (__gthread_mutex_t *__mutex)
     740  {
     741    if (__GTHREAD_WIN32_ACTIVE_P ())
     742      {
     743        BOOL __ret = TryEnterCriticalSection ((LPCRITICAL_SECTION) __mutex);
     744        if (__ret)
     745  	{
     746  	  if (__mutex->RecursionCount > 1)
     747  	    {
     748  	      LeaveCriticalSection ((LPCRITICAL_SECTION) __mutex);
     749  	      return 1;
     750  	    }
     751  	  else
     752  	    return 0;
     753  	}
     754        else
     755  	return 1;
     756      }
     757    else
     758      return 0;
     759  }
     760  
     761  __GTHREAD_WIN32_INLINE int
     762  __gthread_mutex_unlock (__gthread_mutex_t *__mutex)
     763  {
     764    if (__GTHREAD_WIN32_ACTIVE_P ())
     765      LeaveCriticalSection ((LPCRITICAL_SECTION) __mutex);
     766    return 0;
     767  }
     768  
     769  __GTHREAD_WIN32_INLINE int
     770  __gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *__mutex)
     771  {
     772    if (__GTHREAD_WIN32_ACTIVE_P ())
     773      return TryEnterCriticalSection ((LPCRITICAL_SECTION) __mutex) ? 0 : 1;
     774    else
     775      return 0;
     776  }
     777  
     778  #if __GTHREAD_HAS_COND
     779  
     780  __GTHREAD_WIN32_COND_INLINE void
     781  __gthread_cond_init_function (__gthread_cond_t *__cond)
     782  {
     783    InitializeConditionVariable ((PCONDITION_VARIABLE) __cond);
     784  }
     785  
     786  __GTHREAD_WIN32_COND_INLINE int
     787  __gthread_cond_broadcast (__gthread_cond_t *__cond)
     788  {
     789    WakeAllConditionVariable ((PCONDITION_VARIABLE) __cond);
     790    return 0;
     791  }
     792  
     793  __GTHREAD_WIN32_COND_INLINE int
     794  __gthread_cond_signal (__gthread_cond_t *__cond)
     795  {
     796    WakeConditionVariable ((PCONDITION_VARIABLE) __cond);
     797    return 0;
     798  }
     799  
     800  __GTHREAD_WIN32_COND_INLINE int
     801  __gthread_cond_wait (__gthread_cond_t *__cond, __gthread_mutex_t *__mutex)
     802  {
     803    if (SleepConditionVariableCS ((PCONDITION_VARIABLE) __cond,
     804  				(PCRITICAL_SECTION) __mutex,
     805  				INFINITE))
     806      return 0;
     807    else
     808      return (int) GetLastError ();
     809  }
     810  
     811  extern DWORD __gthr_win32_abs_to_rel_time (const __gthread_time_t *);
     812  
     813  __GTHREAD_WIN32_COND_INLINE int
     814  __gthread_cond_timedwait (__gthread_cond_t *__cond,
     815  			  __gthread_mutex_t *__mutex,
     816  			  const __gthread_time_t *__abs_time)
     817  {
     818    DWORD __rel_time = __gthr_win32_abs_to_rel_time (__abs_time);
     819    if (SleepConditionVariableCS ((PCONDITION_VARIABLE) __cond,
     820  				(PCRITICAL_SECTION) __mutex,
     821  				__rel_time))
     822      return 0;
     823    else
     824      return (int) GetLastError ();
     825  }
     826  
     827  #endif /* __GTHREAD_HAS_COND */
     828  
     829  #endif /*  __GTHREAD_HIDE_WIN32API */
     830  
     831  static inline void
     832  __gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *__mutex)
     833  {
     834    __gthread_mutex_init_function (__mutex);
     835  }
     836  
     837  static inline void
     838  __gthread_recursive_mutex_destroy (__gthread_recursive_mutex_t *__mutex)
     839  {
     840    __gthread_mutex_destroy (__mutex);
     841  }
     842  
     843  static inline int
     844  __gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *__mutex)
     845  {
     846    return __gthread_mutex_lock (__mutex);
     847  }
     848  
     849  static inline int
     850  __gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *__mutex)
     851  {
     852    return __gthread_mutex_unlock (__mutex);
     853  }
     854  
     855  #if __GTHREAD_HAS_COND
     856  
     857  static inline int
     858  __gthread_cond_destroy (__gthread_cond_t *__cond ATTRIBUTE_UNUSED)
     859  {
     860    return 0;
     861  }
     862  
     863  static inline int
     864  __gthread_cond_wait_recursive (__gthread_cond_t *__cond,
     865  			       __gthread_recursive_mutex_t *__mutex)
     866  {
     867    return __gthread_cond_wait (__cond, __mutex);
     868  }
     869  
     870  #endif
     871  
     872  #ifdef __cplusplus
     873  }
     874  #endif
     875  
     876  #endif /* _LIBOBJC */
     877  
     878  #endif /* ! GCC_GTHR_WIN32_H */