OSDN Git Service

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