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