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