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