1 /* Threads compatibility routines for libgcc2 and libobjc.  */
2 /* Compile this one with gcc.  */
3 
4 /* Copyright (C) 1999-2018 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 #define NOGDI
549 #include <windows.h>
550 #include <errno.h>
551 
552 static inline int
__gthread_once(__gthread_once_t * __once,void (* __func)(void))553 __gthread_once (__gthread_once_t *__once, void (*__func) (void))
554 {
555   if (! __gthread_active_p ())
556     return -1;
557   else if (__once == NULL || __func == NULL)
558     return EINVAL;
559 
560   if (! __once->done)
561     {
562       if (InterlockedIncrement (&(__once->started)) == 0)
563 	{
564 	  (*__func) ();
565 	  __once->done = TRUE;
566 	}
567       else
568 	{
569 	  /* Another thread is currently executing the code, so wait for it
570 	     to finish; yield the CPU in the meantime.  If performance
571 	     does become an issue, the solution is to use an Event that
572 	     we wait on here (and set above), but that implies a place to
573 	     create the event before this routine is called.  */
574 	  while (! __once->done)
575 	    Sleep (0);
576 	}
577     }
578 
579   return 0;
580 }
581 
582 /* Windows32 thread local keys don't support destructors; this leads to
583    leaks, especially in threaded applications making extensive use of
584    C++ EH. Mingw uses a thread-support DLL to work-around this problem.  */
585 static inline int
__gthread_key_create(__gthread_key_t * __key,void (* __dtor)(void *))586 __gthread_key_create (__gthread_key_t *__key,
587 		      void (*__dtor) (void *) __attribute__((__unused__)))
588 {
589   int __status = 0;
590   DWORD __tls_index = TlsAlloc ();
591   if (__tls_index != 0xFFFFFFFF)
592     {
593       *__key = __tls_index;
594 #ifdef MINGW32_SUPPORTS_MT_EH
595       /* Mingw runtime will run the dtors in reverse order for each thread
596          when the thread exits.  */
597       __status = __mingwthr_key_dtor (*__key, __dtor);
598 #endif
599     }
600   else
601     __status = (int) GetLastError ();
602   return __status;
603 }
604 
605 static inline int
__gthread_key_delete(__gthread_key_t __key)606 __gthread_key_delete (__gthread_key_t __key)
607 {
608   return (TlsFree (__key) != 0) ? 0 : (int) GetLastError ();
609 }
610 
611 static inline void *
__gthread_getspecific(__gthread_key_t __key)612 __gthread_getspecific (__gthread_key_t __key)
613 {
614   DWORD __lasterror;
615   void *__ptr;
616 
617   __lasterror = GetLastError ();
618 
619   __ptr = TlsGetValue (__key);
620 
621   SetLastError (__lasterror);
622 
623   return __ptr;
624 }
625 
626 static inline int
__gthread_setspecific(__gthread_key_t __key,const void * __ptr)627 __gthread_setspecific (__gthread_key_t __key, const void *__ptr)
628 {
629   if (TlsSetValue (__key, CONST_CAST2(void *, const void *, __ptr)) != 0)
630     return 0;
631   else
632     return GetLastError ();
633 }
634 
635 static inline void
__gthread_mutex_init_function(__gthread_mutex_t * __mutex)636 __gthread_mutex_init_function (__gthread_mutex_t *__mutex)
637 {
638   __mutex->counter = -1;
639   __mutex->sema = CreateSemaphoreW (NULL, 0, 65535, NULL);
640 }
641 
642 static inline void
__gthread_mutex_destroy(__gthread_mutex_t * __mutex)643 __gthread_mutex_destroy (__gthread_mutex_t *__mutex)
644 {
645   CloseHandle ((HANDLE) __mutex->sema);
646 }
647 
648 static inline int
__gthread_mutex_lock(__gthread_mutex_t * __mutex)649 __gthread_mutex_lock (__gthread_mutex_t *__mutex)
650 {
651   int __status = 0;
652 
653   if (__gthread_active_p ())
654     {
655       if (InterlockedIncrement (&__mutex->counter) == 0 ||
656 	  WaitForSingleObject (__mutex->sema, INFINITE) == WAIT_OBJECT_0)
657 	__status = 0;
658       else
659 	{
660 	  /* WaitForSingleObject returns WAIT_FAILED, and we can only do
661 	     some best-effort cleanup here.  */
662 	  InterlockedDecrement (&__mutex->counter);
663 	  __status = 1;
664 	}
665     }
666   return __status;
667 }
668 
669 static inline int
__gthread_mutex_trylock(__gthread_mutex_t * __mutex)670 __gthread_mutex_trylock (__gthread_mutex_t *__mutex)
671 {
672   int __status = 0;
673 
674   if (__gthread_active_p ())
675     {
676       if (__GTHR_W32_InterlockedCompareExchange (&__mutex->counter, 0, -1) < 0)
677 	__status = 0;
678       else
679 	__status = 1;
680     }
681   return __status;
682 }
683 
684 static inline int
__gthread_mutex_unlock(__gthread_mutex_t * __mutex)685 __gthread_mutex_unlock (__gthread_mutex_t *__mutex)
686 {
687   if (__gthread_active_p ())
688     {
689       if (InterlockedDecrement (&__mutex->counter) >= 0)
690 	return ReleaseSemaphore (__mutex->sema, 1, NULL) ? 0 : 1;
691     }
692   return 0;
693 }
694 
695 static inline void
__gthread_recursive_mutex_init_function(__gthread_recursive_mutex_t * __mutex)696 __gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *__mutex)
697 {
698   __mutex->counter = -1;
699   __mutex->depth = 0;
700   __mutex->owner = 0;
701   __mutex->sema = CreateSemaphoreW (NULL, 0, 65535, NULL);
702 }
703 
704 static inline int
__gthread_recursive_mutex_lock(__gthread_recursive_mutex_t * __mutex)705 __gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *__mutex)
706 {
707   if (__gthread_active_p ())
708     {
709       DWORD __me = GetCurrentThreadId();
710       if (InterlockedIncrement (&__mutex->counter) == 0)
711 	{
712 	  __mutex->depth = 1;
713 	  __mutex->owner = __me;
714 	}
715       else if (__mutex->owner == __me)
716 	{
717 	  InterlockedDecrement (&__mutex->counter);
718 	  ++(__mutex->depth);
719 	}
720       else if (WaitForSingleObject (__mutex->sema, INFINITE) == WAIT_OBJECT_0)
721 	{
722 	  __mutex->depth = 1;
723 	  __mutex->owner = __me;
724 	}
725       else
726 	{
727 	  /* WaitForSingleObject returns WAIT_FAILED, and we can only do
728 	     some best-effort cleanup here.  */
729 	  InterlockedDecrement (&__mutex->counter);
730 	  return 1;
731 	}
732     }
733   return 0;
734 }
735 
736 static inline int
__gthread_recursive_mutex_trylock(__gthread_recursive_mutex_t * __mutex)737 __gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *__mutex)
738 {
739   if (__gthread_active_p ())
740     {
741       DWORD __me = GetCurrentThreadId();
742       if (__GTHR_W32_InterlockedCompareExchange (&__mutex->counter, 0, -1) < 0)
743 	{
744 	  __mutex->depth = 1;
745 	  __mutex->owner = __me;
746 	}
747       else if (__mutex->owner == __me)
748 	++(__mutex->depth);
749       else
750 	return 1;
751     }
752   return 0;
753 }
754 
755 static inline int
__gthread_recursive_mutex_unlock(__gthread_recursive_mutex_t * __mutex)756 __gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *__mutex)
757 {
758   if (__gthread_active_p ())
759     {
760       --(__mutex->depth);
761       if (__mutex->depth == 0)
762 	{
763 	  __mutex->owner = 0;
764 
765 	  if (InterlockedDecrement (&__mutex->counter) >= 0)
766 	    return ReleaseSemaphore (__mutex->sema, 1, NULL) ? 0 : 1;
767 	}
768     }
769   return 0;
770 }
771 
772 static inline int
__gthread_recursive_mutex_destroy(__gthread_recursive_mutex_t * __mutex)773 __gthread_recursive_mutex_destroy (__gthread_recursive_mutex_t *__mutex)
774 {
775   CloseHandle ((HANDLE) __mutex->sema);
776   return 0;
777 }
778 
779 #endif /*  __GTHREAD_HIDE_WIN32API */
780 
781 #ifdef __cplusplus
782 }
783 #endif
784 
785 #endif /* _LIBOBJC */
786 
787 #endif /* ! GCC_GTHR_WIN32_H */
788