gcc/
[official-gcc.git] / gcc / gthr-win32.h
blob53f8396cc8135ae24e2be3eaa69647a9d5fc3a12
1 /* Threads compatibility routines for libgcc2 and libobjc. */
2 /* Compile this one with gcc. */
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>.
8 This file is part of GCC.
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.
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.
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.
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/>. */
29 #ifndef GCC_GTHR_WIN32_H
30 #define GCC_GTHR_WIN32_H
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
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.
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).
46 This memory leak may be significant for long-running applications
47 that make heavy use of C++ EH.
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.
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).
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).
65 The basic framework should work well enough. In the long term, GCC
66 needs to use Structured Exception Handling on Windows32. */
68 #define __GTHREADS 1
70 #include <errno.h>
71 #ifdef __MINGW32__
72 #include <_mingw.h>
73 #endif
75 #ifndef __UNUSED_PARAM
76 #define __UNUSED_PARAM(x) x
77 #endif
79 #ifdef _LIBOBJC
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
90 /* Key structure for maintaining thread specific storage */
91 static DWORD __gthread_objc_data_tls = (DWORD) -1;
93 /* Backend initialization functions */
95 /* Initialize the threads subsystem. */
96 int
97 __gthread_objc_init_thread_system (void)
99 /* Initialize the thread storage key. */
100 if ((__gthread_objc_data_tls = TlsAlloc ()) != (DWORD) -1)
101 return 0;
102 else
103 return -1;
106 /* Close the threads subsystem. */
108 __gthread_objc_close_thread_system (void)
110 if (__gthread_objc_data_tls != (DWORD) -1)
111 TlsFree (__gthread_objc_data_tls);
112 return 0;
115 /* Backend thread functions */
117 /* Create a new thread of execution. */
118 objc_thread_t
119 __gthread_objc_thread_detach (void (*func)(void *arg), void *arg)
121 DWORD thread_id = 0;
122 HANDLE win32_handle;
124 if (!(win32_handle = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) func,
125 arg, 0, &thread_id)))
126 thread_id = 0;
128 return (objc_thread_t) (INT_PTR) thread_id;
131 /* Set the current thread's priority. */
133 __gthread_objc_thread_set_priority (int priority)
135 int sys_priority = 0;
137 switch (priority)
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;
151 /* Change priority */
152 if (SetThreadPriority (GetCurrentThread (), sys_priority))
153 return 0;
154 else
155 return -1;
158 /* Return the current thread's priority. */
160 __gthread_objc_thread_get_priority (void)
162 int sys_priority;
164 sys_priority = GetThreadPriority (GetCurrentThread ());
166 switch (sys_priority)
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;
174 default:
175 case THREAD_PRIORITY_BELOW_NORMAL:
176 return OBJC_THREAD_BACKGROUND_PRIORITY;
178 case THREAD_PRIORITY_IDLE:
179 case THREAD_PRIORITY_LOWEST:
180 return OBJC_THREAD_LOW_PRIORITY;
183 /* Couldn't get priority. */
184 return -1;
187 /* Yield our process time to another thread. */
188 void
189 __gthread_objc_thread_yield (void)
191 Sleep (0);
194 /* Terminate the current thread. */
196 __gthread_objc_thread_exit (void)
198 /* exit the thread */
199 ExitThread (__objc_thread_exit_status);
201 /* Failed if we reached here */
202 return -1;
205 /* Returns an integer value which uniquely describes a thread. */
206 objc_thread_t
207 __gthread_objc_thread_id (void)
209 return (objc_thread_t) (INT_PTR) GetCurrentThreadId ();
212 /* Sets the thread's local storage pointer. */
214 __gthread_objc_thread_set_data (void *value)
216 if (TlsSetValue (__gthread_objc_data_tls, value))
217 return 0;
218 else
219 return -1;
222 /* Returns the thread's local storage pointer. */
223 void *
224 __gthread_objc_thread_get_data (void)
226 DWORD lasterror;
227 void *ptr;
229 lasterror = GetLastError ();
231 ptr = TlsGetValue (__gthread_objc_data_tls); /* Return thread data. */
233 SetLastError (lasterror);
235 return ptr;
238 /* Backend mutex functions */
240 /* Allocate a mutex. */
242 __gthread_objc_mutex_allocate (objc_mutex_t mutex)
244 if ((mutex->backend = (void *) CreateMutex (NULL, 0, NULL)) == NULL)
245 return -1;
246 else
247 return 0;
250 /* Deallocate a mutex. */
252 __gthread_objc_mutex_deallocate (objc_mutex_t mutex)
254 CloseHandle ((HANDLE) (mutex->backend));
255 return 0;
258 /* Grab a lock on a mutex. */
260 __gthread_objc_mutex_lock (objc_mutex_t mutex)
262 int status;
264 status = WaitForSingleObject ((HANDLE) (mutex->backend), INFINITE);
265 if (status != WAIT_OBJECT_0 && status != WAIT_ABANDONED)
266 return -1;
267 else
268 return 0;
271 /* Try to grab a lock on a mutex. */
273 __gthread_objc_mutex_trylock (objc_mutex_t mutex)
275 int status;
277 status = WaitForSingleObject ((HANDLE) (mutex->backend), 0);
278 if (status != WAIT_OBJECT_0 && status != WAIT_ABANDONED)
279 return -1;
280 else
281 return 0;
284 /* Unlock the mutex */
286 __gthread_objc_mutex_unlock (objc_mutex_t mutex)
288 if (ReleaseMutex ((HANDLE) (mutex->backend)) == 0)
289 return -1;
290 else
291 return 0;
294 /* Backend condition mutex functions */
296 /* Allocate a condition. */
298 __gthread_objc_condition_allocate (objc_condition_t __UNUSED_PARAM(condition))
300 /* Unimplemented. */
301 return -1;
304 /* Deallocate a condition. */
306 __gthread_objc_condition_deallocate (objc_condition_t __UNUSED_PARAM(condition))
308 /* Unimplemented. */
309 return -1;
312 /* Wait on the condition */
314 __gthread_objc_condition_wait (objc_condition_t __UNUSED_PARAM(condition),
315 objc_mutex_t __UNUSED_PARAM(mutex))
317 /* Unimplemented. */
318 return -1;
321 /* Wake up all threads waiting on this condition. */
323 __gthread_objc_condition_broadcast (objc_condition_t __UNUSED_PARAM(condition))
325 /* Unimplemented. */
326 return -1;
329 /* Wake up one thread waiting on this condition. */
331 __gthread_objc_condition_signal (objc_condition_t __UNUSED_PARAM(condition))
333 /* Unimplemented. */
334 return -1;
337 #else /* _LIBOBJC */
339 #ifdef __cplusplus
340 extern "C" {
341 #endif
343 typedef unsigned long __gthread_key_t;
345 typedef struct {
346 int done;
347 long started;
348 } __gthread_once_t;
350 typedef struct {
351 long counter;
352 void *sema;
353 } __gthread_mutex_t;
355 typedef struct {
356 long counter;
357 long depth;
358 unsigned long owner;
359 void *sema;
360 } __gthread_recursive_mutex_t;
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}
369 #if defined (_WIN32) && !defined(__CYGWIN__)
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 *));
376 #endif /* _WIN32 && !__CYGWIN__ */
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)
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;
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 */
401 static inline int
402 __gthread_active_p (void)
404 #ifdef MINGW32_SUPPORTS_MT_EH
405 return _CRT_MT;
406 #else
407 return 1;
408 #endif
411 #if __GTHREAD_HIDE_WIN32API
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. */
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 *);
434 static inline int
435 __gthread_once (__gthread_once_t *__once, void (*__func) (void))
437 if (__gthread_active_p ())
438 return __gthr_win32_once (__once, __func);
439 else
440 return -1;
443 static inline int
444 __gthread_key_create (__gthread_key_t *__key, void (*__dtor) (void *))
446 return __gthr_win32_key_create (__key, __dtor);
449 static inline int
450 __gthread_key_delete (__gthread_key_t __key)
452 return __gthr_win32_key_delete (__key);
455 static inline void *
456 __gthread_getspecific (__gthread_key_t __key)
458 return __gthr_win32_getspecific (__key);
461 static inline int
462 __gthread_setspecific (__gthread_key_t __key, const void *__ptr)
464 return __gthr_win32_setspecific (__key, __ptr);
467 static inline void
468 __gthread_mutex_init_function (__gthread_mutex_t *__mutex)
470 __gthr_win32_mutex_init_function (__mutex);
473 static inline void
474 __gthread_mutex_destroy (__gthread_mutex_t *__mutex)
476 __gthr_win32_mutex_destroy (__mutex);
479 static inline int
480 __gthread_mutex_lock (__gthread_mutex_t *__mutex)
482 if (__gthread_active_p ())
483 return __gthr_win32_mutex_lock (__mutex);
484 else
485 return 0;
488 static inline int
489 __gthread_mutex_trylock (__gthread_mutex_t *__mutex)
491 if (__gthread_active_p ())
492 return __gthr_win32_mutex_trylock (__mutex);
493 else
494 return 0;
497 static inline int
498 __gthread_mutex_unlock (__gthread_mutex_t *__mutex)
500 if (__gthread_active_p ())
501 return __gthr_win32_mutex_unlock (__mutex);
502 else
503 return 0;
506 static inline void
507 __gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *__mutex)
509 __gthr_win32_recursive_mutex_init_function (__mutex);
512 static inline int
513 __gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *__mutex)
515 if (__gthread_active_p ())
516 return __gthr_win32_recursive_mutex_lock (__mutex);
517 else
518 return 0;
521 static inline int
522 __gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *__mutex)
524 if (__gthread_active_p ())
525 return __gthr_win32_recursive_mutex_trylock (__mutex);
526 else
527 return 0;
530 static inline int
531 __gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *__mutex)
533 if (__gthread_active_p ())
534 return __gthr_win32_recursive_mutex_unlock (__mutex);
535 else
536 return 0;
539 #else /* ! __GTHREAD_HIDE_WIN32API */
541 #include <windows.h>
542 #include <errno.h>
544 static inline int
545 __gthread_once (__gthread_once_t *__once, void (*__func) (void))
547 if (! __gthread_active_p ())
548 return -1;
549 else if (__once == NULL || __func == NULL)
550 return EINVAL;
552 if (! __once->done)
554 if (InterlockedIncrement (&(__once->started)) == 0)
556 (*__func) ();
557 __once->done = TRUE;
559 else
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);
571 return 0;
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)))
581 int __status = 0;
582 DWORD __tls_index = TlsAlloc ();
583 if (__tls_index != 0xFFFFFFFF)
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
592 else
593 __status = (int) GetLastError ();
594 return __status;
597 static inline int
598 __gthread_key_delete (__gthread_key_t __key)
600 return (TlsFree (__key) != 0) ? 0 : (int) GetLastError ();
603 static inline void *
604 __gthread_getspecific (__gthread_key_t __key)
606 DWORD __lasterror;
607 void *__ptr;
609 __lasterror = GetLastError ();
611 __ptr = TlsGetValue (__key);
613 SetLastError (__lasterror);
615 return __ptr;
618 static inline int
619 __gthread_setspecific (__gthread_key_t __key, const void *__ptr)
621 if (TlsSetValue (__key, CONST_CAST2(void *, const void *, __ptr)) != 0)
622 return 0;
623 else
624 return GetLastError ();
627 static inline void
628 __gthread_mutex_init_function (__gthread_mutex_t *__mutex)
630 __mutex->counter = -1;
631 __mutex->sema = CreateSemaphore (NULL, 0, 65535, NULL);
634 static inline void
635 __gthread_mutex_destroy (__gthread_mutex_t *__mutex)
637 CloseHandle ((HANDLE) __mutex->sema);
640 static inline int
641 __gthread_mutex_lock (__gthread_mutex_t *__mutex)
643 int __status = 0;
645 if (__gthread_active_p ())
647 if (InterlockedIncrement (&__mutex->counter) == 0 ||
648 WaitForSingleObject (__mutex->sema, INFINITE) == WAIT_OBJECT_0)
649 __status = 0;
650 else
652 /* WaitForSingleObject returns WAIT_FAILED, and we can only do
653 some best-effort cleanup here. */
654 InterlockedDecrement (&__mutex->counter);
655 __status = 1;
658 return __status;
661 static inline int
662 __gthread_mutex_trylock (__gthread_mutex_t *__mutex)
664 int __status = 0;
666 if (__gthread_active_p ())
668 if (__GTHR_W32_InterlockedCompareExchange (&__mutex->counter, 0, -1) < 0)
669 __status = 0;
670 else
671 __status = 1;
673 return __status;
676 static inline int
677 __gthread_mutex_unlock (__gthread_mutex_t *__mutex)
679 if (__gthread_active_p ())
681 if (InterlockedDecrement (&__mutex->counter) >= 0)
682 return ReleaseSemaphore (__mutex->sema, 1, NULL) ? 0 : 1;
684 return 0;
687 static inline void
688 __gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *__mutex)
690 __mutex->counter = -1;
691 __mutex->depth = 0;
692 __mutex->owner = 0;
693 __mutex->sema = CreateSemaphore (NULL, 0, 65535, NULL);
696 static inline int
697 __gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *__mutex)
699 if (__gthread_active_p ())
701 DWORD __me = GetCurrentThreadId();
702 if (InterlockedIncrement (&__mutex->counter) == 0)
704 __mutex->depth = 1;
705 __mutex->owner = __me;
707 else if (__mutex->owner == __me)
709 InterlockedDecrement (&__mutex->counter);
710 ++(__mutex->depth);
712 else if (WaitForSingleObject (__mutex->sema, INFINITE) == WAIT_OBJECT_0)
714 __mutex->depth = 1;
715 __mutex->owner = __me;
717 else
719 /* WaitForSingleObject returns WAIT_FAILED, and we can only do
720 some best-effort cleanup here. */
721 InterlockedDecrement (&__mutex->counter);
722 return 1;
725 return 0;
728 static inline int
729 __gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *__mutex)
731 if (__gthread_active_p ())
733 DWORD __me = GetCurrentThreadId();
734 if (__GTHR_W32_InterlockedCompareExchange (&__mutex->counter, 0, -1) < 0)
736 __mutex->depth = 1;
737 __mutex->owner = __me;
739 else if (__mutex->owner == __me)
740 ++(__mutex->depth);
741 else
742 return 1;
744 return 0;
747 static inline int
748 __gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *__mutex)
750 if (__gthread_active_p ())
752 --(__mutex->depth);
753 if (__mutex->depth == 0)
755 __mutex->owner = 0;
757 if (InterlockedDecrement (&__mutex->counter) >= 0)
758 return ReleaseSemaphore (__mutex->sema, 1, NULL) ? 0 : 1;
761 return 0;
764 #endif /* __GTHREAD_HIDE_WIN32API */
766 #ifdef __cplusplus
768 #endif
770 #endif /* _LIBOBJC */
772 #endif /* ! GCC_GTHR_WIN32_H */