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