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