1 /* Threads compatibility routines for libgcc2 and libobjc.  */
2 /* Compile this one with gcc.  */
3 
4 /* Copyright (C) 1999-2013 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 /* 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
__gthread_objc_init_thread_system(void)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
__gthread_objc_close_thread_system(void)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
__gthread_objc_thread_detach(void (* func)(void * arg),void * arg)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
__gthread_objc_thread_set_priority(int priority)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
__gthread_objc_thread_get_priority(void)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
__gthread_objc_thread_yield(void)188 __gthread_objc_thread_yield (void)
189 {
190   Sleep (0);
191 }
192 
193 /* Terminate the current thread.  */
194 int
__gthread_objc_thread_exit(void)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
__gthread_objc_thread_id(void)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
__gthread_objc_thread_set_data(void * value)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 *
__gthread_objc_thread_get_data(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
__gthread_objc_mutex_allocate(objc_mutex_t mutex)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
__gthread_objc_mutex_deallocate(objc_mutex_t mutex)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
__gthread_objc_mutex_lock(objc_mutex_t mutex)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
__gthread_objc_mutex_trylock(objc_mutex_t mutex)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
__gthread_objc_mutex_unlock(objc_mutex_t mutex)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
__gthread_objc_condition_allocate(objc_condition_t __UNUSED_PARAM (condition))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
__gthread_objc_condition_deallocate(objc_condition_t __UNUSED_PARAM (condition))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
__gthread_objc_condition_wait(objc_condition_t __UNUSED_PARAM (condition),objc_mutex_t __UNUSED_PARAM (mutex))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
__gthread_objc_condition_broadcast(objc_condition_t __UNUSED_PARAM (condition))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
__gthread_objc_condition_signal(objc_condition_t __UNUSED_PARAM (condition))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 /* The Windows95 kernel does not export InterlockedCompareExchange.
378    This provides a substitute.   When building apps that reference
379    gthread_mutex_try_lock, the  __GTHREAD_I486_INLINE_LOCK_PRIMITIVES
380    macro  must be defined if Windows95 is a target.  Currently
381    gthread_mutex_try_lock is not referenced by libgcc or libstdc++.  */
382 #ifdef __GTHREAD_I486_INLINE_LOCK_PRIMITIVES
383 static inline long
__gthr_i486_lock_cmp_xchg(long * __dest,long __xchg,long __comperand)384 __gthr_i486_lock_cmp_xchg(long *__dest, long __xchg, long __comperand)
385 {
386   long result;
387   __asm__ __volatile__ ("\n\
388 	lock\n\
389 	cmpxchg{l} {%4, %1|%1, %4}\n"
390 	: "=a" (result), "=m" (*__dest)
391 	: "0" (__comperand), "m" (*__dest), "r" (__xchg)
392 	: "cc");
393   return result;
394 }
395 #define __GTHR_W32_InterlockedCompareExchange __gthr_i486_lock_cmp_xchg
396 #else  /* __GTHREAD_I486_INLINE_LOCK_PRIMITIVES */
397 #define __GTHR_W32_InterlockedCompareExchange InterlockedCompareExchange
398 #endif /* __GTHREAD_I486_INLINE_LOCK_PRIMITIVES */
399 
400 static inline int
__gthread_active_p(void)401 __gthread_active_p (void)
402 {
403 #ifdef MINGW32_SUPPORTS_MT_EH
404   return _CRT_MT;
405 #else
406   return 1;
407 #endif
408 }
409 
410 #if __GTHREAD_HIDE_WIN32API
411 
412 /* The implementations are in config/i386/gthr-win32.c in libgcc.a.
413    Only stubs are exposed to avoid polluting the C++ namespace with
414    windows api definitions.  */
415 
416 extern int __gthr_win32_once (__gthread_once_t *, void (*) (void));
417 extern int __gthr_win32_key_create (__gthread_key_t *, void (*) (void*));
418 extern int __gthr_win32_key_delete (__gthread_key_t);
419 extern void * __gthr_win32_getspecific (__gthread_key_t);
420 extern int __gthr_win32_setspecific (__gthread_key_t, const void *);
421 extern void __gthr_win32_mutex_init_function (__gthread_mutex_t *);
422 extern int __gthr_win32_mutex_lock (__gthread_mutex_t *);
423 extern int __gthr_win32_mutex_trylock (__gthread_mutex_t *);
424 extern int __gthr_win32_mutex_unlock (__gthread_mutex_t *);
425 extern void
426   __gthr_win32_recursive_mutex_init_function (__gthread_recursive_mutex_t *);
427 extern int __gthr_win32_recursive_mutex_lock (__gthread_recursive_mutex_t *);
428 extern int
429   __gthr_win32_recursive_mutex_trylock (__gthread_recursive_mutex_t *);
430 extern int __gthr_win32_recursive_mutex_unlock (__gthread_recursive_mutex_t *);
431 extern void __gthr_win32_mutex_destroy (__gthread_mutex_t *);
432 extern int
433   __gthr_win32_recursive_mutex_destroy (__gthread_recursive_mutex_t *);
434 
435 static inline int
__gthread_once(__gthread_once_t * __once,void (* __func)(void))436 __gthread_once (__gthread_once_t *__once, void (*__func) (void))
437 {
438   if (__gthread_active_p ())
439     return __gthr_win32_once (__once, __func);
440   else
441     return -1;
442 }
443 
444 static inline int
__gthread_key_create(__gthread_key_t * __key,void (* __dtor)(void *))445 __gthread_key_create (__gthread_key_t *__key, void (*__dtor) (void *))
446 {
447   return __gthr_win32_key_create (__key, __dtor);
448 }
449 
450 static inline int
__gthread_key_delete(__gthread_key_t __key)451 __gthread_key_delete (__gthread_key_t __key)
452 {
453   return __gthr_win32_key_delete (__key);
454 }
455 
456 static inline void *
__gthread_getspecific(__gthread_key_t __key)457 __gthread_getspecific (__gthread_key_t __key)
458 {
459   return __gthr_win32_getspecific (__key);
460 }
461 
462 static inline int
__gthread_setspecific(__gthread_key_t __key,const void * __ptr)463 __gthread_setspecific (__gthread_key_t __key, const void *__ptr)
464 {
465   return __gthr_win32_setspecific (__key, __ptr);
466 }
467 
468 static inline void
__gthread_mutex_init_function(__gthread_mutex_t * __mutex)469 __gthread_mutex_init_function (__gthread_mutex_t *__mutex)
470 {
471   __gthr_win32_mutex_init_function (__mutex);
472 }
473 
474 static inline void
__gthread_mutex_destroy(__gthread_mutex_t * __mutex)475 __gthread_mutex_destroy (__gthread_mutex_t *__mutex)
476 {
477   __gthr_win32_mutex_destroy (__mutex);
478 }
479 
480 static inline int
__gthread_mutex_lock(__gthread_mutex_t * __mutex)481 __gthread_mutex_lock (__gthread_mutex_t *__mutex)
482 {
483   if (__gthread_active_p ())
484     return __gthr_win32_mutex_lock (__mutex);
485   else
486     return 0;
487 }
488 
489 static inline int
__gthread_mutex_trylock(__gthread_mutex_t * __mutex)490 __gthread_mutex_trylock (__gthread_mutex_t *__mutex)
491 {
492   if (__gthread_active_p ())
493     return __gthr_win32_mutex_trylock (__mutex);
494   else
495     return 0;
496 }
497 
498 static inline int
__gthread_mutex_unlock(__gthread_mutex_t * __mutex)499 __gthread_mutex_unlock (__gthread_mutex_t *__mutex)
500 {
501   if (__gthread_active_p ())
502     return __gthr_win32_mutex_unlock (__mutex);
503   else
504     return 0;
505 }
506 
507 static inline void
__gthread_recursive_mutex_init_function(__gthread_recursive_mutex_t * __mutex)508 __gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *__mutex)
509 {
510    __gthr_win32_recursive_mutex_init_function (__mutex);
511 }
512 
513 static inline int
__gthread_recursive_mutex_lock(__gthread_recursive_mutex_t * __mutex)514 __gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *__mutex)
515 {
516   if (__gthread_active_p ())
517     return __gthr_win32_recursive_mutex_lock (__mutex);
518   else
519     return 0;
520 }
521 
522 static inline int
__gthread_recursive_mutex_trylock(__gthread_recursive_mutex_t * __mutex)523 __gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *__mutex)
524 {
525   if (__gthread_active_p ())
526     return __gthr_win32_recursive_mutex_trylock (__mutex);
527   else
528     return 0;
529 }
530 
531 static inline int
__gthread_recursive_mutex_unlock(__gthread_recursive_mutex_t * __mutex)532 __gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *__mutex)
533 {
534   if (__gthread_active_p ())
535     return __gthr_win32_recursive_mutex_unlock (__mutex);
536   else
537     return 0;
538 }
539 
540 static inline int
__gthread_recursive_mutex_destroy(__gthread_recursive_mutex_t * __mutex)541 __gthread_recursive_mutex_destroy (__gthread_recursive_mutex_t *__mutex)
542 {
543   return __gthr_win32_recursive_mutex_destroy (__mutex);
544 }
545 
546 #else /* ! __GTHREAD_HIDE_WIN32API */
547 
548 #include <windows.h>
549 #include <errno.h>
550 
551 static inline int
__gthread_once(__gthread_once_t * __once,void (* __func)(void))552 __gthread_once (__gthread_once_t *__once, void (*__func) (void))
553 {
554   if (! __gthread_active_p ())
555     return -1;
556   else if (__once == NULL || __func == NULL)
557     return EINVAL;
558 
559   if (! __once->done)
560     {
561       if (InterlockedIncrement (&(__once->started)) == 0)
562 	{
563 	  (*__func) ();
564 	  __once->done = TRUE;
565 	}
566       else
567 	{
568 	  /* Another thread is currently executing the code, so wait for it
569 	     to finish; yield the CPU in the meantime.  If performance
570 	     does become an issue, the solution is to use an Event that
571 	     we wait on here (and set above), but that implies a place to
572 	     create the event before this routine is called.  */
573 	  while (! __once->done)
574 	    Sleep (0);
575 	}
576     }
577 
578   return 0;
579 }
580 
581 /* Windows32 thread local keys don't support destructors; this leads to
582    leaks, especially in threaded applications making extensive use of
583    C++ EH. Mingw uses a thread-support DLL to work-around this problem.  */
584 static inline int
__gthread_key_create(__gthread_key_t * __key,void (* __dtor)(void *))585 __gthread_key_create (__gthread_key_t *__key,
586 		      void (*__dtor) (void *) __attribute__((unused)))
587 {
588   int __status = 0;
589   DWORD __tls_index = TlsAlloc ();
590   if (__tls_index != 0xFFFFFFFF)
591     {
592       *__key = __tls_index;
593 #ifdef MINGW32_SUPPORTS_MT_EH
594       /* Mingw runtime will run the dtors in reverse order for each thread
595          when the thread exits.  */
596       __status = __mingwthr_key_dtor (*__key, __dtor);
597 #endif
598     }
599   else
600     __status = (int) GetLastError ();
601   return __status;
602 }
603 
604 static inline int
__gthread_key_delete(__gthread_key_t __key)605 __gthread_key_delete (__gthread_key_t __key)
606 {
607   return (TlsFree (__key) != 0) ? 0 : (int) GetLastError ();
608 }
609 
610 static inline void *
__gthread_getspecific(__gthread_key_t __key)611 __gthread_getspecific (__gthread_key_t __key)
612 {
613   DWORD __lasterror;
614   void *__ptr;
615 
616   __lasterror = GetLastError ();
617 
618   __ptr = TlsGetValue (__key);
619 
620   SetLastError (__lasterror);
621 
622   return __ptr;
623 }
624 
625 static inline int
__gthread_setspecific(__gthread_key_t __key,const void * __ptr)626 __gthread_setspecific (__gthread_key_t __key, const void *__ptr)
627 {
628   if (TlsSetValue (__key, CONST_CAST2(void *, const void *, __ptr)) != 0)
629     return 0;
630   else
631     return GetLastError ();
632 }
633 
634 static inline void
__gthread_mutex_init_function(__gthread_mutex_t * __mutex)635 __gthread_mutex_init_function (__gthread_mutex_t *__mutex)
636 {
637   __mutex->counter = -1;
638   __mutex->sema = CreateSemaphore (NULL, 0, 65535, NULL);
639 }
640 
641 static inline void
__gthread_mutex_destroy(__gthread_mutex_t * __mutex)642 __gthread_mutex_destroy (__gthread_mutex_t *__mutex)
643 {
644   CloseHandle ((HANDLE) __mutex->sema);
645 }
646 
647 static inline int
__gthread_mutex_lock(__gthread_mutex_t * __mutex)648 __gthread_mutex_lock (__gthread_mutex_t *__mutex)
649 {
650   int __status = 0;
651 
652   if (__gthread_active_p ())
653     {
654       if (InterlockedIncrement (&__mutex->counter) == 0 ||
655 	  WaitForSingleObject (__mutex->sema, INFINITE) == WAIT_OBJECT_0)
656 	__status = 0;
657       else
658 	{
659 	  /* WaitForSingleObject returns WAIT_FAILED, and we can only do
660 	     some best-effort cleanup here.  */
661 	  InterlockedDecrement (&__mutex->counter);
662 	  __status = 1;
663 	}
664     }
665   return __status;
666 }
667 
668 static inline int
__gthread_mutex_trylock(__gthread_mutex_t * __mutex)669 __gthread_mutex_trylock (__gthread_mutex_t *__mutex)
670 {
671   int __status = 0;
672 
673   if (__gthread_active_p ())
674     {
675       if (__GTHR_W32_InterlockedCompareExchange (&__mutex->counter, 0, -1) < 0)
676 	__status = 0;
677       else
678 	__status = 1;
679     }
680   return __status;
681 }
682 
683 static inline int
__gthread_mutex_unlock(__gthread_mutex_t * __mutex)684 __gthread_mutex_unlock (__gthread_mutex_t *__mutex)
685 {
686   if (__gthread_active_p ())
687     {
688       if (InterlockedDecrement (&__mutex->counter) >= 0)
689 	return ReleaseSemaphore (__mutex->sema, 1, NULL) ? 0 : 1;
690     }
691   return 0;
692 }
693 
694 static inline void
__gthread_recursive_mutex_init_function(__gthread_recursive_mutex_t * __mutex)695 __gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *__mutex)
696 {
697   __mutex->counter = -1;
698   __mutex->depth = 0;
699   __mutex->owner = 0;
700   __mutex->sema = CreateSemaphore (NULL, 0, 65535, NULL);
701 }
702 
703 static inline int
__gthread_recursive_mutex_lock(__gthread_recursive_mutex_t * __mutex)704 __gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *__mutex)
705 {
706   if (__gthread_active_p ())
707     {
708       DWORD __me = GetCurrentThreadId();
709       if (InterlockedIncrement (&__mutex->counter) == 0)
710 	{
711 	  __mutex->depth = 1;
712 	  __mutex->owner = __me;
713 	}
714       else if (__mutex->owner == __me)
715 	{
716 	  InterlockedDecrement (&__mutex->counter);
717 	  ++(__mutex->depth);
718 	}
719       else if (WaitForSingleObject (__mutex->sema, INFINITE) == WAIT_OBJECT_0)
720 	{
721 	  __mutex->depth = 1;
722 	  __mutex->owner = __me;
723 	}
724       else
725 	{
726 	  /* WaitForSingleObject returns WAIT_FAILED, and we can only do
727 	     some best-effort cleanup here.  */
728 	  InterlockedDecrement (&__mutex->counter);
729 	  return 1;
730 	}
731     }
732   return 0;
733 }
734 
735 static inline int
__gthread_recursive_mutex_trylock(__gthread_recursive_mutex_t * __mutex)736 __gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *__mutex)
737 {
738   if (__gthread_active_p ())
739     {
740       DWORD __me = GetCurrentThreadId();
741       if (__GTHR_W32_InterlockedCompareExchange (&__mutex->counter, 0, -1) < 0)
742 	{
743 	  __mutex->depth = 1;
744 	  __mutex->owner = __me;
745 	}
746       else if (__mutex->owner == __me)
747 	++(__mutex->depth);
748       else
749 	return 1;
750     }
751   return 0;
752 }
753 
754 static inline int
__gthread_recursive_mutex_unlock(__gthread_recursive_mutex_t * __mutex)755 __gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *__mutex)
756 {
757   if (__gthread_active_p ())
758     {
759       --(__mutex->depth);
760       if (__mutex->depth == 0)
761 	{
762 	  __mutex->owner = 0;
763 
764 	  if (InterlockedDecrement (&__mutex->counter) >= 0)
765 	    return ReleaseSemaphore (__mutex->sema, 1, NULL) ? 0 : 1;
766 	}
767     }
768   return 0;
769 }
770 
771 static inline int
__gthread_recursive_mutex_destroy(__gthread_recursive_mutex_t * __mutex)772 __gthread_recursive_mutex_destroy (__gthread_recursive_mutex_t *__mutex)
773 {
774   CloseHandle ((HANDLE) __mutex->sema);
775   return 0;
776 }
777 
778 #endif /*  __GTHREAD_HIDE_WIN32API */
779 
780 #ifdef __cplusplus
781 }
782 #endif
783 
784 #endif /* _LIBOBJC */
785 
786 #endif /* ! GCC_GTHR_WIN32_H */
787