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