]>
Commit | Line | Data |
---|---|---|
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 | 7 | This file is part of GCC. |
62dafdeb | 8 | |
1322177d LB |
9 | GCC is free software; you can redistribute it and/or modify it under |
10 | the terms of the GNU General Public License as published by the Free | |
748086b7 | 11 | Software Foundation; either version 3, or (at your option) any later |
1322177d | 12 | version. |
62dafdeb | 13 | |
1322177d LB |
14 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
15 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
16 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
17 | for more details. | |
62dafdeb | 18 | |
748086b7 JJ |
19 | Under Section 7 of GPL version 3, you are granted additional |
20 | permissions described in the GCC Runtime Library Exception, version | |
21 | 3.1, as published by the Free Software Foundation. | |
22 | ||
23 | You should have received a copy of the GNU General Public License and | |
24 | a copy of the GCC Runtime Library Exception along with this program; | |
25 | see 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 | 101 | static DWORD __gthread_objc_data_tls = TLS_OUT_OF_INDEXES; |
15794a95 L |
102 | |
103 | /* Backend initialization functions */ | |
104 | ||
71287280 | 105 | /* Initialize the threads subsystem. */ |
15794a95 | 106 | int |
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 | 117 | int |
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 | 128 | objc_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 | 142 | int |
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 | 169 | int |
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 | 198 | void |
fc98f5cb | 199 | __gthread_objc_thread_yield (void) |
15794a95 | 200 | { |
fc98f5cb | 201 | Sleep (0); |
15794a95 L |
202 | } |
203 | ||
71287280 | 204 | /* Terminate the current thread. */ |
15794a95 | 205 | int |
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 | 216 | objc_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 | 223 | int |
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 | 233 | void * |
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 | 245 | int |
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 | 255 | int |
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 | 263 | int |
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 | 276 | int |
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 */ | |
289 | int | |
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 | 301 | int |
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 | 309 | int |
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 */ | |
317 | int | |
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 | 326 | int |
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 | 334 | int |
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 |
348 | extern "C" { | |
349 | #endif | |
62dafdeb | 350 | |
9149a5b7 EB |
351 | typedef unsigned int __gthr_win32_DWORD; |
352 | typedef void *__gthr_win32_HANDLE; | |
62dafdeb MK |
353 | |
354 | typedef 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 | 363 | typedef struct { |
9149a5b7 EB |
364 | void *Ptr; |
365 | } __gthr_win32_CONDITION_VARIABLE; | |
366 | ||
367 | typedef __gthr_win32_HANDLE __gthread_t; | |
368 | typedef __gthr_win32_DWORD __gthread_key_t; | |
369 | typedef struct { int done; long started; } __gthread_once_t; | |
370 | typedef __gthr_win32_CRITICAL_SECTION __gthread_mutex_t; | |
371 | typedef __gthr_win32_CRITICAL_SECTION __gthread_recursive_mutex_t; | |
372 | #if __GTHREAD_HAS_COND | |
373 | typedef __gthr_win32_CONDITION_VARIABLE __gthread_cond_t; | |
374 | #endif | |
375 | typedef 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. | |
386 | typedef 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. */ |
397 | extern int _CRT_MT; | |
b25bb36a | 398 | extern 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 | 405 | static 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 |
415 | extern int __gthr_win32_create (__gthread_t *, void *(*) (void*), void *); |
416 | extern int __gthr_win32_join (__gthread_t, void **); | |
417 | extern __gthread_t __gthr_win32_self (void); | |
b25bb36a | 418 | extern int __gthr_win32_once (__gthread_once_t *, void (*) (void)); |
9149a5b7 EB |
419 | extern int __gthr_win32_detach (__gthread_t); |
420 | extern int __gthr_win32_equal (__gthread_t, __gthread_t); | |
421 | extern int __gthr_win32_yield (void); | |
b25bb36a DS |
422 | extern int __gthr_win32_key_create (__gthread_key_t *, void (*) (void*)); |
423 | extern int __gthr_win32_key_delete (__gthread_key_t); | |
424 | extern void * __gthr_win32_getspecific (__gthread_key_t); | |
425 | extern int __gthr_win32_setspecific (__gthread_key_t, const void *); | |
426 | extern void __gthr_win32_mutex_init_function (__gthread_mutex_t *); | |
9149a5b7 | 427 | extern void __gthr_win32_mutex_destroy (__gthread_mutex_t *); |
b25bb36a DS |
428 | extern int __gthr_win32_mutex_lock (__gthread_mutex_t *); |
429 | extern int __gthr_win32_mutex_trylock (__gthread_mutex_t *); | |
430 | extern int __gthr_win32_mutex_unlock (__gthread_mutex_t *); | |
9149a5b7 EB |
431 | extern int __gthr_win32_recursive_mutex_trylock (__gthread_recursive_mutex_t *); |
432 | #if __GTHREAD_HAS_COND | |
433 | extern void __gthr_win32_cond_init_function (__gthread_cond_t *); | |
434 | extern int __gthr_win32_cond_broadcast (__gthread_cond_t *); | |
435 | extern int __gthr_win32_cond_signal (__gthread_cond_t *); | |
436 | extern int __gthr_win32_cond_wait (__gthread_cond_t *, __gthread_mutex_t *); | |
437 | extern int __gthr_win32_cond_timedwait (__gthread_cond_t *, __gthread_mutex_t *, | |
438 | const __gthread_time_t *); | |
439 | #endif | |
440 | ||
441 | static 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 | ||
448 | static inline int | |
449 | __gthread_join (__gthread_t __thr, void **__value_ptr) | |
450 | { | |
451 | return __gthr_win32_join (__thr, __value_ptr); | |
452 | } | |
453 | ||
454 | static 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 | ||
466 | static inline int | |
467 | __gthread_detach (__gthread_t __thr) | |
468 | { | |
469 | return __gthr_win32_detach (__thr); | |
470 | } | |
471 | ||
472 | static inline int | |
473 | __gthread_equal (__gthread_t __thr1, __gthread_t __thr2) | |
474 | { | |
475 | return __gthr_win32_equal (__thr1, __thr2); | |
476 | } | |
477 | ||
478 | static inline int | |
479 | __gthread_yield (void) | |
480 | { | |
481 | return __gthr_win32_yield (); | |
482 | } | |
b25bb36a DS |
483 | |
484 | static 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 | ||
493 | static 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 | 499 | static 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 | ||
505 | static inline void * | |
09e361bb | 506 | __gthread_getspecific (__gthread_key_t __key) |
b25bb36a | 507 | { |
09e361bb | 508 | return __gthr_win32_getspecific (__key); |
b25bb36a DS |
509 | } |
510 | ||
511 | static 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 | ||
517 | static 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 | 523 | static 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 | 529 | static 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 | ||
538 | static 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 | ||
547 | static 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 |
556 | static 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 | 567 | static 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 | 573 | static 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 | ||
579 | static 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 | ||
585 | static 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 | 591 | static 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 | ||
811 | extern 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 | 831 | static 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 |
837 | static inline void |
838 | __gthread_recursive_mutex_destroy (__gthread_recursive_mutex_t *__mutex) | |
40aac948 | 839 | { |
9149a5b7 | 840 | __gthread_mutex_destroy (__mutex); |
40aac948 JM |
841 | } |
842 | ||
843 | static 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 | ||
849 | static 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 | ||
857 | static inline int | |
858 | __gthread_cond_destroy (__gthread_cond_t *__cond ATTRIBUTE_UNUSED) | |
859 | { | |
40aac948 JM |
860 | return 0; |
861 | } | |
862 | ||
1504e3e1 | 863 | static 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 */ |