]> 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
a945c346 4/* Copyright (C) 1999-2024 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
9149a5b7
EB
31/* So we can test Windows version numbers. */
32#include <stdlib.h>
fea16f81 33
9149a5b7
EB
34/* The Windows threading model does not map well into the POSIX inspired
35 GCC threading model, so there are caveats one needs to be aware of.
62dafdeb 36
f22a97d2 37 1. The destructor supplied to __gthread_key_create is ignored for
9149a5b7
EB
38 generic Windows ports. This will certainly cause memory leaks
39 due to unreclaimed EH contexts (sizeof (eh_context) is at least
f22a97d2 40 24 bytes for x86 currently).
62dafdeb
MK
41
42 This memory leak may be significant for long-running applications
43 that make heavy use of C++ EH.
44
f22a97d2
MK
45 However, Mingw runtime (version 0.3 or newer) provides a mechanism
46 to emulate pthreads key dtors; the runtime provides a special DLL,
47 linked in if -mthreads option is specified, that runs the dtors in
48 the reverse order of registration when each thread exits. If
49 -mthreads option is not given, a stub is linked in instead of the
9149a5b7 50 DLL, which results in memory leak. Other Windows ports can use
f22a97d2
MK
51 the same technique of course to avoid the leak.
52
62dafdeb 53 2. The error codes returned are non-POSIX like, and cast into ints.
589005ff 54 This may cause incorrect error return due to truncation values on
62dafdeb 55 hw where sizeof (DWORD) > sizeof (int).
589005ff 56
9149a5b7
EB
57 3. POSIX-like condition variables are supported, but only on Vista and
58 Server 2008 or later versions.
589005ff 59
9149a5b7 60 4. Timed lock primitives are not supported. */
62dafdeb
MK
61
62#define __GTHREADS 1
63
9149a5b7
EB
64/* Condition variables are supported on Vista and Server 2008 or later. */
65#if _WIN32_WINNT >= 0x0600
66#define __GTHREAD_HAS_COND 1
67#define __GTHREADS_CXX0X 1
68#endif
69
70#if _GTHREAD_USE_MUTEX_TIMEDLOCK
71#error Timed lock primitives are not supported on Windows targets
72#endif
73
74/* Make sure CONST_CAST2 (origin in system.h) is declared. */
75#ifndef CONST_CAST2
76#ifdef __cplusplus
77#define CONST_CAST2(TOTYPE,FROMTYPE,X) (const_cast<TOTYPE> (X))
78#else
79#define CONST_CAST2(TOTYPE,FROMTYPE,X) ((__extension__(union {FROMTYPE _q; TOTYPE _nq;})(X))._nq)
80#endif
5dab7f92 81#endif
15794a95 82
9149a5b7
EB
83#ifndef ATTRIBUTE_UNUSED
84#define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
ce4a9de3
KT
85#endif
86
15794a95
L
87#ifdef _LIBOBJC
88
3b56934f 89/* This is necessary to prevent windef.h (included from windows.h) from
f3b569ca 90 defining its own BOOL as a typedef. */
3b56934f
CF
91#ifndef __OBJC__
92#define __OBJC__
93#endif
9149a5b7 94#define WIN32_LEAN_AND_MEAN
3b56934f 95#include <windows.h>
339db340 96/* Now undef the windows BOOL and CC_NONE */
3b56934f 97#undef BOOL
339db340 98#undef CC_NONE
3b56934f 99
15794a95 100/* Key structure for maintaining thread specific storage */
9149a5b7 101static DWORD __gthread_objc_data_tls = TLS_OUT_OF_INDEXES;
15794a95
L
102
103/* Backend initialization functions */
104
71287280 105/* Initialize the threads subsystem. */
15794a95 106int
fc98f5cb 107__gthread_objc_init_thread_system (void)
15794a95 108{
ea4b7848 109 /* Initialize the thread storage key. */
9149a5b7 110 if ((__gthread_objc_data_tls = TlsAlloc ()) != TLS_OUT_OF_INDEXES)
15794a95
L
111 return 0;
112 else
113 return -1;
114}
115
71287280 116/* Close the threads subsystem. */
15794a95 117int
fc98f5cb 118__gthread_objc_close_thread_system (void)
15794a95 119{
9149a5b7 120 if (__gthread_objc_data_tls != TLS_OUT_OF_INDEXES)
fc98f5cb 121 TlsFree (__gthread_objc_data_tls);
15794a95
L
122 return 0;
123}
124
125/* Backend thread functions */
126
71287280 127/* Create a new thread of execution. */
15794a95 128objc_thread_t
fc98f5cb 129__gthread_objc_thread_detach (void (*func)(void *arg), void *arg)
15794a95
L
130{
131 DWORD thread_id = 0;
132 HANDLE win32_handle;
133
fc98f5cb
KH
134 if (!(win32_handle = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) func,
135 arg, 0, &thread_id)))
15794a95 136 thread_id = 0;
589005ff 137
ce4a9de3 138 return (objc_thread_t) (INT_PTR) thread_id;
15794a95
L
139}
140
71287280 141/* Set the current thread's priority. */
15794a95 142int
fc98f5cb 143__gthread_objc_thread_set_priority (int priority)
15794a95
L
144{
145 int sys_priority = 0;
146
147 switch (priority)
148 {
149 case OBJC_THREAD_INTERACTIVE_PRIORITY:
150 sys_priority = THREAD_PRIORITY_NORMAL;
151 break;
152 default:
153 case OBJC_THREAD_BACKGROUND_PRIORITY:
154 sys_priority = THREAD_PRIORITY_BELOW_NORMAL;
155 break;
156 case OBJC_THREAD_LOW_PRIORITY:
157 sys_priority = THREAD_PRIORITY_LOWEST;
158 break;
159 }
160
161 /* Change priority */
fc98f5cb 162 if (SetThreadPriority (GetCurrentThread (), sys_priority))
15794a95
L
163 return 0;
164 else
165 return -1;
166}
167
71287280 168/* Return the current thread's priority. */
15794a95 169int
fc98f5cb 170__gthread_objc_thread_get_priority (void)
15794a95
L
171{
172 int sys_priority;
173
fc98f5cb 174 sys_priority = GetThreadPriority (GetCurrentThread ());
589005ff 175
15794a95
L
176 switch (sys_priority)
177 {
178 case THREAD_PRIORITY_HIGHEST:
179 case THREAD_PRIORITY_TIME_CRITICAL:
180 case THREAD_PRIORITY_ABOVE_NORMAL:
181 case THREAD_PRIORITY_NORMAL:
182 return OBJC_THREAD_INTERACTIVE_PRIORITY;
183
184 default:
185 case THREAD_PRIORITY_BELOW_NORMAL:
186 return OBJC_THREAD_BACKGROUND_PRIORITY;
589005ff 187
15794a95
L
188 case THREAD_PRIORITY_IDLE:
189 case THREAD_PRIORITY_LOWEST:
190 return OBJC_THREAD_LOW_PRIORITY;
191 }
192
71287280 193 /* Couldn't get priority. */
15794a95
L
194 return -1;
195}
196
71287280 197/* Yield our process time to another thread. */
15794a95 198void
fc98f5cb 199__gthread_objc_thread_yield (void)
15794a95 200{
fc98f5cb 201 Sleep (0);
15794a95
L
202}
203
71287280 204/* Terminate the current thread. */
15794a95 205int
fc98f5cb 206__gthread_objc_thread_exit (void)
15794a95
L
207{
208 /* exit the thread */
fc98f5cb 209 ExitThread (__objc_thread_exit_status);
15794a95
L
210
211 /* Failed if we reached here */
212 return -1;
213}
214
71287280 215/* Returns an integer value which uniquely describes a thread. */
15794a95 216objc_thread_t
fc98f5cb 217__gthread_objc_thread_id (void)
15794a95 218{
ce4a9de3 219 return (objc_thread_t) (INT_PTR) GetCurrentThreadId ();
15794a95
L
220}
221
71287280 222/* Sets the thread's local storage pointer. */
15794a95 223int
fc98f5cb 224__gthread_objc_thread_set_data (void *value)
15794a95 225{
fc98f5cb 226 if (TlsSetValue (__gthread_objc_data_tls, value))
15794a95
L
227 return 0;
228 else
229 return -1;
230}
231
71287280 232/* Returns the thread's local storage pointer. */
15794a95 233void *
fc98f5cb 234__gthread_objc_thread_get_data (void)
15794a95 235{
9149a5b7
EB
236 DWORD lasterror = GetLastError ();
237 void * ptr = TlsGetValue (__gthread_objc_data_tls);
fc98f5cb 238 SetLastError (lasterror);
69e905c8 239 return ptr;
15794a95
L
240}
241
242/* Backend mutex functions */
243
71287280 244/* Allocate a mutex. */
15794a95 245int
fc98f5cb 246__gthread_objc_mutex_allocate (objc_mutex_t mutex)
15794a95 247{
fc98f5cb 248 if ((mutex->backend = (void *) CreateMutex (NULL, 0, NULL)) == NULL)
15794a95
L
249 return -1;
250 else
251 return 0;
252}
253
71287280 254/* Deallocate a mutex. */
15794a95 255int
fc98f5cb 256__gthread_objc_mutex_deallocate (objc_mutex_t mutex)
15794a95 257{
fc98f5cb 258 CloseHandle ((HANDLE) (mutex->backend));
15794a95
L
259 return 0;
260}
261
71287280 262/* Grab a lock on a mutex. */
15794a95 263int
fc98f5cb 264__gthread_objc_mutex_lock (objc_mutex_t mutex)
15794a95
L
265{
266 int status;
267
fc98f5cb 268 status = WaitForSingleObject ((HANDLE) (mutex->backend), INFINITE);
15794a95
L
269 if (status != WAIT_OBJECT_0 && status != WAIT_ABANDONED)
270 return -1;
271 else
272 return 0;
273}
274
71287280 275/* Try to grab a lock on a mutex. */
15794a95 276int
fc98f5cb 277__gthread_objc_mutex_trylock (objc_mutex_t mutex)
15794a95
L
278{
279 int status;
280
fc98f5cb 281 status = WaitForSingleObject ((HANDLE) (mutex->backend), 0);
15794a95
L
282 if (status != WAIT_OBJECT_0 && status != WAIT_ABANDONED)
283 return -1;
284 else
285 return 0;
286}
287
288/* Unlock the mutex */
289int
fc98f5cb 290__gthread_objc_mutex_unlock (objc_mutex_t mutex)
15794a95 291{
fc98f5cb 292 if (ReleaseMutex ((HANDLE) (mutex->backend)) == 0)
15794a95
L
293 return -1;
294 else
295 return 0;
296}
297
298/* Backend condition mutex functions */
299
71287280 300/* Allocate a condition. */
15794a95 301int
9149a5b7 302__gthread_objc_condition_allocate (objc_condition_t condition ATTRIBUTE_UNUSED)
15794a95 303{
71287280 304 /* Unimplemented. */
15794a95
L
305 return -1;
306}
307
71287280 308/* Deallocate a condition. */
15794a95 309int
9149a5b7 310__gthread_objc_condition_deallocate (objc_condition_t condition ATTRIBUTE_UNUSED)
15794a95 311{
71287280 312 /* Unimplemented. */
15794a95
L
313 return -1;
314}
315
316/* Wait on the condition */
317int
9149a5b7
EB
318__gthread_objc_condition_wait (objc_condition_t condition ATTRIBUTE_UNUSED,
319 objc_mutex_t mutex ATTRIBUTE_UNUSED)
15794a95 320{
71287280 321 /* Unimplemented. */
15794a95
L
322 return -1;
323}
324
71287280 325/* Wake up all threads waiting on this condition. */
15794a95 326int
9149a5b7 327__gthread_objc_condition_broadcast (objc_condition_t condition ATTRIBUTE_UNUSED)
15794a95 328{
71287280 329 /* Unimplemented. */
15794a95
L
330 return -1;
331}
332
71287280 333/* Wake up one thread waiting on this condition. */
15794a95 334int
9149a5b7 335__gthread_objc_condition_signal (objc_condition_t condition ATTRIBUTE_UNUSED)
15794a95 336{
71287280 337 /* Unimplemented. */
15794a95
L
338 return -1;
339}
340
341#else /* _LIBOBJC */
342
9149a5b7
EB
343/* For struct timespec. Do not include <sys/time.h> here since Gnulib provides
344 its own version which drags the Win32 API definitions. */
345#include <sys/timeb.h>
346
b25bb36a
DS
347#ifdef __cplusplus
348extern "C" {
349#endif
62dafdeb 350
9149a5b7
EB
351typedef unsigned int __gthr_win32_DWORD;
352typedef void *__gthr_win32_HANDLE;
62dafdeb
MK
353
354typedef struct {
9149a5b7
EB
355 void *DebugInfo;
356 int LockCount;
357 int RecursionCount;
358 __gthr_win32_HANDLE OwningThread;
359 __gthr_win32_HANDLE LockSemaphore;
360 void *SpinCount;
361} __gthr_win32_CRITICAL_SECTION;
62dafdeb 362
80408cac 363typedef struct {
9149a5b7
EB
364 void *Ptr;
365} __gthr_win32_CONDITION_VARIABLE;
366
367typedef __gthr_win32_HANDLE __gthread_t;
368typedef __gthr_win32_DWORD __gthread_key_t;
369typedef struct { int done; long started; } __gthread_once_t;
370typedef __gthr_win32_CRITICAL_SECTION __gthread_mutex_t;
371typedef __gthr_win32_CRITICAL_SECTION __gthread_recursive_mutex_t;
372#if __GTHREAD_HAS_COND
373typedef __gthr_win32_CONDITION_VARIABLE __gthread_cond_t;
374#endif
375typedef struct timespec __gthread_time_t;
40aac948 376
b25bb36a 377#define __GTHREAD_ONCE_INIT {0, -1}
62dafdeb 378#define __GTHREAD_MUTEX_INIT_FUNCTION __gthread_mutex_init_function
40219f96
WY
379#define __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION \
380 __gthread_recursive_mutex_init_function
9149a5b7
EB
381#define __GTHREAD_COND_INIT_FUNCTION __gthread_cond_init_function
382#define __GTHREAD_TIME_INIT {0, 0}
62dafdeb 383
e2fc12a5
JW
384// Libstdc++ std::basic_filebuf needs the old definition of __gthread_mutex_t
385// for layout purposes, but doesn't actually use it.
386typedef struct {
387 long __unused1;
388 void *__unused2;
389} __gthr_win32_legacy_mutex_t;
390#define __GTHREAD_LEGACY_MUTEX_T __gthr_win32_legacy_mutex_t
391
a1bda0d7 392#if defined (_WIN32) && !defined(__CYGWIN__)
f22a97d2 393#define MINGW32_SUPPORTS_MT_EH 1
cc2902df 394/* Mingw runtime >= v0.3 provides a magic variable that is set to nonzero
589005ff 395 if -mthreads option was specified, or 0 otherwise. This is to get around
f22a97d2
MK
396 the lack of weak symbols in PE-COFF. */
397extern int _CRT_MT;
b25bb36a 398extern int __mingwthr_key_dtor (unsigned long, void (*) (void *));
a1bda0d7 399#endif /* _WIN32 && !__CYGWIN__ */
f22a97d2 400
dcf8fe1e
JY
401/* __GTHR_W32_InterlockedCompareExchange is left over from win95,
402 which did not support InterlockedCompareExchange. */
42dfcf84 403#define __GTHR_W32_InterlockedCompareExchange InterlockedCompareExchange
42dfcf84 404
62dafdeb 405static inline int
d1e51320 406__gthread_active_p (void)
62dafdeb 407{
f22a97d2
MK
408#ifdef MINGW32_SUPPORTS_MT_EH
409 return _CRT_MT;
410#else
62dafdeb 411 return 1;
f22a97d2 412#endif
62dafdeb
MK
413}
414
9149a5b7
EB
415extern int __gthr_win32_create (__gthread_t *, void *(*) (void*), void *);
416extern int __gthr_win32_join (__gthread_t, void **);
417extern __gthread_t __gthr_win32_self (void);
b25bb36a 418extern int __gthr_win32_once (__gthread_once_t *, void (*) (void));
9149a5b7
EB
419extern int __gthr_win32_detach (__gthread_t);
420extern int __gthr_win32_equal (__gthread_t, __gthread_t);
421extern int __gthr_win32_yield (void);
b25bb36a
DS
422extern int __gthr_win32_key_create (__gthread_key_t *, void (*) (void*));
423extern int __gthr_win32_key_delete (__gthread_key_t);
424extern void * __gthr_win32_getspecific (__gthread_key_t);
425extern int __gthr_win32_setspecific (__gthread_key_t, const void *);
426extern void __gthr_win32_mutex_init_function (__gthread_mutex_t *);
9149a5b7 427extern void __gthr_win32_mutex_destroy (__gthread_mutex_t *);
b25bb36a
DS
428extern int __gthr_win32_mutex_lock (__gthread_mutex_t *);
429extern int __gthr_win32_mutex_trylock (__gthread_mutex_t *);
430extern int __gthr_win32_mutex_unlock (__gthread_mutex_t *);
9149a5b7
EB
431extern int __gthr_win32_recursive_mutex_trylock (__gthread_recursive_mutex_t *);
432#if __GTHREAD_HAS_COND
433extern void __gthr_win32_cond_init_function (__gthread_cond_t *);
434extern int __gthr_win32_cond_broadcast (__gthread_cond_t *);
435extern int __gthr_win32_cond_signal (__gthread_cond_t *);
436extern int __gthr_win32_cond_wait (__gthread_cond_t *, __gthread_mutex_t *);
437extern int __gthr_win32_cond_timedwait (__gthread_cond_t *, __gthread_mutex_t *,
438 const __gthread_time_t *);
439#endif
440
441static inline int
442__gthread_create (__gthread_t *__thr, void *(*__func) (void*),
443 void *__args)
444{
445 return __gthr_win32_create (__thr, __func, __args);
446}
447
448static inline int
449__gthread_join (__gthread_t __thr, void **__value_ptr)
450{
451 return __gthr_win32_join (__thr, __value_ptr);
452}
453
454static inline __gthread_t
455__gthread_self (void)
456{
457 return __gthr_win32_self ();
458}
459
460#if __GTHREAD_HIDE_WIN32API
461
462/* The implementations are in config/i386/gthr-win32.c in libgcc.a.
463 Only stubs are exposed to avoid polluting the C++ namespace with
464 Win32 API definitions. */
465
466static inline int
467__gthread_detach (__gthread_t __thr)
468{
469 return __gthr_win32_detach (__thr);
470}
471
472static inline int
473__gthread_equal (__gthread_t __thr1, __gthread_t __thr2)
474{
475 return __gthr_win32_equal (__thr1, __thr2);
476}
477
478static inline int
479__gthread_yield (void)
480{
481 return __gthr_win32_yield ();
482}
b25bb36a
DS
483
484static inline int
09e361bb 485__gthread_once (__gthread_once_t *__once, void (*__func) (void))
b25bb36a 486{
fc98f5cb 487 if (__gthread_active_p ())
09e361bb 488 return __gthr_win32_once (__once, __func);
b25bb36a 489 else
fc98f5cb 490 return -1;
b25bb36a
DS
491}
492
493static inline int
09e361bb 494__gthread_key_create (__gthread_key_t *__key, void (*__dtor) (void *))
b25bb36a 495{
09e361bb 496 return __gthr_win32_key_create (__key, __dtor);
b25bb36a
DS
497}
498
fc98f5cb 499static inline int
09e361bb 500__gthread_key_delete (__gthread_key_t __key)
b25bb36a 501{
09e361bb 502 return __gthr_win32_key_delete (__key);
b25bb36a
DS
503}
504
505static inline void *
09e361bb 506__gthread_getspecific (__gthread_key_t __key)
b25bb36a 507{
09e361bb 508 return __gthr_win32_getspecific (__key);
b25bb36a
DS
509}
510
511static inline int
09e361bb 512__gthread_setspecific (__gthread_key_t __key, const void *__ptr)
b25bb36a 513{
09e361bb 514 return __gthr_win32_setspecific (__key, __ptr);
b25bb36a
DS
515}
516
517static inline void
09e361bb 518__gthread_mutex_init_function (__gthread_mutex_t *__mutex)
b25bb36a 519{
09e361bb 520 __gthr_win32_mutex_init_function (__mutex);
b25bb36a
DS
521}
522
c262f705 523static inline void
09e361bb 524__gthread_mutex_destroy (__gthread_mutex_t *__mutex)
c262f705 525{
09e361bb 526 __gthr_win32_mutex_destroy (__mutex);
c262f705
DS
527}
528
b25bb36a 529static inline int
09e361bb 530__gthread_mutex_lock (__gthread_mutex_t *__mutex)
b25bb36a
DS
531{
532 if (__gthread_active_p ())
09e361bb 533 return __gthr_win32_mutex_lock (__mutex);
b25bb36a
DS
534 else
535 return 0;
536}
537
538static inline int
09e361bb 539__gthread_mutex_trylock (__gthread_mutex_t *__mutex)
b25bb36a
DS
540{
541 if (__gthread_active_p ())
09e361bb 542 return __gthr_win32_mutex_trylock (__mutex);
b25bb36a 543 else
fc98f5cb 544 return 0;
b25bb36a
DS
545}
546
547static inline int
09e361bb 548__gthread_mutex_unlock (__gthread_mutex_t *__mutex)
b25bb36a
DS
549{
550 if (__gthread_active_p ())
09e361bb 551 return __gthr_win32_mutex_unlock (__mutex);
b25bb36a 552 else
fc98f5cb 553 return 0;
b25bb36a
DS
554}
555
9149a5b7
EB
556static inline int
557__gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *__mutex)
558{
559 if (__gthread_active_p ())
560 return __gthr_win32_recursive_mutex_trylock (__mutex);
561 else
562 return 0;
563}
564
565#if __GTHREAD_HAS_COND
566
40219f96 567static inline void
9149a5b7 568__gthread_cond_init_function (__gthread_cond_t *__cond)
40219f96 569{
9149a5b7 570 __gthr_win32_cond_init_function (__cond);
40219f96
WY
571}
572
40aac948 573static inline int
9149a5b7 574__gthread_cond_broadcast (__gthread_cond_t *__cond)
40aac948 575{
9149a5b7 576 return __gthr_win32_cond_broadcast (__cond);
40aac948
JM
577}
578
579static inline int
9149a5b7 580__gthread_cond_signal (__gthread_cond_t *__cond)
40aac948 581{
9149a5b7 582 return __gthr_win32_cond_signal (__cond);
40aac948
JM
583}
584
585static inline int
9149a5b7 586__gthread_cond_wait (__gthread_cond_t *__cond, __gthread_mutex_t *__mutex)
40aac948 587{
9149a5b7 588 return __gthr_win32_cond_wait (__cond, __mutex);
40aac948
JM
589}
590
1504e3e1 591static inline int
9149a5b7
EB
592__gthread_cond_timedwait (__gthread_cond_t *__cond, __gthread_mutex_t *__mutex,
593 const __gthread_time_t *__abs_time)
1504e3e1 594{
9149a5b7 595 return __gthr_win32_cond_timedwait (__cond, __mutex, __abs_time);
1504e3e1
JW
596}
597
9149a5b7
EB
598#endif /* __GTHREAD_HAS_COND */
599
b25bb36a
DS
600#else /* ! __GTHREAD_HIDE_WIN32API */
601
9149a5b7
EB
602#ifndef __GTHREAD_WIN32_INLINE
603#define __GTHREAD_WIN32_INLINE static inline
604#endif
605
606#ifndef __GTHREAD_WIN32_COND_INLINE
607#define __GTHREAD_WIN32_COND_INLINE static inline
608#endif
609
610#ifndef __GTHREAD_WIN32_ACTIVE_P
611#define __GTHREAD_WIN32_ACTIVE_P __gthread_active_p
612#endif
613
614#define WIN32_LEAN_AND_MEAN
b25bb36a 615#include <windows.h>
339db340 616#undef CC_NONE
b25bb36a 617
9149a5b7
EB
618__GTHREAD_WIN32_INLINE int
619__gthread_detach (__gthread_t __thr)
620{
621 CloseHandle ((HANDLE) __thr);
622 return 0;
623}
624
625__GTHREAD_WIN32_INLINE int
626__gthread_equal (__gthread_t __t1, __gthread_t __t2)
627{
628 return GetThreadId ((HANDLE) __t1) == GetThreadId ((HANDLE) __t2);
629}
630
631__GTHREAD_WIN32_INLINE int
632__gthread_yield (void)
633{
634 Sleep (0);
635 return 0;
636}
637
638__GTHREAD_WIN32_INLINE int
09e361bb 639__gthread_once (__gthread_once_t *__once, void (*__func) (void))
62dafdeb 640{
9149a5b7 641 if (!__GTHREAD_WIN32_ACTIVE_P ())
62dafdeb 642 return -1;
62dafdeb 643
9149a5b7 644 if (__builtin_expect (!__once->done, 0))
62dafdeb 645 {
9149a5b7
EB
646 /* We rely on the memory model of the x86 architecture where every load
647 has acquire semantics and every store has release semantics. */
648 if (__atomic_add_fetch (&__once->started, 1, __ATOMIC_ACQ_REL) == 0)
589005ff 649 {
09e361bb 650 (*__func) ();
9149a5b7 651 __once->done = 1;
62dafdeb 652 }
f22a97d2
MK
653 else
654 {
589005ff 655 /* Another thread is currently executing the code, so wait for it
9149a5b7 656 to finish and yield the CPU in the meantime. If performance
589005ff
KH
657 does become an issue, the solution is to use an Event that
658 we wait on here (and set above), but that implies a place to
659 create the event before this routine is called. */
9149a5b7
EB
660 while (!__once->done)
661 __gthread_yield ();
f22a97d2 662 }
62dafdeb 663 }
589005ff 664
62dafdeb
MK
665 return 0;
666}
667
9149a5b7 668/* Windows thread local keys don't support destructors; this leads to
589005ff 669 leaks, especially in threaded applications making extensive use of
f22a97d2 670 C++ EH. Mingw uses a thread-support DLL to work-around this problem. */
9149a5b7 671__GTHREAD_WIN32_INLINE int
09e361bb 672__gthread_key_create (__gthread_key_t *__key,
9149a5b7 673 void (*__dtor) (void *) ATTRIBUTE_UNUSED)
62dafdeb 674{
09e361bb 675 DWORD __tls_index = TlsAlloc ();
9149a5b7 676 if (__tls_index != TLS_OUT_OF_INDEXES)
f22a97d2 677 {
09e361bb 678 *__key = __tls_index;
f22a97d2
MK
679#ifdef MINGW32_SUPPORTS_MT_EH
680 /* Mingw runtime will run the dtors in reverse order for each thread
681 when the thread exits. */
9149a5b7
EB
682 return __mingwthr_key_dtor (*__key, __dtor);
683#else
684 return 0;
f22a97d2
MK
685#endif
686 }
62dafdeb 687 else
9149a5b7 688 return (int) GetLastError ();
62dafdeb
MK
689}
690
9149a5b7 691__GTHREAD_WIN32_INLINE int
09e361bb 692__gthread_key_delete (__gthread_key_t __key)
62dafdeb 693{
9149a5b7
EB
694 if (TlsFree (__key))
695 return 0;
696 else
697 return (int) GetLastError ();
62dafdeb
MK
698}
699
9149a5b7 700__GTHREAD_WIN32_INLINE void *
09e361bb 701__gthread_getspecific (__gthread_key_t __key)
62dafdeb 702{
9149a5b7
EB
703 DWORD __lasterror = GetLastError ();
704 void *__ptr = TlsGetValue (__key);
09e361bb 705 SetLastError (__lasterror);
09e361bb 706 return __ptr;
62dafdeb
MK
707}
708
9149a5b7 709__GTHREAD_WIN32_INLINE int
09e361bb 710__gthread_setspecific (__gthread_key_t __key, const void *__ptr)
62dafdeb 711{
9149a5b7 712 if (TlsSetValue (__key, CONST_CAST2(void *, const void *, __ptr)))
fea16f81
DS
713 return 0;
714 else
9149a5b7 715 return (int) GetLastError ();
62dafdeb
MK
716}
717
9149a5b7 718__GTHREAD_WIN32_INLINE void
09e361bb 719__gthread_mutex_init_function (__gthread_mutex_t *__mutex)
62dafdeb 720{
9149a5b7 721 InitializeCriticalSection ((LPCRITICAL_SECTION) __mutex);
62dafdeb
MK
722}
723
9149a5b7 724__GTHREAD_WIN32_INLINE void
09e361bb 725__gthread_mutex_destroy (__gthread_mutex_t *__mutex)
ef4195d6 726{
9149a5b7 727 DeleteCriticalSection ((LPCRITICAL_SECTION) __mutex);
ef4195d6
JD
728}
729
9149a5b7 730__GTHREAD_WIN32_INLINE int
09e361bb 731__gthread_mutex_lock (__gthread_mutex_t *__mutex)
62dafdeb 732{
9149a5b7
EB
733 if (__GTHREAD_WIN32_ACTIVE_P ())
734 EnterCriticalSection ((LPCRITICAL_SECTION) __mutex);
735 return 0;
736}
62dafdeb 737
9149a5b7
EB
738__GTHREAD_WIN32_INLINE int
739__gthread_mutex_trylock (__gthread_mutex_t *__mutex)
740{
741 if (__GTHREAD_WIN32_ACTIVE_P ())
62dafdeb 742 {
9149a5b7
EB
743 BOOL __ret = TryEnterCriticalSection ((LPCRITICAL_SECTION) __mutex);
744 if (__ret)
80408cac 745 {
9149a5b7
EB
746 if (__mutex->RecursionCount > 1)
747 {
748 LeaveCriticalSection ((LPCRITICAL_SECTION) __mutex);
749 return 1;
750 }
751 else
752 return 0;
80408cac 753 }
9149a5b7
EB
754 else
755 return 1;
62dafdeb 756 }
9149a5b7
EB
757 else
758 return 0;
62dafdeb
MK
759}
760
9149a5b7
EB
761__GTHREAD_WIN32_INLINE int
762__gthread_mutex_unlock (__gthread_mutex_t *__mutex)
62dafdeb 763{
9149a5b7
EB
764 if (__GTHREAD_WIN32_ACTIVE_P ())
765 LeaveCriticalSection ((LPCRITICAL_SECTION) __mutex);
766 return 0;
767}
62dafdeb 768
9149a5b7
EB
769__GTHREAD_WIN32_INLINE int
770__gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *__mutex)
771{
772 if (__GTHREAD_WIN32_ACTIVE_P ())
773 return TryEnterCriticalSection ((LPCRITICAL_SECTION) __mutex) ? 0 : 1;
774 else
775 return 0;
62dafdeb
MK
776}
777
9149a5b7
EB
778#if __GTHREAD_HAS_COND
779
780__GTHREAD_WIN32_COND_INLINE void
781__gthread_cond_init_function (__gthread_cond_t *__cond)
62dafdeb 782{
9149a5b7
EB
783 InitializeConditionVariable ((PCONDITION_VARIABLE) __cond);
784}
785
786__GTHREAD_WIN32_COND_INLINE int
787__gthread_cond_broadcast (__gthread_cond_t *__cond)
788{
789 WakeAllConditionVariable ((PCONDITION_VARIABLE) __cond);
80408cac 790 return 0;
62dafdeb
MK
791}
792
9149a5b7
EB
793__GTHREAD_WIN32_COND_INLINE int
794__gthread_cond_signal (__gthread_cond_t *__cond)
795{
796 WakeConditionVariable ((PCONDITION_VARIABLE) __cond);
797 return 0;
798}
799
800__GTHREAD_WIN32_COND_INLINE int
801__gthread_cond_wait (__gthread_cond_t *__cond, __gthread_mutex_t *__mutex)
802{
803 if (SleepConditionVariableCS ((PCONDITION_VARIABLE) __cond,
804 (PCRITICAL_SECTION) __mutex,
805 INFINITE))
806 return 0;
807 else
808 return (int) GetLastError ();
809}
810
811extern DWORD __gthr_win32_abs_to_rel_time (const __gthread_time_t *);
812
813__GTHREAD_WIN32_COND_INLINE int
814__gthread_cond_timedwait (__gthread_cond_t *__cond,
815 __gthread_mutex_t *__mutex,
816 const __gthread_time_t *__abs_time)
817{
818 DWORD __rel_time = __gthr_win32_abs_to_rel_time (__abs_time);
819 if (SleepConditionVariableCS ((PCONDITION_VARIABLE) __cond,
820 (PCRITICAL_SECTION) __mutex,
821 __rel_time))
822 return 0;
823 else
824 return (int) GetLastError ();
825}
826
827#endif /* __GTHREAD_HAS_COND */
828
829#endif /* __GTHREAD_HIDE_WIN32API */
830
40aac948 831static inline void
09e361bb 832__gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *__mutex)
40aac948 833{
9149a5b7 834 __gthread_mutex_init_function (__mutex);
40aac948
JM
835}
836
9149a5b7
EB
837static inline void
838__gthread_recursive_mutex_destroy (__gthread_recursive_mutex_t *__mutex)
40aac948 839{
9149a5b7 840 __gthread_mutex_destroy (__mutex);
40aac948
JM
841}
842
843static inline int
9149a5b7 844__gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *__mutex)
40aac948 845{
9149a5b7 846 return __gthread_mutex_lock (__mutex);
40aac948
JM
847}
848
849static inline int
09e361bb 850__gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *__mutex)
40aac948 851{
9149a5b7
EB
852 return __gthread_mutex_unlock (__mutex);
853}
40aac948 854
9149a5b7
EB
855#if __GTHREAD_HAS_COND
856
857static inline int
858__gthread_cond_destroy (__gthread_cond_t *__cond ATTRIBUTE_UNUSED)
859{
40aac948
JM
860 return 0;
861}
862
1504e3e1 863static inline int
9149a5b7
EB
864__gthread_cond_wait_recursive (__gthread_cond_t *__cond,
865 __gthread_recursive_mutex_t *__mutex)
1504e3e1 866{
9149a5b7 867 return __gthread_cond_wait (__cond, __mutex);
1504e3e1
JW
868}
869
9149a5b7 870#endif
b25bb36a
DS
871
872#ifdef __cplusplus
873}
874#endif
875
15794a95
L
876#endif /* _LIBOBJC */
877
88657302 878#endif /* ! GCC_GTHR_WIN32_H */