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