Daily bump.
[official-gcc.git] / gcc / gthr-win32.h
blob6a32c1a134c022dffcf4418fd1db2265c89e0e81
1 /* Threads compatibility routines for libgcc2 and libobjc. */
2 /* Compile this one with gcc. */
4 /* Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005
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 2, 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 You should have received a copy of the GNU General Public License
21 along with GCC; see the file COPYING. If not, write to the Free
22 Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
23 02110-1301, USA. */
25 /* As a special exception, if you link this library with other files,
26 some of which are compiled with GCC, to produce an executable,
27 this library does not by itself cause the resulting executable
28 to be covered by the GNU General Public License.
29 This exception does not however invalidate any other reasons why
30 the executable file might be covered by the GNU General Public License. */
32 #ifndef GCC_GTHR_WIN32_H
33 #define GCC_GTHR_WIN32_H
35 /* Windows32 threads specific definitions. The windows32 threading model
36 does not map well into pthread-inspired gcc's threading model, and so
37 there are caveats one needs to be aware of.
39 1. The destructor supplied to __gthread_key_create is ignored for
40 generic x86-win32 ports. This will certainly cause memory leaks
41 due to unreclaimed eh contexts (sizeof (eh_context) is at least
42 24 bytes for x86 currently).
44 This memory leak may be significant for long-running applications
45 that make heavy use of C++ EH.
47 However, Mingw runtime (version 0.3 or newer) provides a mechanism
48 to emulate pthreads key dtors; the runtime provides a special DLL,
49 linked in if -mthreads option is specified, that runs the dtors in
50 the reverse order of registration when each thread exits. If
51 -mthreads option is not given, a stub is linked in instead of the
52 DLL, which results in memory leak. Other x86-win32 ports can use
53 the same technique of course to avoid the leak.
55 2. The error codes returned are non-POSIX like, and cast into ints.
56 This may cause incorrect error return due to truncation values on
57 hw where sizeof (DWORD) > sizeof (int).
59 3. We are currently using a special mutex instead of the Critical
60 Sections, since Win9x does not support TryEnterCriticalSection
61 (while NT does).
63 The basic framework should work well enough. In the long term, GCC
64 needs to use Structured Exception Handling on Windows32. */
66 #define __GTHREADS 1
68 #include <errno.h>
69 #ifdef __MINGW32__
70 #include <_mingw.h>
71 #endif
73 #ifdef _LIBOBJC
75 /* This is necessary to prevent windef.h (included from windows.h) from
76 defining its own BOOL as a typedef. */
77 #ifndef __OBJC__
78 #define __OBJC__
79 #endif
80 #include <windows.h>
81 /* Now undef the windows BOOL. */
82 #undef BOOL
84 /* Key structure for maintaining thread specific storage */
85 static DWORD __gthread_objc_data_tls = (DWORD) -1;
87 /* Backend initialization functions */
89 /* Initialize the threads subsystem. */
90 int
91 __gthread_objc_init_thread_system (void)
93 /* Initialize the thread storage key. */
94 if ((__gthread_objc_data_tls = TlsAlloc ()) != (DWORD) -1)
95 return 0;
96 else
97 return -1;
100 /* Close the threads subsystem. */
102 __gthread_objc_close_thread_system (void)
104 if (__gthread_objc_data_tls != (DWORD) -1)
105 TlsFree (__gthread_objc_data_tls);
106 return 0;
109 /* Backend thread functions */
111 /* Create a new thread of execution. */
112 objc_thread_t
113 __gthread_objc_thread_detach (void (*func)(void *arg), void *arg)
115 DWORD thread_id = 0;
116 HANDLE win32_handle;
118 if (!(win32_handle = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) func,
119 arg, 0, &thread_id)))
120 thread_id = 0;
122 return (objc_thread_t) thread_id;
125 /* Set the current thread's priority. */
127 __gthread_objc_thread_set_priority (int priority)
129 int sys_priority = 0;
131 switch (priority)
133 case OBJC_THREAD_INTERACTIVE_PRIORITY:
134 sys_priority = THREAD_PRIORITY_NORMAL;
135 break;
136 default:
137 case OBJC_THREAD_BACKGROUND_PRIORITY:
138 sys_priority = THREAD_PRIORITY_BELOW_NORMAL;
139 break;
140 case OBJC_THREAD_LOW_PRIORITY:
141 sys_priority = THREAD_PRIORITY_LOWEST;
142 break;
145 /* Change priority */
146 if (SetThreadPriority (GetCurrentThread (), sys_priority))
147 return 0;
148 else
149 return -1;
152 /* Return the current thread's priority. */
154 __gthread_objc_thread_get_priority (void)
156 int sys_priority;
158 sys_priority = GetThreadPriority (GetCurrentThread ());
160 switch (sys_priority)
162 case THREAD_PRIORITY_HIGHEST:
163 case THREAD_PRIORITY_TIME_CRITICAL:
164 case THREAD_PRIORITY_ABOVE_NORMAL:
165 case THREAD_PRIORITY_NORMAL:
166 return OBJC_THREAD_INTERACTIVE_PRIORITY;
168 default:
169 case THREAD_PRIORITY_BELOW_NORMAL:
170 return OBJC_THREAD_BACKGROUND_PRIORITY;
172 case THREAD_PRIORITY_IDLE:
173 case THREAD_PRIORITY_LOWEST:
174 return OBJC_THREAD_LOW_PRIORITY;
177 /* Couldn't get priority. */
178 return -1;
181 /* Yield our process time to another thread. */
182 void
183 __gthread_objc_thread_yield (void)
185 Sleep (0);
188 /* Terminate the current thread. */
190 __gthread_objc_thread_exit (void)
192 /* exit the thread */
193 ExitThread (__objc_thread_exit_status);
195 /* Failed if we reached here */
196 return -1;
199 /* Returns an integer value which uniquely describes a thread. */
200 objc_thread_t
201 __gthread_objc_thread_id (void)
203 return (objc_thread_t) GetCurrentThreadId ();
206 /* Sets the thread's local storage pointer. */
208 __gthread_objc_thread_set_data (void *value)
210 if (TlsSetValue (__gthread_objc_data_tls, value))
211 return 0;
212 else
213 return -1;
216 /* Returns the thread's local storage pointer. */
217 void *
218 __gthread_objc_thread_get_data (void)
220 DWORD lasterror;
221 void *ptr;
223 lasterror = GetLastError ();
225 ptr = TlsGetValue (__gthread_objc_data_tls); /* Return thread data. */
227 SetLastError (lasterror);
229 return ptr;
232 /* Backend mutex functions */
234 /* Allocate a mutex. */
236 __gthread_objc_mutex_allocate (objc_mutex_t mutex)
238 if ((mutex->backend = (void *) CreateMutex (NULL, 0, NULL)) == NULL)
239 return -1;
240 else
241 return 0;
244 /* Deallocate a mutex. */
246 __gthread_objc_mutex_deallocate (objc_mutex_t mutex)
248 CloseHandle ((HANDLE) (mutex->backend));
249 return 0;
252 /* Grab a lock on a mutex. */
254 __gthread_objc_mutex_lock (objc_mutex_t mutex)
256 int status;
258 status = WaitForSingleObject ((HANDLE) (mutex->backend), INFINITE);
259 if (status != WAIT_OBJECT_0 && status != WAIT_ABANDONED)
260 return -1;
261 else
262 return 0;
265 /* Try to grab a lock on a mutex. */
267 __gthread_objc_mutex_trylock (objc_mutex_t mutex)
269 int status;
271 status = WaitForSingleObject ((HANDLE) (mutex->backend), 0);
272 if (status != WAIT_OBJECT_0 && status != WAIT_ABANDONED)
273 return -1;
274 else
275 return 0;
278 /* Unlock the mutex */
280 __gthread_objc_mutex_unlock (objc_mutex_t mutex)
282 if (ReleaseMutex ((HANDLE) (mutex->backend)) == 0)
283 return -1;
284 else
285 return 0;
288 /* Backend condition mutex functions */
290 /* Allocate a condition. */
292 __gthread_objc_condition_allocate (objc_condition_t condition)
294 /* Unimplemented. */
295 return -1;
298 /* Deallocate a condition. */
300 __gthread_objc_condition_deallocate (objc_condition_t condition)
302 /* Unimplemented. */
303 return -1;
306 /* Wait on the condition */
308 __gthread_objc_condition_wait (objc_condition_t condition, objc_mutex_t mutex)
310 /* Unimplemented. */
311 return -1;
314 /* Wake up all threads waiting on this condition. */
316 __gthread_objc_condition_broadcast (objc_condition_t condition)
318 /* Unimplemented. */
319 return -1;
322 /* Wake up one thread waiting on this condition. */
324 __gthread_objc_condition_signal (objc_condition_t condition)
326 /* Unimplemented. */
327 return -1;
330 #else /* _LIBOBJC */
332 #ifdef __cplusplus
333 extern "C" {
334 #endif
336 typedef unsigned long __gthread_key_t;
338 typedef struct {
339 int done;
340 long started;
341 } __gthread_once_t;
343 typedef struct {
344 long counter;
345 void *sema;
346 } __gthread_mutex_t;
348 typedef struct {
349 long counter;
350 long depth;
351 unsigned long owner;
352 void *sema;
353 } __gthread_recursive_mutex_t;
355 #define __GTHREAD_ONCE_INIT {0, -1}
356 #define __GTHREAD_MUTEX_INIT_FUNCTION __gthread_mutex_init_function
357 #define __GTHREAD_MUTEX_INIT_DEFAULT {-1, 0}
358 #define __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION \
359 __gthread_recursive_mutex_init_function
360 #define __GTHREAD_RECURSIVE_MUTEX_INIT_DEFAULT {-1, 0, 0, 0}
362 #define __GTHREAD_MUTEX_DESTROY_FUNCTION \
363 __gthread_mutex_destroy_function
365 #if __MINGW32_MAJOR_VERSION >= 1 || \
366 (__MINGW32_MAJOR_VERSION == 0 && __MINGW32_MINOR_VERSION > 2)
367 #define MINGW32_SUPPORTS_MT_EH 1
368 /* Mingw runtime >= v0.3 provides a magic variable that is set to nonzero
369 if -mthreads option was specified, or 0 otherwise. This is to get around
370 the lack of weak symbols in PE-COFF. */
371 extern int _CRT_MT;
372 extern int __mingwthr_key_dtor (unsigned long, void (*) (void *));
373 #endif /* __MINGW32__ version */
375 /* The Windows95 kernel does not export InterlockedCompareExchange.
376 This provides a substitute. When building apps that reference
377 gthread_mutex_try_lock, the __GTHREAD_I486_INLINE_LOCK_PRIMITIVES
378 macro must be defined if Windows95 is a target. Currently
379 gthread_mutex_try_lock is not referenced by libgcc or libstdc++. */
380 #ifdef __GTHREAD_I486_INLINE_LOCK_PRIMITIVES
381 static inline long
382 __gthr_i486_lock_cmp_xchg(long *dest, long xchg, long comperand)
384 long result;
385 __asm__ __volatile__ ("\n\
386 lock\n\
387 cmpxchg{l} {%4, %1|%1, %4}\n"
388 : "=a" (result), "=m" (*dest)
389 : "0" (comperand), "m" (*dest), "r" (xchg)
390 : "cc");
391 return result;
393 #define __GTHR_W32_InterlockedCompareExchange __gthr_i486_lock_cmp_xchg
394 #else /* __GTHREAD_I486_INLINE_LOCK_PRIMITIVES */
395 #define __GTHR_W32_InterlockedCompareExchange InterlockedCompareExchange
396 #endif /* __GTHREAD_I486_INLINE_LOCK_PRIMITIVES */
398 static inline int
399 __gthread_active_p (void)
401 #ifdef MINGW32_SUPPORTS_MT_EH
402 return _CRT_MT;
403 #else
404 return 1;
405 #endif
408 #if __GTHREAD_HIDE_WIN32API
410 /* The implementations are in config/i386/gthr-win32.c in libgcc.a.
411 Only stubs are exposed to avoid polluting the C++ namespace with
412 windows api definitions. */
414 extern int __gthr_win32_once (__gthread_once_t *, void (*) (void));
415 extern int __gthr_win32_key_create (__gthread_key_t *, void (*) (void*));
416 extern int __gthr_win32_key_delete (__gthread_key_t);
417 extern void * __gthr_win32_getspecific (__gthread_key_t);
418 extern int __gthr_win32_setspecific (__gthread_key_t, const void *);
419 extern void __gthr_win32_mutex_init_function (__gthread_mutex_t *);
420 extern int __gthr_win32_mutex_lock (__gthread_mutex_t *);
421 extern int __gthr_win32_mutex_trylock (__gthread_mutex_t *);
422 extern int __gthr_win32_mutex_unlock (__gthread_mutex_t *);
423 extern void
424 __gthr_win32_recursive_mutex_init_function (__gthread_recursive_mutex_t *);
425 extern int __gthr_win32_recursive_mutex_lock (__gthread_recursive_mutex_t *);
426 extern int
427 __gthr_win32_recursive_mutex_trylock (__gthread_recursive_mutex_t *);
428 extern int __gthr_win32_recursive_mutex_unlock (__gthread_recursive_mutex_t *);
430 static inline int
431 __gthread_once (__gthread_once_t *once, void (*func) (void))
433 if (__gthread_active_p ())
434 return __gthr_win32_once (once, func);
435 else
436 return -1;
439 static inline int
440 __gthread_key_create (__gthread_key_t *key, void (*dtor) (void *))
442 return __gthr_win32_key_create (key, dtor);
445 static inline int
446 __gthread_key_delete (__gthread_key_t key)
448 return __gthr_win32_key_delete (key);
451 static inline void *
452 __gthread_getspecific (__gthread_key_t key)
454 return __gthr_win32_getspecific (key);
457 static inline int
458 __gthread_setspecific (__gthread_key_t key, const void *ptr)
460 return __gthr_win32_setspecific (key, ptr);
463 static inline void
464 __gthread_mutex_init_function (__gthread_mutex_t *mutex)
466 __gthr_win32_mutex_init_function (mutex);
469 static inline int
470 __gthread_mutex_lock (__gthread_mutex_t *mutex)
472 if (__gthread_active_p ())
473 return __gthr_win32_mutex_lock (mutex);
474 else
475 return 0;
478 static inline int
479 __gthread_mutex_trylock (__gthread_mutex_t *mutex)
481 if (__gthread_active_p ())
482 return __gthr_win32_mutex_trylock (mutex);
483 else
484 return 0;
487 static inline int
488 __gthread_mutex_unlock (__gthread_mutex_t *mutex)
490 if (__gthread_active_p ())
491 return __gthr_win32_mutex_unlock (mutex);
492 else
493 return 0;
496 static inline void
497 __gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *mutex)
499 __gthr_win32_recursive_mutex_init_function (mutex);
502 static inline int
503 __gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex)
505 if (__gthread_active_p ())
506 return __gthr_win32_recursive_mutex_lock (mutex);
507 else
508 return 0;
511 static inline int
512 __gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex)
514 if (__gthread_active_p ())
515 return __gthr_win32_recursive_mutex_trylock (mutex);
516 else
517 return 0;
520 static inline int
521 __gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex)
523 if (__gthread_active_p ())
524 return __gthr_win32_recursive_mutex_unlock (mutex);
525 else
526 return 0;
529 #else /* ! __GTHREAD_HIDE_WIN32API */
531 #include <windows.h>
532 #include <errno.h>
534 static inline int
535 __gthread_once (__gthread_once_t *once, void (*func) (void))
537 if (! __gthread_active_p ())
538 return -1;
539 else if (once == NULL || func == NULL)
540 return EINVAL;
542 if (! once->done)
544 if (InterlockedIncrement (&(once->started)) == 0)
546 (*func) ();
547 once->done = TRUE;
549 else
551 /* Another thread is currently executing the code, so wait for it
552 to finish; yield the CPU in the meantime. If performance
553 does become an issue, the solution is to use an Event that
554 we wait on here (and set above), but that implies a place to
555 create the event before this routine is called. */
556 while (! once->done)
557 Sleep (0);
561 return 0;
564 /* Windows32 thread local keys don't support destructors; this leads to
565 leaks, especially in threaded applications making extensive use of
566 C++ EH. Mingw uses a thread-support DLL to work-around this problem. */
567 static inline int
568 __gthread_key_create (__gthread_key_t *key,
569 void (*dtor) (void *) __attribute__((unused)))
571 int status = 0;
572 DWORD tls_index = TlsAlloc ();
573 if (tls_index != 0xFFFFFFFF)
575 *key = tls_index;
576 #ifdef MINGW32_SUPPORTS_MT_EH
577 /* Mingw runtime will run the dtors in reverse order for each thread
578 when the thread exits. */
579 status = __mingwthr_key_dtor (*key, dtor);
580 #endif
582 else
583 status = (int) GetLastError ();
584 return status;
587 static inline int
588 __gthread_key_delete (__gthread_key_t key)
590 return (TlsFree (key) != 0) ? 0 : (int) GetLastError ();
593 static inline void *
594 __gthread_getspecific (__gthread_key_t key)
596 DWORD lasterror;
597 void *ptr;
599 lasterror = GetLastError ();
601 ptr = TlsGetValue (key);
603 SetLastError (lasterror);
605 return ptr;
608 static inline int
609 __gthread_setspecific (__gthread_key_t key, const void *ptr)
611 return (TlsSetValue (key, (void*) ptr) != 0) ? 0 : (int) GetLastError ();
614 static inline void
615 __gthread_mutex_init_function (__gthread_mutex_t *mutex)
617 mutex->counter = -1;
618 mutex->sema = CreateSemaphore (NULL, 0, 65535, NULL);
621 static inline void
622 __gthread_mutex_destroy_function (__gthread_mutex_t *mutex)
624 CloseHandle ((HANDLE) mutex->sema);
627 static inline int
628 __gthread_mutex_lock (__gthread_mutex_t *mutex)
630 int status = 0;
632 if (__gthread_active_p ())
634 if (InterlockedIncrement (&mutex->counter) == 0 ||
635 WaitForSingleObject (mutex->sema, INFINITE) == WAIT_OBJECT_0)
636 status = 0;
637 else
639 /* WaitForSingleObject returns WAIT_FAILED, and we can only do
640 some best-effort cleanup here. */
641 InterlockedDecrement (&mutex->counter);
642 status = 1;
645 return status;
648 static inline int
649 __gthread_mutex_trylock (__gthread_mutex_t *mutex)
651 int status = 0;
653 if (__gthread_active_p ())
655 if (__GTHR_W32_InterlockedCompareExchange (&mutex->counter, 0, -1) < 0)
656 status = 0;
657 else
658 status = 1;
660 return status;
663 static inline int
664 __gthread_mutex_unlock (__gthread_mutex_t *mutex)
666 if (__gthread_active_p ())
668 if (InterlockedDecrement (&mutex->counter) >= 0)
669 return ReleaseSemaphore (mutex->sema, 1, NULL) ? 0 : 1;
671 return 0;
674 static inline void
675 __gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *mutex)
677 mutex->counter = -1;
678 mutex->depth = 0;
679 mutex->owner = 0;
680 mutex->sema = CreateSemaphore (NULL, 0, 65535, NULL);
683 static inline int
684 __gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex)
686 if (__gthread_active_p ())
688 DWORD me = GetCurrentThreadId();
689 if (InterlockedIncrement (&mutex->counter) == 0)
691 mutex->depth = 1;
692 mutex->owner = me;
694 else if (mutex->owner == me)
696 InterlockedDecrement (&mutex->counter);
697 ++(mutex->depth);
699 else if (WaitForSingleObject (mutex->sema, INFINITE) == WAIT_OBJECT_0)
701 mutex->depth = 1;
702 mutex->owner = me;
704 else
706 /* WaitForSingleObject returns WAIT_FAILED, and we can only do
707 some best-effort cleanup here. */
708 InterlockedDecrement (&mutex->counter);
709 return 1;
712 return 0;
715 static inline int
716 __gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex)
718 if (__gthread_active_p ())
720 DWORD me = GetCurrentThreadId();
721 if (__GTHR_W32_InterlockedCompareExchange (&mutex->counter, 0, -1) < 0)
723 mutex->depth = 1;
724 mutex->owner = me;
726 else if (mutex->owner == me)
727 ++(mutex->depth);
728 else
729 return 1;
731 return 0;
734 static inline int
735 __gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex)
737 if (__gthread_active_p ())
739 --(mutex->depth);
740 if (mutex->depth == 0)
742 mutex->owner = 0;
744 if (InterlockedDecrement (&mutex->counter) >= 0)
745 return ReleaseSemaphore (mutex->sema, 1, NULL) ? 0 : 1;
748 return 0;
751 #endif /* __GTHREAD_HIDE_WIN32API */
753 #ifdef __cplusplus
755 #endif
757 #endif /* _LIBOBJC */
759 #endif /* ! GCC_GTHR_WIN32_H */