]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/gthr-win32.h
re PR testsuite/27476 (ACATS: Ada testsuite Bourne shell compatibility problem on...
[thirdparty/gcc.git] / gcc / gthr-win32.h
CommitLineData
15794a95 1/* Threads compatibility routines for libgcc2 and libobjc. */
62dafdeb 2/* Compile this one with gcc. */
fe9565ed
KH
3
4/* Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005
5 Free Software Foundation, Inc.
62dafdeb
MK
6 Contributed by Mumit Khan <khan@xraylith.wisc.edu>.
7
1322177d 8This file is part of GCC.
62dafdeb 9
1322177d
LB
10GCC is free software; you can redistribute it and/or modify it under
11the terms of the GNU General Public License as published by the Free
12Software Foundation; either version 2, or (at your option) any later
13version.
62dafdeb 14
1322177d
LB
15GCC is distributed in the hope that it will be useful, but WITHOUT ANY
16WARRANTY; without even the implied warranty of MERCHANTABILITY or
17FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18for more details.
62dafdeb
MK
19
20You should have received a copy of the GNU General Public License
1322177d 21along with GCC; see the file COPYING. If not, write to the Free
366ccddb
KC
22Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
2302110-1301, USA. */
62dafdeb
MK
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
88657302
RH
32#ifndef GCC_GTHR_WIN32_H
33#define GCC_GTHR_WIN32_H
62dafdeb
MK
34
35/* Windows32 threads specific definitions. The windows32 threading model
589005ff 36 does not map well into pthread-inspired gcc's threading model, and so
62dafdeb
MK
37 there are caveats one needs to be aware of.
38
f22a97d2 39 1. The destructor supplied to __gthread_key_create is ignored for
589005ff
KH
40 generic x86-win32 ports. This will certainly cause memory leaks
41 due to unreclaimed eh contexts (sizeof (eh_context) is at least
f22a97d2 42 24 bytes for x86 currently).
62dafdeb
MK
43
44 This memory leak may be significant for long-running applications
45 that make heavy use of C++ EH.
46
f22a97d2
MK
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
589005ff 52 DLL, which results in memory leak. Other x86-win32 ports can use
f22a97d2
MK
53 the same technique of course to avoid the leak.
54
62dafdeb 55 2. The error codes returned are non-POSIX like, and cast into ints.
589005ff 56 This may cause incorrect error return due to truncation values on
62dafdeb 57 hw where sizeof (DWORD) > sizeof (int).
589005ff 58
80408cac
WY
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).
589005ff 62
f22a97d2
MK
63 The basic framework should work well enough. In the long term, GCC
64 needs to use Structured Exception Handling on Windows32. */
62dafdeb
MK
65
66#define __GTHREADS 1
67
5dab7f92
TP
68#include <errno.h>
69#ifdef __MINGW32__
70#include <_mingw.h>
71#endif
15794a95
L
72
73#ifdef _LIBOBJC
74
3b56934f 75/* This is necessary to prevent windef.h (included from windows.h) from
f3b569ca 76 defining its own BOOL as a typedef. */
3b56934f
CF
77#ifndef __OBJC__
78#define __OBJC__
79#endif
80#include <windows.h>
589005ff 81/* Now undef the windows BOOL. */
3b56934f
CF
82#undef BOOL
83
15794a95 84/* Key structure for maintaining thread specific storage */
fc98f5cb 85static DWORD __gthread_objc_data_tls = (DWORD) -1;
15794a95
L
86
87/* Backend initialization functions */
88
71287280 89/* Initialize the threads subsystem. */
15794a95 90int
fc98f5cb 91__gthread_objc_init_thread_system (void)
15794a95 92{
ea4b7848 93 /* Initialize the thread storage key. */
fc98f5cb 94 if ((__gthread_objc_data_tls = TlsAlloc ()) != (DWORD) -1)
15794a95
L
95 return 0;
96 else
97 return -1;
98}
99
71287280 100/* Close the threads subsystem. */
15794a95 101int
fc98f5cb 102__gthread_objc_close_thread_system (void)
15794a95 103{
fc98f5cb
KH
104 if (__gthread_objc_data_tls != (DWORD) -1)
105 TlsFree (__gthread_objc_data_tls);
15794a95
L
106 return 0;
107}
108
109/* Backend thread functions */
110
71287280 111/* Create a new thread of execution. */
15794a95 112objc_thread_t
fc98f5cb 113__gthread_objc_thread_detach (void (*func)(void *arg), void *arg)
15794a95
L
114{
115 DWORD thread_id = 0;
116 HANDLE win32_handle;
117
fc98f5cb
KH
118 if (!(win32_handle = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) func,
119 arg, 0, &thread_id)))
15794a95 120 thread_id = 0;
589005ff 121
fc98f5cb 122 return (objc_thread_t) thread_id;
15794a95
L
123}
124
71287280 125/* Set the current thread's priority. */
15794a95 126int
fc98f5cb 127__gthread_objc_thread_set_priority (int priority)
15794a95
L
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 */
fc98f5cb 146 if (SetThreadPriority (GetCurrentThread (), sys_priority))
15794a95
L
147 return 0;
148 else
149 return -1;
150}
151
71287280 152/* Return the current thread's priority. */
15794a95 153int
fc98f5cb 154__gthread_objc_thread_get_priority (void)
15794a95
L
155{
156 int sys_priority;
157
fc98f5cb 158 sys_priority = GetThreadPriority (GetCurrentThread ());
589005ff 159
15794a95
L
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;
589005ff 171
15794a95
L
172 case THREAD_PRIORITY_IDLE:
173 case THREAD_PRIORITY_LOWEST:
174 return OBJC_THREAD_LOW_PRIORITY;
175 }
176
71287280 177 /* Couldn't get priority. */
15794a95
L
178 return -1;
179}
180
71287280 181/* Yield our process time to another thread. */
15794a95 182void
fc98f5cb 183__gthread_objc_thread_yield (void)
15794a95 184{
fc98f5cb 185 Sleep (0);
15794a95
L
186}
187
71287280 188/* Terminate the current thread. */
15794a95 189int
fc98f5cb 190__gthread_objc_thread_exit (void)
15794a95
L
191{
192 /* exit the thread */
fc98f5cb 193 ExitThread (__objc_thread_exit_status);
15794a95
L
194
195 /* Failed if we reached here */
196 return -1;
197}
198
71287280 199/* Returns an integer value which uniquely describes a thread. */
15794a95 200objc_thread_t
fc98f5cb 201__gthread_objc_thread_id (void)
15794a95 202{
fc98f5cb 203 return (objc_thread_t) GetCurrentThreadId ();
15794a95
L
204}
205
71287280 206/* Sets the thread's local storage pointer. */
15794a95 207int
fc98f5cb 208__gthread_objc_thread_set_data (void *value)
15794a95 209{
fc98f5cb 210 if (TlsSetValue (__gthread_objc_data_tls, value))
15794a95
L
211 return 0;
212 else
213 return -1;
214}
215
71287280 216/* Returns the thread's local storage pointer. */
15794a95 217void *
fc98f5cb 218__gthread_objc_thread_get_data (void)
15794a95 219{
69e905c8
TP
220 DWORD lasterror;
221 void *ptr;
222
fc98f5cb 223 lasterror = GetLastError ();
69e905c8 224
fc98f5cb 225 ptr = TlsGetValue (__gthread_objc_data_tls); /* Return thread data. */
69e905c8 226
fc98f5cb 227 SetLastError (lasterror);
69e905c8
TP
228
229 return ptr;
15794a95
L
230}
231
232/* Backend mutex functions */
233
71287280 234/* Allocate a mutex. */
15794a95 235int
fc98f5cb 236__gthread_objc_mutex_allocate (objc_mutex_t mutex)
15794a95 237{
fc98f5cb 238 if ((mutex->backend = (void *) CreateMutex (NULL, 0, NULL)) == NULL)
15794a95
L
239 return -1;
240 else
241 return 0;
242}
243
71287280 244/* Deallocate a mutex. */
15794a95 245int
fc98f5cb 246__gthread_objc_mutex_deallocate (objc_mutex_t mutex)
15794a95 247{
fc98f5cb 248 CloseHandle ((HANDLE) (mutex->backend));
15794a95
L
249 return 0;
250}
251
71287280 252/* Grab a lock on a mutex. */
15794a95 253int
fc98f5cb 254__gthread_objc_mutex_lock (objc_mutex_t mutex)
15794a95
L
255{
256 int status;
257
fc98f5cb 258 status = WaitForSingleObject ((HANDLE) (mutex->backend), INFINITE);
15794a95
L
259 if (status != WAIT_OBJECT_0 && status != WAIT_ABANDONED)
260 return -1;
261 else
262 return 0;
263}
264
71287280 265/* Try to grab a lock on a mutex. */
15794a95 266int
fc98f5cb 267__gthread_objc_mutex_trylock (objc_mutex_t mutex)
15794a95
L
268{
269 int status;
270
fc98f5cb 271 status = WaitForSingleObject ((HANDLE) (mutex->backend), 0);
15794a95
L
272 if (status != WAIT_OBJECT_0 && status != WAIT_ABANDONED)
273 return -1;
274 else
275 return 0;
276}
277
278/* Unlock the mutex */
279int
fc98f5cb 280__gthread_objc_mutex_unlock (objc_mutex_t mutex)
15794a95 281{
fc98f5cb 282 if (ReleaseMutex ((HANDLE) (mutex->backend)) == 0)
15794a95
L
283 return -1;
284 else
285 return 0;
286}
287
288/* Backend condition mutex functions */
289
71287280 290/* Allocate a condition. */
15794a95 291int
fc98f5cb 292__gthread_objc_condition_allocate (objc_condition_t condition)
15794a95 293{
71287280 294 /* Unimplemented. */
15794a95
L
295 return -1;
296}
297
71287280 298/* Deallocate a condition. */
15794a95 299int
fc98f5cb 300__gthread_objc_condition_deallocate (objc_condition_t condition)
15794a95 301{
71287280 302 /* Unimplemented. */
15794a95
L
303 return -1;
304}
305
306/* Wait on the condition */
307int
fc98f5cb 308__gthread_objc_condition_wait (objc_condition_t condition, objc_mutex_t mutex)
15794a95 309{
71287280 310 /* Unimplemented. */
15794a95
L
311 return -1;
312}
313
71287280 314/* Wake up all threads waiting on this condition. */
15794a95 315int
fc98f5cb 316__gthread_objc_condition_broadcast (objc_condition_t condition)
15794a95 317{
71287280 318 /* Unimplemented. */
15794a95
L
319 return -1;
320}
321
71287280 322/* Wake up one thread waiting on this condition. */
15794a95 323int
fc98f5cb 324__gthread_objc_condition_signal (objc_condition_t condition)
15794a95 325{
71287280 326 /* Unimplemented. */
15794a95
L
327 return -1;
328}
329
330#else /* _LIBOBJC */
331
b25bb36a
DS
332#ifdef __cplusplus
333extern "C" {
334#endif
62dafdeb 335
b25bb36a 336typedef unsigned long __gthread_key_t;
62dafdeb
MK
337
338typedef struct {
339 int done;
340 long started;
341} __gthread_once_t;
342
80408cac
WY
343typedef struct {
344 long counter;
345 void *sema;
346} __gthread_mutex_t;
62dafdeb 347
40aac948
JM
348typedef struct {
349 long counter;
350 long depth;
40219f96 351 unsigned long owner;
40aac948
JM
352 void *sema;
353} __gthread_recursive_mutex_t;
354
b25bb36a 355#define __GTHREAD_ONCE_INIT {0, -1}
62dafdeb 356#define __GTHREAD_MUTEX_INIT_FUNCTION __gthread_mutex_init_function
42dfcf84 357#define __GTHREAD_MUTEX_INIT_DEFAULT {-1, 0}
40219f96
WY
358#define __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION \
359 __gthread_recursive_mutex_init_function
360#define __GTHREAD_RECURSIVE_MUTEX_INIT_DEFAULT {-1, 0, 0, 0}
62dafdeb 361
f22a97d2
MK
362#if __MINGW32_MAJOR_VERSION >= 1 || \
363 (__MINGW32_MAJOR_VERSION == 0 && __MINGW32_MINOR_VERSION > 2)
364#define MINGW32_SUPPORTS_MT_EH 1
cc2902df 365/* Mingw runtime >= v0.3 provides a magic variable that is set to nonzero
589005ff 366 if -mthreads option was specified, or 0 otherwise. This is to get around
f22a97d2
MK
367 the lack of weak symbols in PE-COFF. */
368extern int _CRT_MT;
b25bb36a
DS
369extern int __mingwthr_key_dtor (unsigned long, void (*) (void *));
370#endif /* __MINGW32__ version */
f22a97d2 371
42dfcf84
WY
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
378static inline long
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
62dafdeb 395static inline int
d1e51320 396__gthread_active_p (void)
62dafdeb 397{
f22a97d2
MK
398#ifdef MINGW32_SUPPORTS_MT_EH
399 return _CRT_MT;
400#else
62dafdeb 401 return 1;
f22a97d2 402#endif
62dafdeb
MK
403}
404
81888fcd 405#if __GTHREAD_HIDE_WIN32API
b25bb36a
DS
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
411extern int __gthr_win32_once (__gthread_once_t *, void (*) (void));
412extern int __gthr_win32_key_create (__gthread_key_t *, void (*) (void*));
413extern int __gthr_win32_key_delete (__gthread_key_t);
414extern void * __gthr_win32_getspecific (__gthread_key_t);
415extern int __gthr_win32_setspecific (__gthread_key_t, const void *);
416extern void __gthr_win32_mutex_init_function (__gthread_mutex_t *);
417extern int __gthr_win32_mutex_lock (__gthread_mutex_t *);
418extern int __gthr_win32_mutex_trylock (__gthread_mutex_t *);
419extern int __gthr_win32_mutex_unlock (__gthread_mutex_t *);
40219f96
WY
420extern void
421 __gthr_win32_recursive_mutex_init_function (__gthread_recursive_mutex_t *);
422extern int __gthr_win32_recursive_mutex_lock (__gthread_recursive_mutex_t *);
423extern int
424 __gthr_win32_recursive_mutex_trylock (__gthread_recursive_mutex_t *);
425extern int __gthr_win32_recursive_mutex_unlock (__gthread_recursive_mutex_t *);
b25bb36a
DS
426
427static inline int
428__gthread_once (__gthread_once_t *once, void (*func) (void))
429{
fc98f5cb 430 if (__gthread_active_p ())
b25bb36a
DS
431 return __gthr_win32_once (once, func);
432 else
fc98f5cb 433 return -1;
b25bb36a
DS
434}
435
436static inline int
437__gthread_key_create (__gthread_key_t *key, void (*dtor) (void *))
438{
439 return __gthr_win32_key_create (key, dtor);
440}
441
fc98f5cb 442static inline int
b25bb36a
DS
443__gthread_key_delete (__gthread_key_t key)
444{
fc98f5cb 445 return __gthr_win32_key_delete (key);
b25bb36a
DS
446}
447
448static inline void *
449__gthread_getspecific (__gthread_key_t key)
450{
451 return __gthr_win32_getspecific (key);
452}
453
454static inline int
455__gthread_setspecific (__gthread_key_t key, const void *ptr)
456{
457 return __gthr_win32_setspecific (key, ptr);
458}
459
460static inline void
461__gthread_mutex_init_function (__gthread_mutex_t *mutex)
462{
463 __gthr_win32_mutex_init_function (mutex);
464}
465
466static inline int
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
475static inline int
476__gthread_mutex_trylock (__gthread_mutex_t *mutex)
477{
478 if (__gthread_active_p ())
479 return __gthr_win32_mutex_trylock (mutex);
480 else
fc98f5cb 481 return 0;
b25bb36a
DS
482}
483
484static inline int
485__gthread_mutex_unlock (__gthread_mutex_t *mutex)
486{
487 if (__gthread_active_p ())
488 return __gthr_win32_mutex_unlock (mutex);
489 else
fc98f5cb 490 return 0;
b25bb36a
DS
491}
492
40219f96
WY
493static inline void
494__gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *mutex)
495{
496 __gthr_win32_recursive_mutex_init_function (mutex);
497}
498
40aac948
JM
499static inline int
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
508static inline int
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
517static inline int
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
b25bb36a
DS
526#else /* ! __GTHREAD_HIDE_WIN32API */
527
528#include <windows.h>
529#include <errno.h>
530
62dafdeb 531static inline int
d1e51320 532__gthread_once (__gthread_once_t *once, void (*func) (void))
62dafdeb
MK
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)
589005ff 542 {
62dafdeb
MK
543 (*func) ();
544 once->done = TRUE;
545 }
f22a97d2
MK
546 else
547 {
589005ff
KH
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. */
f22a97d2
MK
553 while (! once->done)
554 Sleep (0);
555 }
62dafdeb 556 }
589005ff 557
62dafdeb
MK
558 return 0;
559}
560
f22a97d2 561/* Windows32 thread local keys don't support destructors; this leads to
589005ff 562 leaks, especially in threaded applications making extensive use of
f22a97d2 563 C++ EH. Mingw uses a thread-support DLL to work-around this problem. */
62dafdeb 564static inline int
f22a97d2 565__gthread_key_create (__gthread_key_t *key, void (*dtor) (void *))
62dafdeb
MK
566{
567 int status = 0;
568 DWORD tls_index = TlsAlloc ();
569 if (tls_index != 0xFFFFFFFF)
f22a97d2
MK
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 }
62dafdeb
MK
578 else
579 status = (int) GetLastError ();
580 return status;
581}
582
62dafdeb
MK
583static inline int
584__gthread_key_delete (__gthread_key_t key)
585{
586 return (TlsFree (key) != 0) ? 0 : (int) GetLastError ();
587}
588
589static inline void *
590__gthread_getspecific (__gthread_key_t key)
591{
69e905c8
TP
592 DWORD lasterror;
593 void *ptr;
594
fc98f5cb 595 lasterror = GetLastError ();
69e905c8 596
fc98f5cb 597 ptr = TlsGetValue (key);
69e905c8 598
fc98f5cb 599 SetLastError (lasterror);
69e905c8
TP
600
601 return ptr;
62dafdeb
MK
602}
603
604static inline int
605__gthread_setspecific (__gthread_key_t key, const void *ptr)
606{
f22a97d2 607 return (TlsSetValue (key, (void*) ptr) != 0) ? 0 : (int) GetLastError ();
62dafdeb
MK
608}
609
610static inline void
611__gthread_mutex_init_function (__gthread_mutex_t *mutex)
612{
42dfcf84 613 mutex->counter = -1;
80408cac 614 mutex->sema = CreateSemaphore (NULL, 0, 65535, NULL);
62dafdeb
MK
615}
616
617static inline int
618__gthread_mutex_lock (__gthread_mutex_t *mutex)
619{
620 int status = 0;
621
622 if (__gthread_active_p ())
623 {
42dfcf84 624 if (InterlockedIncrement (&mutex->counter) == 0 ||
80408cac 625 WaitForSingleObject (mutex->sema, INFINITE) == WAIT_OBJECT_0)
62dafdeb
MK
626 status = 0;
627 else
80408cac 628 {
42dfcf84
WY
629 /* WaitForSingleObject returns WAIT_FAILED, and we can only do
630 some best-effort cleanup here. */
80408cac
WY
631 InterlockedDecrement (&mutex->counter);
632 status = 1;
633 }
62dafdeb
MK
634 }
635 return status;
636}
637
638static inline int
639__gthread_mutex_trylock (__gthread_mutex_t *mutex)
640{
641 int status = 0;
642
643 if (__gthread_active_p ())
644 {
42dfcf84 645 if (__GTHR_W32_InterlockedCompareExchange (&mutex->counter, 0, -1) < 0)
62dafdeb
MK
646 status = 0;
647 else
648 status = 1;
649 }
650 return status;
651}
652
653static inline int
654__gthread_mutex_unlock (__gthread_mutex_t *mutex)
655{
656 if (__gthread_active_p ())
80408cac 657 {
42dfcf84 658 if (InterlockedDecrement (&mutex->counter) >= 0)
80408cac
WY
659 return ReleaseSemaphore (mutex->sema, 1, NULL) ? 0 : 1;
660 }
661 return 0;
62dafdeb
MK
662}
663
40aac948
JM
664static inline void
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
673static inline int
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 {
40219f96 686 InterlockedDecrement (&mutex->counter);
40aac948
JM
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
705static inline int
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
724static inline int
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
b25bb36a
DS
741#endif /* __GTHREAD_HIDE_WIN32API */
742
743#ifdef __cplusplus
744}
745#endif
746
15794a95
L
747#endif /* _LIBOBJC */
748
88657302 749#endif /* ! GCC_GTHR_WIN32_H */