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