]>
Commit | Line | Data |
---|---|---|
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 | 8 | This file is part of GCC. |
62dafdeb | 9 | |
1322177d LB |
10 | GCC is free software; you can redistribute it and/or modify it under |
11 | the terms of the GNU General Public License as published by the Free | |
748086b7 | 12 | Software Foundation; either version 3, or (at your option) any later |
1322177d | 13 | version. |
62dafdeb | 14 | |
1322177d LB |
15 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
16 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
17 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
18 | for more details. | |
62dafdeb | 19 | |
748086b7 JJ |
20 | Under Section 7 of GPL version 3, you are granted additional |
21 | permissions described in the GCC Runtime Library Exception, version | |
22 | 3.1, as published by the Free Software Foundation. | |
23 | ||
24 | You should have received a copy of the GNU General Public License and | |
25 | a copy of the GCC Runtime Library Exception along with this program; | |
26 | see 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 | 87 | static DWORD __gthread_objc_data_tls = (DWORD) -1; |
15794a95 L |
88 | |
89 | /* Backend initialization functions */ | |
90 | ||
71287280 | 91 | /* Initialize the threads subsystem. */ |
15794a95 | 92 | int |
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 | 103 | int |
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 | 114 | objc_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 | 128 | int |
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 | 155 | int |
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 | 184 | void |
fc98f5cb | 185 | __gthread_objc_thread_yield (void) |
15794a95 | 186 | { |
fc98f5cb | 187 | Sleep (0); |
15794a95 L |
188 | } |
189 | ||
71287280 | 190 | /* Terminate the current thread. */ |
15794a95 | 191 | int |
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 | 202 | objc_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 | 209 | int |
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 | 219 | void * |
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 | 237 | int |
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 | 247 | int |
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 | 255 | int |
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 | 268 | int |
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 */ | |
281 | int | |
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 | 293 | int |
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 | 301 | int |
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 */ | |
309 | int | |
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 | 317 | int |
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 | 325 | int |
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 |
335 | extern "C" { | |
336 | #endif | |
62dafdeb | 337 | |
b25bb36a | 338 | typedef unsigned long __gthread_key_t; |
62dafdeb MK |
339 | |
340 | typedef struct { | |
341 | int done; | |
342 | long started; | |
343 | } __gthread_once_t; | |
344 | ||
80408cac WY |
345 | typedef struct { |
346 | long counter; | |
347 | void *sema; | |
348 | } __gthread_mutex_t; | |
62dafdeb | 349 | |
40aac948 JM |
350 | typedef 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. */ |
370 | extern int _CRT_MT; | |
b25bb36a DS |
371 | extern 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 | |
380 | static 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 | 397 | static 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 | ||
413 | extern int __gthr_win32_once (__gthread_once_t *, void (*) (void)); | |
414 | extern int __gthr_win32_key_create (__gthread_key_t *, void (*) (void*)); | |
415 | extern int __gthr_win32_key_delete (__gthread_key_t); | |
416 | extern void * __gthr_win32_getspecific (__gthread_key_t); | |
417 | extern int __gthr_win32_setspecific (__gthread_key_t, const void *); | |
418 | extern void __gthr_win32_mutex_init_function (__gthread_mutex_t *); | |
419 | extern int __gthr_win32_mutex_lock (__gthread_mutex_t *); | |
420 | extern int __gthr_win32_mutex_trylock (__gthread_mutex_t *); | |
421 | extern int __gthr_win32_mutex_unlock (__gthread_mutex_t *); | |
40219f96 WY |
422 | extern void |
423 | __gthr_win32_recursive_mutex_init_function (__gthread_recursive_mutex_t *); | |
424 | extern int __gthr_win32_recursive_mutex_lock (__gthread_recursive_mutex_t *); | |
425 | extern int | |
426 | __gthr_win32_recursive_mutex_trylock (__gthread_recursive_mutex_t *); | |
427 | extern int __gthr_win32_recursive_mutex_unlock (__gthread_recursive_mutex_t *); | |
c262f705 | 428 | extern void __gthr_win32_mutex_destroy (__gthread_mutex_t *); |
b25bb36a DS |
429 | |
430 | static 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 | ||
439 | static 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 | 445 | static 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 | ||
451 | static inline void * | |
09e361bb | 452 | __gthread_getspecific (__gthread_key_t __key) |
b25bb36a | 453 | { |
09e361bb | 454 | return __gthr_win32_getspecific (__key); |
b25bb36a DS |
455 | } |
456 | ||
457 | static 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 | ||
463 | static 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 | 469 | static 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 | 475 | static 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 | ||
484 | static 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 | ||
493 | static 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 | 502 | static 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 | 508 | static 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 | ||
517 | static 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 | ||
526 | static 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 | 540 | static 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 | 573 | static 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 | 593 | static 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 | ||
599 | static 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 | ||
614 | static 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 | ||
623 | static 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 | 630 | static inline void |
09e361bb | 631 | __gthread_mutex_destroy (__gthread_mutex_t *__mutex) |
ef4195d6 | 632 | { |
09e361bb | 633 | CloseHandle ((HANDLE) __mutex->sema); |
ef4195d6 JD |
634 | } |
635 | ||
62dafdeb | 636 | static 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 | ||
657 | static 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 | ||
672 | static 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 | 683 | static 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 | ||
692 | static 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 | ||
724 | static 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 | ||
743 | static 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 */ |