]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgcc/config/i386/gthr-win32.h
Update copyright years.
[thirdparty/gcc.git] / libgcc / config / i386 / gthr-win32.h
CommitLineData
15794a95 1/* Threads compatibility routines for libgcc2 and libobjc. */
62dafdeb 2/* Compile this one with gcc. */
fe9565ed 3
8d9254fc 4/* Copyright (C) 1999-2020 Free Software Foundation, Inc.
62dafdeb
MK
5 Contributed by Mumit Khan <khan@xraylith.wisc.edu>.
6
1322177d 7This file is part of GCC.
62dafdeb 8
1322177d
LB
9GCC is free software; you can redistribute it and/or modify it under
10the terms of the GNU General Public License as published by the Free
748086b7 11Software Foundation; either version 3, or (at your option) any later
1322177d 12version.
62dafdeb 13
1322177d
LB
14GCC is distributed in the hope that it will be useful, but WITHOUT ANY
15WARRANTY; without even the implied warranty of MERCHANTABILITY or
16FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17for more details.
62dafdeb 18
748086b7
JJ
19Under Section 7 of GPL version 3, you are granted additional
20permissions described in the GCC Runtime Library Exception, version
213.1, as published by the Free Software Foundation.
22
23You should have received a copy of the GNU General Public License and
24a copy of the GCC Runtime Library Exception along with this program;
25see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
26<http://www.gnu.org/licenses/>. */
62dafdeb 27
88657302
RH
28#ifndef GCC_GTHR_WIN32_H
29#define GCC_GTHR_WIN32_H
62dafdeb 30
fea16f81
DS
31/* Make sure CONST_CAST2 (origin in system.h) is declared. */
32#ifndef CONST_CAST2
33#define CONST_CAST2(TOTYPE,FROMTYPE,X) ((__extension__(union {FROMTYPE _q; TOTYPE _nq;})(X))._nq)
34#endif
35
62dafdeb 36/* Windows32 threads specific definitions. The windows32 threading model
589005ff 37 does not map well into pthread-inspired gcc's threading model, and so
62dafdeb
MK
38 there are caveats one needs to be aware of.
39
f22a97d2 40 1. The destructor supplied to __gthread_key_create is ignored for
589005ff
KH
41 generic x86-win32 ports. This will certainly cause memory leaks
42 due to unreclaimed eh contexts (sizeof (eh_context) is at least
f22a97d2 43 24 bytes for x86 currently).
62dafdeb
MK
44
45 This memory leak may be significant for long-running applications
46 that make heavy use of C++ EH.
47
f22a97d2
MK
48 However, Mingw runtime (version 0.3 or newer) provides a mechanism
49 to emulate pthreads key dtors; the runtime provides a special DLL,
50 linked in if -mthreads option is specified, that runs the dtors in
51 the reverse order of registration when each thread exits. If
52 -mthreads option is not given, a stub is linked in instead of the
589005ff 53 DLL, which results in memory leak. Other x86-win32 ports can use
f22a97d2
MK
54 the same technique of course to avoid the leak.
55
62dafdeb 56 2. The error codes returned are non-POSIX like, and cast into ints.
589005ff 57 This may cause incorrect error return due to truncation values on
62dafdeb 58 hw where sizeof (DWORD) > sizeof (int).
589005ff 59
80408cac
WY
60 3. We are currently using a special mutex instead of the Critical
61 Sections, since Win9x does not support TryEnterCriticalSection
62 (while NT does).
589005ff 63
f22a97d2
MK
64 The basic framework should work well enough. In the long term, GCC
65 needs to use Structured Exception Handling on Windows32. */
62dafdeb
MK
66
67#define __GTHREADS 1
68
5dab7f92
TP
69#include <errno.h>
70#ifdef __MINGW32__
71#include <_mingw.h>
72#endif
15794a95 73
ce4a9de3
KT
74#ifndef __UNUSED_PARAM
75#define __UNUSED_PARAM(x) x
76#endif
77
15794a95
L
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
ce4a9de3 127 return (objc_thread_t) (INT_PTR) 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{
ce4a9de3 208 return (objc_thread_t) (INT_PTR) 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
ce4a9de3 297__gthread_objc_condition_allocate (objc_condition_t __UNUSED_PARAM(condition))
15794a95 298{
71287280 299 /* Unimplemented. */
15794a95
L
300 return -1;
301}
302
71287280 303/* Deallocate a condition. */
15794a95 304int
ce4a9de3 305__gthread_objc_condition_deallocate (objc_condition_t __UNUSED_PARAM(condition))
15794a95 306{
71287280 307 /* Unimplemented. */
15794a95
L
308 return -1;
309}
310
311/* Wait on the condition */
312int
ce4a9de3
KT
313__gthread_objc_condition_wait (objc_condition_t __UNUSED_PARAM(condition),
314 objc_mutex_t __UNUSED_PARAM(mutex))
15794a95 315{
71287280 316 /* Unimplemented. */
15794a95
L
317 return -1;
318}
319
71287280 320/* Wake up all threads waiting on this condition. */
15794a95 321int
ce4a9de3 322__gthread_objc_condition_broadcast (objc_condition_t __UNUSED_PARAM(condition))
15794a95 323{
71287280 324 /* Unimplemented. */
15794a95
L
325 return -1;
326}
327
71287280 328/* Wake up one thread waiting on this condition. */
15794a95 329int
ce4a9de3 330__gthread_objc_condition_signal (objc_condition_t __UNUSED_PARAM(condition))
15794a95 331{
71287280 332 /* Unimplemented. */
15794a95
L
333 return -1;
334}
335
336#else /* _LIBOBJC */
337
b25bb36a
DS
338#ifdef __cplusplus
339extern "C" {
340#endif
62dafdeb 341
b25bb36a 342typedef unsigned long __gthread_key_t;
62dafdeb
MK
343
344typedef struct {
345 int done;
346 long started;
347} __gthread_once_t;
348
80408cac
WY
349typedef struct {
350 long counter;
351 void *sema;
352} __gthread_mutex_t;
62dafdeb 353
40aac948
JM
354typedef struct {
355 long counter;
356 long depth;
40219f96 357 unsigned long owner;
40aac948
JM
358 void *sema;
359} __gthread_recursive_mutex_t;
360
b25bb36a 361#define __GTHREAD_ONCE_INIT {0, -1}
62dafdeb 362#define __GTHREAD_MUTEX_INIT_FUNCTION __gthread_mutex_init_function
42dfcf84 363#define __GTHREAD_MUTEX_INIT_DEFAULT {-1, 0}
40219f96
WY
364#define __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION \
365 __gthread_recursive_mutex_init_function
366#define __GTHREAD_RECURSIVE_MUTEX_INIT_DEFAULT {-1, 0, 0, 0}
62dafdeb 367
a1bda0d7 368#if defined (_WIN32) && !defined(__CYGWIN__)
f22a97d2 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 374extern int __mingwthr_key_dtor (unsigned long, void (*) (void *));
a1bda0d7 375#endif /* _WIN32 && !__CYGWIN__ */
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
09e361bb 384__gthr_i486_lock_cmp_xchg(long *__dest, long __xchg, long __comperand)
42dfcf84
WY
385{
386 long result;
387 __asm__ __volatile__ ("\n\
388 lock\n\
389 cmpxchg{l} {%4, %1|%1, %4}\n"
09e361bb
JJ
390 : "=a" (result), "=m" (*__dest)
391 : "0" (__comperand), "m" (*__dest), "r" (__xchg)
42dfcf84
WY
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 *);
1504e3e1
JW
432extern int
433 __gthr_win32_recursive_mutex_destroy (__gthread_recursive_mutex_t *);
b25bb36a
DS
434
435static inline int
09e361bb 436__gthread_once (__gthread_once_t *__once, void (*__func) (void))
b25bb36a 437{
fc98f5cb 438 if (__gthread_active_p ())
09e361bb 439 return __gthr_win32_once (__once, __func);
b25bb36a 440 else
fc98f5cb 441 return -1;
b25bb36a
DS
442}
443
444static inline int
09e361bb 445__gthread_key_create (__gthread_key_t *__key, void (*__dtor) (void *))
b25bb36a 446{
09e361bb 447 return __gthr_win32_key_create (__key, __dtor);
b25bb36a
DS
448}
449
fc98f5cb 450static inline int
09e361bb 451__gthread_key_delete (__gthread_key_t __key)
b25bb36a 452{
09e361bb 453 return __gthr_win32_key_delete (__key);
b25bb36a
DS
454}
455
456static inline void *
09e361bb 457__gthread_getspecific (__gthread_key_t __key)
b25bb36a 458{
09e361bb 459 return __gthr_win32_getspecific (__key);
b25bb36a
DS
460}
461
462static inline int
09e361bb 463__gthread_setspecific (__gthread_key_t __key, const void *__ptr)
b25bb36a 464{
09e361bb 465 return __gthr_win32_setspecific (__key, __ptr);
b25bb36a
DS
466}
467
468static inline void
09e361bb 469__gthread_mutex_init_function (__gthread_mutex_t *__mutex)
b25bb36a 470{
09e361bb 471 __gthr_win32_mutex_init_function (__mutex);
b25bb36a
DS
472}
473
c262f705 474static inline void
09e361bb 475__gthread_mutex_destroy (__gthread_mutex_t *__mutex)
c262f705 476{
09e361bb 477 __gthr_win32_mutex_destroy (__mutex);
c262f705
DS
478}
479
b25bb36a 480static inline int
09e361bb 481__gthread_mutex_lock (__gthread_mutex_t *__mutex)
b25bb36a
DS
482{
483 if (__gthread_active_p ())
09e361bb 484 return __gthr_win32_mutex_lock (__mutex);
b25bb36a
DS
485 else
486 return 0;
487}
488
489static inline int
09e361bb 490__gthread_mutex_trylock (__gthread_mutex_t *__mutex)
b25bb36a
DS
491{
492 if (__gthread_active_p ())
09e361bb 493 return __gthr_win32_mutex_trylock (__mutex);
b25bb36a 494 else
fc98f5cb 495 return 0;
b25bb36a
DS
496}
497
498static inline int
09e361bb 499__gthread_mutex_unlock (__gthread_mutex_t *__mutex)
b25bb36a
DS
500{
501 if (__gthread_active_p ())
09e361bb 502 return __gthr_win32_mutex_unlock (__mutex);
b25bb36a 503 else
fc98f5cb 504 return 0;
b25bb36a
DS
505}
506
40219f96 507static inline void
09e361bb 508__gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *__mutex)
40219f96 509{
09e361bb 510 __gthr_win32_recursive_mutex_init_function (__mutex);
40219f96
WY
511}
512
40aac948 513static inline int
09e361bb 514__gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *__mutex)
40aac948
JM
515{
516 if (__gthread_active_p ())
09e361bb 517 return __gthr_win32_recursive_mutex_lock (__mutex);
40aac948
JM
518 else
519 return 0;
520}
521
522static inline int
09e361bb 523__gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *__mutex)
40aac948
JM
524{
525 if (__gthread_active_p ())
09e361bb 526 return __gthr_win32_recursive_mutex_trylock (__mutex);
40aac948
JM
527 else
528 return 0;
529}
530
531static inline int
09e361bb 532__gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *__mutex)
40aac948
JM
533{
534 if (__gthread_active_p ())
09e361bb 535 return __gthr_win32_recursive_mutex_unlock (__mutex);
40aac948
JM
536 else
537 return 0;
538}
539
1504e3e1 540static inline int
5e3e4fe8 541__gthread_recursive_mutex_destroy (__gthread_recursive_mutex_t *__mutex)
1504e3e1
JW
542{
543 return __gthr_win32_recursive_mutex_destroy (__mutex);
544}
545
b25bb36a
DS
546#else /* ! __GTHREAD_HIDE_WIN32API */
547
db9f7f65 548#define NOGDI
b25bb36a
DS
549#include <windows.h>
550#include <errno.h>
551
62dafdeb 552static inline int
09e361bb 553__gthread_once (__gthread_once_t *__once, void (*__func) (void))
62dafdeb
MK
554{
555 if (! __gthread_active_p ())
556 return -1;
09e361bb 557 else if (__once == NULL || __func == NULL)
62dafdeb
MK
558 return EINVAL;
559
09e361bb 560 if (! __once->done)
62dafdeb 561 {
09e361bb 562 if (InterlockedIncrement (&(__once->started)) == 0)
589005ff 563 {
09e361bb
JJ
564 (*__func) ();
565 __once->done = TRUE;
62dafdeb 566 }
f22a97d2
MK
567 else
568 {
589005ff
KH
569 /* Another thread is currently executing the code, so wait for it
570 to finish; yield the CPU in the meantime. If performance
571 does become an issue, the solution is to use an Event that
572 we wait on here (and set above), but that implies a place to
573 create the event before this routine is called. */
09e361bb 574 while (! __once->done)
f22a97d2
MK
575 Sleep (0);
576 }
62dafdeb 577 }
589005ff 578
62dafdeb
MK
579 return 0;
580}
581
f22a97d2 582/* Windows32 thread local keys don't support destructors; this leads to
589005ff 583 leaks, especially in threaded applications making extensive use of
f22a97d2 584 C++ EH. Mingw uses a thread-support DLL to work-around this problem. */
62dafdeb 585static inline int
09e361bb 586__gthread_key_create (__gthread_key_t *__key,
7727f8f2 587 void (*__dtor) (void *) __attribute__((__unused__)))
62dafdeb 588{
09e361bb
JJ
589 int __status = 0;
590 DWORD __tls_index = TlsAlloc ();
591 if (__tls_index != 0xFFFFFFFF)
f22a97d2 592 {
09e361bb 593 *__key = __tls_index;
f22a97d2
MK
594#ifdef MINGW32_SUPPORTS_MT_EH
595 /* Mingw runtime will run the dtors in reverse order for each thread
596 when the thread exits. */
09e361bb 597 __status = __mingwthr_key_dtor (*__key, __dtor);
f22a97d2
MK
598#endif
599 }
62dafdeb 600 else
09e361bb
JJ
601 __status = (int) GetLastError ();
602 return __status;
62dafdeb
MK
603}
604
62dafdeb 605static inline int
09e361bb 606__gthread_key_delete (__gthread_key_t __key)
62dafdeb 607{
09e361bb 608 return (TlsFree (__key) != 0) ? 0 : (int) GetLastError ();
62dafdeb
MK
609}
610
611static inline void *
09e361bb 612__gthread_getspecific (__gthread_key_t __key)
62dafdeb 613{
09e361bb
JJ
614 DWORD __lasterror;
615 void *__ptr;
69e905c8 616
09e361bb 617 __lasterror = GetLastError ();
69e905c8 618
09e361bb 619 __ptr = TlsGetValue (__key);
69e905c8 620
09e361bb 621 SetLastError (__lasterror);
69e905c8 622
09e361bb 623 return __ptr;
62dafdeb
MK
624}
625
626static inline int
09e361bb 627__gthread_setspecific (__gthread_key_t __key, const void *__ptr)
62dafdeb 628{
09e361bb 629 if (TlsSetValue (__key, CONST_CAST2(void *, const void *, __ptr)) != 0)
fea16f81
DS
630 return 0;
631 else
632 return GetLastError ();
62dafdeb
MK
633}
634
635static inline void
09e361bb 636__gthread_mutex_init_function (__gthread_mutex_t *__mutex)
62dafdeb 637{
09e361bb 638 __mutex->counter = -1;
dff717d2 639 __mutex->sema = CreateSemaphoreW (NULL, 0, 65535, NULL);
62dafdeb
MK
640}
641
ef4195d6 642static inline void
09e361bb 643__gthread_mutex_destroy (__gthread_mutex_t *__mutex)
ef4195d6 644{
09e361bb 645 CloseHandle ((HANDLE) __mutex->sema);
ef4195d6
JD
646}
647
62dafdeb 648static inline int
09e361bb 649__gthread_mutex_lock (__gthread_mutex_t *__mutex)
62dafdeb 650{
09e361bb 651 int __status = 0;
62dafdeb
MK
652
653 if (__gthread_active_p ())
654 {
09e361bb
JJ
655 if (InterlockedIncrement (&__mutex->counter) == 0 ||
656 WaitForSingleObject (__mutex->sema, INFINITE) == WAIT_OBJECT_0)
657 __status = 0;
62dafdeb 658 else
80408cac 659 {
42dfcf84
WY
660 /* WaitForSingleObject returns WAIT_FAILED, and we can only do
661 some best-effort cleanup here. */
09e361bb
JJ
662 InterlockedDecrement (&__mutex->counter);
663 __status = 1;
80408cac 664 }
62dafdeb 665 }
09e361bb 666 return __status;
62dafdeb
MK
667}
668
669static inline int
09e361bb 670__gthread_mutex_trylock (__gthread_mutex_t *__mutex)
62dafdeb 671{
09e361bb 672 int __status = 0;
62dafdeb
MK
673
674 if (__gthread_active_p ())
675 {
09e361bb
JJ
676 if (__GTHR_W32_InterlockedCompareExchange (&__mutex->counter, 0, -1) < 0)
677 __status = 0;
62dafdeb 678 else
09e361bb 679 __status = 1;
62dafdeb 680 }
09e361bb 681 return __status;
62dafdeb
MK
682}
683
684static inline int
09e361bb 685__gthread_mutex_unlock (__gthread_mutex_t *__mutex)
62dafdeb
MK
686{
687 if (__gthread_active_p ())
80408cac 688 {
09e361bb
JJ
689 if (InterlockedDecrement (&__mutex->counter) >= 0)
690 return ReleaseSemaphore (__mutex->sema, 1, NULL) ? 0 : 1;
80408cac
WY
691 }
692 return 0;
62dafdeb
MK
693}
694
40aac948 695static inline void
09e361bb 696__gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *__mutex)
40aac948 697{
09e361bb
JJ
698 __mutex->counter = -1;
699 __mutex->depth = 0;
700 __mutex->owner = 0;
dff717d2 701 __mutex->sema = CreateSemaphoreW (NULL, 0, 65535, NULL);
40aac948
JM
702}
703
704static inline int
09e361bb 705__gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *__mutex)
40aac948
JM
706{
707 if (__gthread_active_p ())
708 {
09e361bb
JJ
709 DWORD __me = GetCurrentThreadId();
710 if (InterlockedIncrement (&__mutex->counter) == 0)
40aac948 711 {
09e361bb
JJ
712 __mutex->depth = 1;
713 __mutex->owner = __me;
40aac948 714 }
09e361bb 715 else if (__mutex->owner == __me)
40aac948 716 {
09e361bb
JJ
717 InterlockedDecrement (&__mutex->counter);
718 ++(__mutex->depth);
40aac948 719 }
09e361bb 720 else if (WaitForSingleObject (__mutex->sema, INFINITE) == WAIT_OBJECT_0)
40aac948 721 {
09e361bb
JJ
722 __mutex->depth = 1;
723 __mutex->owner = __me;
40aac948
JM
724 }
725 else
726 {
727 /* WaitForSingleObject returns WAIT_FAILED, and we can only do
728 some best-effort cleanup here. */
09e361bb 729 InterlockedDecrement (&__mutex->counter);
40aac948
JM
730 return 1;
731 }
732 }
733 return 0;
734}
735
736static inline int
09e361bb 737__gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *__mutex)
40aac948
JM
738{
739 if (__gthread_active_p ())
740 {
09e361bb
JJ
741 DWORD __me = GetCurrentThreadId();
742 if (__GTHR_W32_InterlockedCompareExchange (&__mutex->counter, 0, -1) < 0)
40aac948 743 {
09e361bb
JJ
744 __mutex->depth = 1;
745 __mutex->owner = __me;
40aac948 746 }
09e361bb
JJ
747 else if (__mutex->owner == __me)
748 ++(__mutex->depth);
40aac948
JM
749 else
750 return 1;
751 }
752 return 0;
753}
754
755static inline int
09e361bb 756__gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *__mutex)
40aac948
JM
757{
758 if (__gthread_active_p ())
759 {
09e361bb
JJ
760 --(__mutex->depth);
761 if (__mutex->depth == 0)
40aac948 762 {
09e361bb 763 __mutex->owner = 0;
40aac948 764
09e361bb
JJ
765 if (InterlockedDecrement (&__mutex->counter) >= 0)
766 return ReleaseSemaphore (__mutex->sema, 1, NULL) ? 0 : 1;
40aac948
JM
767 }
768 }
769 return 0;
770}
771
1504e3e1 772static inline int
5e3e4fe8 773__gthread_recursive_mutex_destroy (__gthread_recursive_mutex_t *__mutex)
1504e3e1 774{
5e3e4fe8 775 CloseHandle ((HANDLE) __mutex->sema);
1504e3e1
JW
776 return 0;
777}
778
b25bb36a
DS
779#endif /* __GTHREAD_HIDE_WIN32API */
780
781#ifdef __cplusplus
782}
783#endif
784
15794a95
L
785#endif /* _LIBOBJC */
786
88657302 787#endif /* ! GCC_GTHR_WIN32_H */