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