2008-08-17 Paul Thomas <pault@gcc.gnu.org>
[official-gcc.git] / gcc / gthr-win32.h
blob74ac6179c2c44cd4ce8c5f19bc6d2fb795261af8
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 #ifdef _LIBOBJC
77 /* This is necessary to prevent windef.h (included from windows.h) from
78 defining its own BOOL as a typedef. */
79 #ifndef __OBJC__
80 #define __OBJC__
81 #endif
82 #include <windows.h>
83 /* Now undef the windows BOOL. */
84 #undef BOOL
86 /* Key structure for maintaining thread specific storage */
87 static DWORD __gthread_objc_data_tls = (DWORD) -1;
89 /* Backend initialization functions */
91 /* Initialize the threads subsystem. */
92 int
93 __gthread_objc_init_thread_system (void)
95 /* Initialize the thread storage key. */
96 if ((__gthread_objc_data_tls = TlsAlloc ()) != (DWORD) -1)
97 return 0;
98 else
99 return -1;
102 /* Close the threads subsystem. */
104 __gthread_objc_close_thread_system (void)
106 if (__gthread_objc_data_tls != (DWORD) -1)
107 TlsFree (__gthread_objc_data_tls);
108 return 0;
111 /* Backend thread functions */
113 /* Create a new thread of execution. */
114 objc_thread_t
115 __gthread_objc_thread_detach (void (*func)(void *arg), void *arg)
117 DWORD thread_id = 0;
118 HANDLE win32_handle;
120 if (!(win32_handle = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) func,
121 arg, 0, &thread_id)))
122 thread_id = 0;
124 return (objc_thread_t) thread_id;
127 /* Set the current thread's priority. */
129 __gthread_objc_thread_set_priority (int priority)
131 int sys_priority = 0;
133 switch (priority)
135 case OBJC_THREAD_INTERACTIVE_PRIORITY:
136 sys_priority = THREAD_PRIORITY_NORMAL;
137 break;
138 default:
139 case OBJC_THREAD_BACKGROUND_PRIORITY:
140 sys_priority = THREAD_PRIORITY_BELOW_NORMAL;
141 break;
142 case OBJC_THREAD_LOW_PRIORITY:
143 sys_priority = THREAD_PRIORITY_LOWEST;
144 break;
147 /* Change priority */
148 if (SetThreadPriority (GetCurrentThread (), sys_priority))
149 return 0;
150 else
151 return -1;
154 /* Return the current thread's priority. */
156 __gthread_objc_thread_get_priority (void)
158 int sys_priority;
160 sys_priority = GetThreadPriority (GetCurrentThread ());
162 switch (sys_priority)
164 case THREAD_PRIORITY_HIGHEST:
165 case THREAD_PRIORITY_TIME_CRITICAL:
166 case THREAD_PRIORITY_ABOVE_NORMAL:
167 case THREAD_PRIORITY_NORMAL:
168 return OBJC_THREAD_INTERACTIVE_PRIORITY;
170 default:
171 case THREAD_PRIORITY_BELOW_NORMAL:
172 return OBJC_THREAD_BACKGROUND_PRIORITY;
174 case THREAD_PRIORITY_IDLE:
175 case THREAD_PRIORITY_LOWEST:
176 return OBJC_THREAD_LOW_PRIORITY;
179 /* Couldn't get priority. */
180 return -1;
183 /* Yield our process time to another thread. */
184 void
185 __gthread_objc_thread_yield (void)
187 Sleep (0);
190 /* Terminate the current thread. */
192 __gthread_objc_thread_exit (void)
194 /* exit the thread */
195 ExitThread (__objc_thread_exit_status);
197 /* Failed if we reached here */
198 return -1;
201 /* Returns an integer value which uniquely describes a thread. */
202 objc_thread_t
203 __gthread_objc_thread_id (void)
205 return (objc_thread_t) GetCurrentThreadId ();
208 /* Sets the thread's local storage pointer. */
210 __gthread_objc_thread_set_data (void *value)
212 if (TlsSetValue (__gthread_objc_data_tls, value))
213 return 0;
214 else
215 return -1;
218 /* Returns the thread's local storage pointer. */
219 void *
220 __gthread_objc_thread_get_data (void)
222 DWORD lasterror;
223 void *ptr;
225 lasterror = GetLastError ();
227 ptr = TlsGetValue (__gthread_objc_data_tls); /* Return thread data. */
229 SetLastError (lasterror);
231 return ptr;
234 /* Backend mutex functions */
236 /* Allocate a mutex. */
238 __gthread_objc_mutex_allocate (objc_mutex_t mutex)
240 if ((mutex->backend = (void *) CreateMutex (NULL, 0, NULL)) == NULL)
241 return -1;
242 else
243 return 0;
246 /* Deallocate a mutex. */
248 __gthread_objc_mutex_deallocate (objc_mutex_t mutex)
250 CloseHandle ((HANDLE) (mutex->backend));
251 return 0;
254 /* Grab a lock on a mutex. */
256 __gthread_objc_mutex_lock (objc_mutex_t mutex)
258 int status;
260 status = WaitForSingleObject ((HANDLE) (mutex->backend), INFINITE);
261 if (status != WAIT_OBJECT_0 && status != WAIT_ABANDONED)
262 return -1;
263 else
264 return 0;
267 /* Try to grab a lock on a mutex. */
269 __gthread_objc_mutex_trylock (objc_mutex_t mutex)
271 int status;
273 status = WaitForSingleObject ((HANDLE) (mutex->backend), 0);
274 if (status != WAIT_OBJECT_0 && status != WAIT_ABANDONED)
275 return -1;
276 else
277 return 0;
280 /* Unlock the mutex */
282 __gthread_objc_mutex_unlock (objc_mutex_t mutex)
284 if (ReleaseMutex ((HANDLE) (mutex->backend)) == 0)
285 return -1;
286 else
287 return 0;
290 /* Backend condition mutex functions */
292 /* Allocate a condition. */
294 __gthread_objc_condition_allocate (objc_condition_t condition)
296 /* Unimplemented. */
297 return -1;
300 /* Deallocate a condition. */
302 __gthread_objc_condition_deallocate (objc_condition_t condition)
304 /* Unimplemented. */
305 return -1;
308 /* Wait on the condition */
310 __gthread_objc_condition_wait (objc_condition_t condition, objc_mutex_t mutex)
312 /* Unimplemented. */
313 return -1;
316 /* Wake up all threads waiting on this condition. */
318 __gthread_objc_condition_broadcast (objc_condition_t condition)
320 /* Unimplemented. */
321 return -1;
324 /* Wake up one thread waiting on this condition. */
326 __gthread_objc_condition_signal (objc_condition_t condition)
328 /* Unimplemented. */
329 return -1;
332 #else /* _LIBOBJC */
334 #ifdef __cplusplus
335 extern "C" {
336 #endif
338 typedef unsigned long __gthread_key_t;
340 typedef struct {
341 int done;
342 long started;
343 } __gthread_once_t;
345 typedef struct {
346 long counter;
347 void *sema;
348 } __gthread_mutex_t;
350 typedef struct {
351 long counter;
352 long depth;
353 unsigned long owner;
354 void *sema;
355 } __gthread_recursive_mutex_t;
357 #define __GTHREAD_ONCE_INIT {0, -1}
358 #define __GTHREAD_MUTEX_INIT_FUNCTION __gthread_mutex_init_function
359 #define __GTHREAD_MUTEX_INIT_DEFAULT {-1, 0}
360 #define __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION \
361 __gthread_recursive_mutex_init_function
362 #define __GTHREAD_RECURSIVE_MUTEX_INIT_DEFAULT {-1, 0, 0, 0}
364 #if defined (_WIN32) && !defined(__CYGWIN__)
365 #define MINGW32_SUPPORTS_MT_EH 1
366 /* Mingw runtime >= v0.3 provides a magic variable that is set to nonzero
367 if -mthreads option was specified, or 0 otherwise. This is to get around
368 the lack of weak symbols in PE-COFF. */
369 extern int _CRT_MT;
370 extern int __mingwthr_key_dtor (unsigned long, void (*) (void *));
371 #endif /* _WIN32 && !__CYGWIN__ */
373 /* The Windows95 kernel does not export InterlockedCompareExchange.
374 This provides a substitute. When building apps that reference
375 gthread_mutex_try_lock, the __GTHREAD_I486_INLINE_LOCK_PRIMITIVES
376 macro must be defined if Windows95 is a target. Currently
377 gthread_mutex_try_lock is not referenced by libgcc or libstdc++. */
378 #ifdef __GTHREAD_I486_INLINE_LOCK_PRIMITIVES
379 static inline long
380 __gthr_i486_lock_cmp_xchg(long *__dest, long __xchg, long __comperand)
382 long result;
383 __asm__ __volatile__ ("\n\
384 lock\n\
385 cmpxchg{l} {%4, %1|%1, %4}\n"
386 : "=a" (result), "=m" (*__dest)
387 : "0" (__comperand), "m" (*__dest), "r" (__xchg)
388 : "cc");
389 return result;
391 #define __GTHR_W32_InterlockedCompareExchange __gthr_i486_lock_cmp_xchg
392 #else /* __GTHREAD_I486_INLINE_LOCK_PRIMITIVES */
393 #define __GTHR_W32_InterlockedCompareExchange InterlockedCompareExchange
394 #endif /* __GTHREAD_I486_INLINE_LOCK_PRIMITIVES */
396 static inline int
397 __gthread_active_p (void)
399 #ifdef MINGW32_SUPPORTS_MT_EH
400 return _CRT_MT;
401 #else
402 return 1;
403 #endif
406 #if __GTHREAD_HIDE_WIN32API
408 /* The implementations are in config/i386/gthr-win32.c in libgcc.a.
409 Only stubs are exposed to avoid polluting the C++ namespace with
410 windows api definitions. */
412 extern int __gthr_win32_once (__gthread_once_t *, void (*) (void));
413 extern int __gthr_win32_key_create (__gthread_key_t *, void (*) (void*));
414 extern int __gthr_win32_key_delete (__gthread_key_t);
415 extern void * __gthr_win32_getspecific (__gthread_key_t);
416 extern int __gthr_win32_setspecific (__gthread_key_t, const void *);
417 extern void __gthr_win32_mutex_init_function (__gthread_mutex_t *);
418 extern int __gthr_win32_mutex_lock (__gthread_mutex_t *);
419 extern int __gthr_win32_mutex_trylock (__gthread_mutex_t *);
420 extern int __gthr_win32_mutex_unlock (__gthread_mutex_t *);
421 extern void
422 __gthr_win32_recursive_mutex_init_function (__gthread_recursive_mutex_t *);
423 extern int __gthr_win32_recursive_mutex_lock (__gthread_recursive_mutex_t *);
424 extern int
425 __gthr_win32_recursive_mutex_trylock (__gthread_recursive_mutex_t *);
426 extern int __gthr_win32_recursive_mutex_unlock (__gthread_recursive_mutex_t *);
427 extern void __gthr_win32_mutex_destroy (__gthread_mutex_t *);
429 static inline int
430 __gthread_once (__gthread_once_t *__once, void (*__func) (void))
432 if (__gthread_active_p ())
433 return __gthr_win32_once (__once, __func);
434 else
435 return -1;
438 static inline int
439 __gthread_key_create (__gthread_key_t *__key, void (*__dtor) (void *))
441 return __gthr_win32_key_create (__key, __dtor);
444 static inline int
445 __gthread_key_delete (__gthread_key_t __key)
447 return __gthr_win32_key_delete (__key);
450 static inline void *
451 __gthread_getspecific (__gthread_key_t __key)
453 return __gthr_win32_getspecific (__key);
456 static inline int
457 __gthread_setspecific (__gthread_key_t __key, const void *__ptr)
459 return __gthr_win32_setspecific (__key, __ptr);
462 static inline void
463 __gthread_mutex_init_function (__gthread_mutex_t *__mutex)
465 __gthr_win32_mutex_init_function (__mutex);
468 static inline void
469 __gthread_mutex_destroy (__gthread_mutex_t *__mutex)
471 __gthr_win32_mutex_destroy (__mutex);
474 static inline int
475 __gthread_mutex_lock (__gthread_mutex_t *__mutex)
477 if (__gthread_active_p ())
478 return __gthr_win32_mutex_lock (__mutex);
479 else
480 return 0;
483 static inline int
484 __gthread_mutex_trylock (__gthread_mutex_t *__mutex)
486 if (__gthread_active_p ())
487 return __gthr_win32_mutex_trylock (__mutex);
488 else
489 return 0;
492 static inline int
493 __gthread_mutex_unlock (__gthread_mutex_t *__mutex)
495 if (__gthread_active_p ())
496 return __gthr_win32_mutex_unlock (__mutex);
497 else
498 return 0;
501 static inline void
502 __gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *__mutex)
504 __gthr_win32_recursive_mutex_init_function (__mutex);
507 static inline int
508 __gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *__mutex)
510 if (__gthread_active_p ())
511 return __gthr_win32_recursive_mutex_lock (__mutex);
512 else
513 return 0;
516 static inline int
517 __gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *__mutex)
519 if (__gthread_active_p ())
520 return __gthr_win32_recursive_mutex_trylock (__mutex);
521 else
522 return 0;
525 static inline int
526 __gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *__mutex)
528 if (__gthread_active_p ())
529 return __gthr_win32_recursive_mutex_unlock (__mutex);
530 else
531 return 0;
534 #else /* ! __GTHREAD_HIDE_WIN32API */
536 #include <windows.h>
537 #include <errno.h>
539 static inline int
540 __gthread_once (__gthread_once_t *__once, void (*__func) (void))
542 if (! __gthread_active_p ())
543 return -1;
544 else if (__once == NULL || __func == NULL)
545 return EINVAL;
547 if (! __once->done)
549 if (InterlockedIncrement (&(__once->started)) == 0)
551 (*__func) ();
552 __once->done = TRUE;
554 else
556 /* Another thread is currently executing the code, so wait for it
557 to finish; yield the CPU in the meantime. If performance
558 does become an issue, the solution is to use an Event that
559 we wait on here (and set above), but that implies a place to
560 create the event before this routine is called. */
561 while (! __once->done)
562 Sleep (0);
566 return 0;
569 /* Windows32 thread local keys don't support destructors; this leads to
570 leaks, especially in threaded applications making extensive use of
571 C++ EH. Mingw uses a thread-support DLL to work-around this problem. */
572 static inline int
573 __gthread_key_create (__gthread_key_t *__key,
574 void (*__dtor) (void *) __attribute__((unused)))
576 int __status = 0;
577 DWORD __tls_index = TlsAlloc ();
578 if (__tls_index != 0xFFFFFFFF)
580 *__key = __tls_index;
581 #ifdef MINGW32_SUPPORTS_MT_EH
582 /* Mingw runtime will run the dtors in reverse order for each thread
583 when the thread exits. */
584 __status = __mingwthr_key_dtor (*__key, __dtor);
585 #endif
587 else
588 __status = (int) GetLastError ();
589 return __status;
592 static inline int
593 __gthread_key_delete (__gthread_key_t __key)
595 return (TlsFree (__key) != 0) ? 0 : (int) GetLastError ();
598 static inline void *
599 __gthread_getspecific (__gthread_key_t __key)
601 DWORD __lasterror;
602 void *__ptr;
604 __lasterror = GetLastError ();
606 __ptr = TlsGetValue (__key);
608 SetLastError (__lasterror);
610 return __ptr;
613 static inline int
614 __gthread_setspecific (__gthread_key_t __key, const void *__ptr)
616 if (TlsSetValue (__key, CONST_CAST2(void *, const void *, __ptr)) != 0)
617 return 0;
618 else
619 return GetLastError ();
622 static inline void
623 __gthread_mutex_init_function (__gthread_mutex_t *__mutex)
625 __mutex->counter = -1;
626 __mutex->sema = CreateSemaphore (NULL, 0, 65535, NULL);
629 static inline void
630 __gthread_mutex_destroy (__gthread_mutex_t *__mutex)
632 CloseHandle ((HANDLE) __mutex->sema);
635 static inline int
636 __gthread_mutex_lock (__gthread_mutex_t *__mutex)
638 int __status = 0;
640 if (__gthread_active_p ())
642 if (InterlockedIncrement (&__mutex->counter) == 0 ||
643 WaitForSingleObject (__mutex->sema, INFINITE) == WAIT_OBJECT_0)
644 __status = 0;
645 else
647 /* WaitForSingleObject returns WAIT_FAILED, and we can only do
648 some best-effort cleanup here. */
649 InterlockedDecrement (&__mutex->counter);
650 __status = 1;
653 return __status;
656 static inline int
657 __gthread_mutex_trylock (__gthread_mutex_t *__mutex)
659 int __status = 0;
661 if (__gthread_active_p ())
663 if (__GTHR_W32_InterlockedCompareExchange (&__mutex->counter, 0, -1) < 0)
664 __status = 0;
665 else
666 __status = 1;
668 return __status;
671 static inline int
672 __gthread_mutex_unlock (__gthread_mutex_t *__mutex)
674 if (__gthread_active_p ())
676 if (InterlockedDecrement (&__mutex->counter) >= 0)
677 return ReleaseSemaphore (__mutex->sema, 1, NULL) ? 0 : 1;
679 return 0;
682 static inline void
683 __gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *__mutex)
685 __mutex->counter = -1;
686 __mutex->depth = 0;
687 __mutex->owner = 0;
688 __mutex->sema = CreateSemaphore (NULL, 0, 65535, NULL);
691 static inline int
692 __gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *__mutex)
694 if (__gthread_active_p ())
696 DWORD __me = GetCurrentThreadId();
697 if (InterlockedIncrement (&__mutex->counter) == 0)
699 __mutex->depth = 1;
700 __mutex->owner = __me;
702 else if (__mutex->owner == __me)
704 InterlockedDecrement (&__mutex->counter);
705 ++(__mutex->depth);
707 else if (WaitForSingleObject (__mutex->sema, INFINITE) == WAIT_OBJECT_0)
709 __mutex->depth = 1;
710 __mutex->owner = __me;
712 else
714 /* WaitForSingleObject returns WAIT_FAILED, and we can only do
715 some best-effort cleanup here. */
716 InterlockedDecrement (&__mutex->counter);
717 return 1;
720 return 0;
723 static inline int
724 __gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *__mutex)
726 if (__gthread_active_p ())
728 DWORD __me = GetCurrentThreadId();
729 if (__GTHR_W32_InterlockedCompareExchange (&__mutex->counter, 0, -1) < 0)
731 __mutex->depth = 1;
732 __mutex->owner = __me;
734 else if (__mutex->owner == __me)
735 ++(__mutex->depth);
736 else
737 return 1;
739 return 0;
742 static inline int
743 __gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *__mutex)
745 if (__gthread_active_p ())
747 --(__mutex->depth);
748 if (__mutex->depth == 0)
750 __mutex->owner = 0;
752 if (InterlockedDecrement (&__mutex->counter) >= 0)
753 return ReleaseSemaphore (__mutex->sema, 1, NULL) ? 0 : 1;
756 return 0;
759 #endif /* __GTHREAD_HIDE_WIN32API */
761 #ifdef __cplusplus
763 #endif
765 #endif /* _LIBOBJC */
767 #endif /* ! GCC_GTHR_WIN32_H */