* gcc.dg/compat/struct-layout-1_generate.c (dg_options): New. Moved
[official-gcc.git] / gcc / gthr-win32.h
blobe9a6e8869c4ee175cd6400032522ef715b6a77bb
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 /* Make sure CONST_CAST2 (origin in system.h) is declared. */
36 #ifndef CONST_CAST2
37 #define CONST_CAST2(TOTYPE,FROMTYPE,X) ((__extension__(union {FROMTYPE _q; TOTYPE _nq;})(X))._nq)
38 #endif
40 /* Windows32 threads specific definitions. The windows32 threading model
41 does not map well into pthread-inspired gcc's threading model, and so
42 there are caveats one needs to be aware of.
44 1. The destructor supplied to __gthread_key_create is ignored for
45 generic x86-win32 ports. This will certainly cause memory leaks
46 due to unreclaimed eh contexts (sizeof (eh_context) is at least
47 24 bytes for x86 currently).
49 This memory leak may be significant for long-running applications
50 that make heavy use of C++ EH.
52 However, Mingw runtime (version 0.3 or newer) provides a mechanism
53 to emulate pthreads key dtors; the runtime provides a special DLL,
54 linked in if -mthreads option is specified, that runs the dtors in
55 the reverse order of registration when each thread exits. If
56 -mthreads option is not given, a stub is linked in instead of the
57 DLL, which results in memory leak. Other x86-win32 ports can use
58 the same technique of course to avoid the leak.
60 2. The error codes returned are non-POSIX like, and cast into ints.
61 This may cause incorrect error return due to truncation values on
62 hw where sizeof (DWORD) > sizeof (int).
64 3. We are currently using a special mutex instead of the Critical
65 Sections, since Win9x does not support TryEnterCriticalSection
66 (while NT does).
68 The basic framework should work well enough. In the long term, GCC
69 needs to use Structured Exception Handling on Windows32. */
71 #define __GTHREADS 1
73 #include <errno.h>
74 #ifdef __MINGW32__
75 #include <_mingw.h>
76 #endif
78 #ifdef _LIBOBJC
80 /* This is necessary to prevent windef.h (included from windows.h) from
81 defining its own BOOL as a typedef. */
82 #ifndef __OBJC__
83 #define __OBJC__
84 #endif
85 #include <windows.h>
86 /* Now undef the windows BOOL. */
87 #undef BOOL
89 /* Key structure for maintaining thread specific storage */
90 static DWORD __gthread_objc_data_tls = (DWORD) -1;
92 /* Backend initialization functions */
94 /* Initialize the threads subsystem. */
95 int
96 __gthread_objc_init_thread_system (void)
98 /* Initialize the thread storage key. */
99 if ((__gthread_objc_data_tls = TlsAlloc ()) != (DWORD) -1)
100 return 0;
101 else
102 return -1;
105 /* Close the threads subsystem. */
107 __gthread_objc_close_thread_system (void)
109 if (__gthread_objc_data_tls != (DWORD) -1)
110 TlsFree (__gthread_objc_data_tls);
111 return 0;
114 /* Backend thread functions */
116 /* Create a new thread of execution. */
117 objc_thread_t
118 __gthread_objc_thread_detach (void (*func)(void *arg), void *arg)
120 DWORD thread_id = 0;
121 HANDLE win32_handle;
123 if (!(win32_handle = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) func,
124 arg, 0, &thread_id)))
125 thread_id = 0;
127 return (objc_thread_t) thread_id;
130 /* Set the current thread's priority. */
132 __gthread_objc_thread_set_priority (int priority)
134 int sys_priority = 0;
136 switch (priority)
138 case OBJC_THREAD_INTERACTIVE_PRIORITY:
139 sys_priority = THREAD_PRIORITY_NORMAL;
140 break;
141 default:
142 case OBJC_THREAD_BACKGROUND_PRIORITY:
143 sys_priority = THREAD_PRIORITY_BELOW_NORMAL;
144 break;
145 case OBJC_THREAD_LOW_PRIORITY:
146 sys_priority = THREAD_PRIORITY_LOWEST;
147 break;
150 /* Change priority */
151 if (SetThreadPriority (GetCurrentThread (), sys_priority))
152 return 0;
153 else
154 return -1;
157 /* Return the current thread's priority. */
159 __gthread_objc_thread_get_priority (void)
161 int sys_priority;
163 sys_priority = GetThreadPriority (GetCurrentThread ());
165 switch (sys_priority)
167 case THREAD_PRIORITY_HIGHEST:
168 case THREAD_PRIORITY_TIME_CRITICAL:
169 case THREAD_PRIORITY_ABOVE_NORMAL:
170 case THREAD_PRIORITY_NORMAL:
171 return OBJC_THREAD_INTERACTIVE_PRIORITY;
173 default:
174 case THREAD_PRIORITY_BELOW_NORMAL:
175 return OBJC_THREAD_BACKGROUND_PRIORITY;
177 case THREAD_PRIORITY_IDLE:
178 case THREAD_PRIORITY_LOWEST:
179 return OBJC_THREAD_LOW_PRIORITY;
182 /* Couldn't get priority. */
183 return -1;
186 /* Yield our process time to another thread. */
187 void
188 __gthread_objc_thread_yield (void)
190 Sleep (0);
193 /* Terminate the current thread. */
195 __gthread_objc_thread_exit (void)
197 /* exit the thread */
198 ExitThread (__objc_thread_exit_status);
200 /* Failed if we reached here */
201 return -1;
204 /* Returns an integer value which uniquely describes a thread. */
205 objc_thread_t
206 __gthread_objc_thread_id (void)
208 return (objc_thread_t) GetCurrentThreadId ();
211 /* Sets the thread's local storage pointer. */
213 __gthread_objc_thread_set_data (void *value)
215 if (TlsSetValue (__gthread_objc_data_tls, value))
216 return 0;
217 else
218 return -1;
221 /* Returns the thread's local storage pointer. */
222 void *
223 __gthread_objc_thread_get_data (void)
225 DWORD lasterror;
226 void *ptr;
228 lasterror = GetLastError ();
230 ptr = TlsGetValue (__gthread_objc_data_tls); /* Return thread data. */
232 SetLastError (lasterror);
234 return ptr;
237 /* Backend mutex functions */
239 /* Allocate a mutex. */
241 __gthread_objc_mutex_allocate (objc_mutex_t mutex)
243 if ((mutex->backend = (void *) CreateMutex (NULL, 0, NULL)) == NULL)
244 return -1;
245 else
246 return 0;
249 /* Deallocate a mutex. */
251 __gthread_objc_mutex_deallocate (objc_mutex_t mutex)
253 CloseHandle ((HANDLE) (mutex->backend));
254 return 0;
257 /* Grab a lock on a mutex. */
259 __gthread_objc_mutex_lock (objc_mutex_t mutex)
261 int status;
263 status = WaitForSingleObject ((HANDLE) (mutex->backend), INFINITE);
264 if (status != WAIT_OBJECT_0 && status != WAIT_ABANDONED)
265 return -1;
266 else
267 return 0;
270 /* Try to grab a lock on a mutex. */
272 __gthread_objc_mutex_trylock (objc_mutex_t mutex)
274 int status;
276 status = WaitForSingleObject ((HANDLE) (mutex->backend), 0);
277 if (status != WAIT_OBJECT_0 && status != WAIT_ABANDONED)
278 return -1;
279 else
280 return 0;
283 /* Unlock the mutex */
285 __gthread_objc_mutex_unlock (objc_mutex_t mutex)
287 if (ReleaseMutex ((HANDLE) (mutex->backend)) == 0)
288 return -1;
289 else
290 return 0;
293 /* Backend condition mutex functions */
295 /* Allocate a condition. */
297 __gthread_objc_condition_allocate (objc_condition_t condition)
299 /* Unimplemented. */
300 return -1;
303 /* Deallocate a condition. */
305 __gthread_objc_condition_deallocate (objc_condition_t condition)
307 /* Unimplemented. */
308 return -1;
311 /* Wait on the condition */
313 __gthread_objc_condition_wait (objc_condition_t condition, objc_mutex_t mutex)
315 /* Unimplemented. */
316 return -1;
319 /* Wake up all threads waiting on this condition. */
321 __gthread_objc_condition_broadcast (objc_condition_t condition)
323 /* Unimplemented. */
324 return -1;
327 /* Wake up one thread waiting on this condition. */
329 __gthread_objc_condition_signal (objc_condition_t condition)
331 /* Unimplemented. */
332 return -1;
335 #else /* _LIBOBJC */
337 #ifdef __cplusplus
338 extern "C" {
339 #endif
341 typedef unsigned long __gthread_key_t;
343 typedef struct {
344 int done;
345 long started;
346 } __gthread_once_t;
348 typedef struct {
349 long counter;
350 void *sema;
351 } __gthread_mutex_t;
353 typedef struct {
354 long counter;
355 long depth;
356 unsigned long owner;
357 void *sema;
358 } __gthread_recursive_mutex_t;
360 #define __GTHREAD_ONCE_INIT {0, -1}
361 #define __GTHREAD_MUTEX_INIT_FUNCTION __gthread_mutex_init_function
362 #define __GTHREAD_MUTEX_INIT_DEFAULT {-1, 0}
363 #define __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION \
364 __gthread_recursive_mutex_init_function
365 #define __GTHREAD_RECURSIVE_MUTEX_INIT_DEFAULT {-1, 0, 0, 0}
367 #if __MINGW32_MAJOR_VERSION >= 1 || \
368 (__MINGW32_MAJOR_VERSION == 0 && __MINGW32_MINOR_VERSION > 2)
369 #define MINGW32_SUPPORTS_MT_EH 1
370 /* Mingw runtime >= v0.3 provides a magic variable that is set to nonzero
371 if -mthreads option was specified, or 0 otherwise. This is to get around
372 the lack of weak symbols in PE-COFF. */
373 extern int _CRT_MT;
374 extern int __mingwthr_key_dtor (unsigned long, void (*) (void *));
375 #endif /* __MINGW32__ version */
377 /* The Windows95 kernel does not export InterlockedCompareExchange.
378 This provides a substitute. When building apps that reference
379 gthread_mutex_try_lock, the __GTHREAD_I486_INLINE_LOCK_PRIMITIVES
380 macro must be defined if Windows95 is a target. Currently
381 gthread_mutex_try_lock is not referenced by libgcc or libstdc++. */
382 #ifdef __GTHREAD_I486_INLINE_LOCK_PRIMITIVES
383 static inline long
384 __gthr_i486_lock_cmp_xchg(long *dest, long xchg, long comperand)
386 long result;
387 __asm__ __volatile__ ("\n\
388 lock\n\
389 cmpxchg{l} {%4, %1|%1, %4}\n"
390 : "=a" (result), "=m" (*dest)
391 : "0" (comperand), "m" (*dest), "r" (xchg)
392 : "cc");
393 return result;
395 #define __GTHR_W32_InterlockedCompareExchange __gthr_i486_lock_cmp_xchg
396 #else /* __GTHREAD_I486_INLINE_LOCK_PRIMITIVES */
397 #define __GTHR_W32_InterlockedCompareExchange InterlockedCompareExchange
398 #endif /* __GTHREAD_I486_INLINE_LOCK_PRIMITIVES */
400 static inline int
401 __gthread_active_p (void)
403 #ifdef MINGW32_SUPPORTS_MT_EH
404 return _CRT_MT;
405 #else
406 return 1;
407 #endif
410 #if __GTHREAD_HIDE_WIN32API
412 /* The implementations are in config/i386/gthr-win32.c in libgcc.a.
413 Only stubs are exposed to avoid polluting the C++ namespace with
414 windows api definitions. */
416 extern int __gthr_win32_once (__gthread_once_t *, void (*) (void));
417 extern int __gthr_win32_key_create (__gthread_key_t *, void (*) (void*));
418 extern int __gthr_win32_key_delete (__gthread_key_t);
419 extern void * __gthr_win32_getspecific (__gthread_key_t);
420 extern int __gthr_win32_setspecific (__gthread_key_t, const void *);
421 extern void __gthr_win32_mutex_init_function (__gthread_mutex_t *);
422 extern int __gthr_win32_mutex_lock (__gthread_mutex_t *);
423 extern int __gthr_win32_mutex_trylock (__gthread_mutex_t *);
424 extern int __gthr_win32_mutex_unlock (__gthread_mutex_t *);
425 extern void
426 __gthr_win32_recursive_mutex_init_function (__gthread_recursive_mutex_t *);
427 extern int __gthr_win32_recursive_mutex_lock (__gthread_recursive_mutex_t *);
428 extern int
429 __gthr_win32_recursive_mutex_trylock (__gthread_recursive_mutex_t *);
430 extern int __gthr_win32_recursive_mutex_unlock (__gthread_recursive_mutex_t *);
431 extern void __gthr_win32_mutex_destroy (__gthread_mutex_t *);
433 static inline int
434 __gthread_once (__gthread_once_t *once, void (*func) (void))
436 if (__gthread_active_p ())
437 return __gthr_win32_once (once, func);
438 else
439 return -1;
442 static inline int
443 __gthread_key_create (__gthread_key_t *key, void (*dtor) (void *))
445 return __gthr_win32_key_create (key, dtor);
448 static inline int
449 __gthread_key_delete (__gthread_key_t key)
451 return __gthr_win32_key_delete (key);
454 static inline void *
455 __gthread_getspecific (__gthread_key_t key)
457 return __gthr_win32_getspecific (key);
460 static inline int
461 __gthread_setspecific (__gthread_key_t key, const void *ptr)
463 return __gthr_win32_setspecific (key, ptr);
466 static inline void
467 __gthread_mutex_init_function (__gthread_mutex_t *mutex)
469 __gthr_win32_mutex_init_function (mutex);
472 static inline void
473 __gthread_mutex_destroy (__gthread_mutex_t *mutex)
475 __gthr_win32_mutex_destroy (mutex);
478 static inline int
479 __gthread_mutex_lock (__gthread_mutex_t *mutex)
481 if (__gthread_active_p ())
482 return __gthr_win32_mutex_lock (mutex);
483 else
484 return 0;
487 static inline int
488 __gthread_mutex_trylock (__gthread_mutex_t *mutex)
490 if (__gthread_active_p ())
491 return __gthr_win32_mutex_trylock (mutex);
492 else
493 return 0;
496 static inline int
497 __gthread_mutex_unlock (__gthread_mutex_t *mutex)
499 if (__gthread_active_p ())
500 return __gthr_win32_mutex_unlock (mutex);
501 else
502 return 0;
505 static inline void
506 __gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *mutex)
508 __gthr_win32_recursive_mutex_init_function (mutex);
511 static inline int
512 __gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex)
514 if (__gthread_active_p ())
515 return __gthr_win32_recursive_mutex_lock (mutex);
516 else
517 return 0;
520 static inline int
521 __gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex)
523 if (__gthread_active_p ())
524 return __gthr_win32_recursive_mutex_trylock (mutex);
525 else
526 return 0;
529 static inline int
530 __gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex)
532 if (__gthread_active_p ())
533 return __gthr_win32_recursive_mutex_unlock (mutex);
534 else
535 return 0;
538 #else /* ! __GTHREAD_HIDE_WIN32API */
540 #include <windows.h>
541 #include <errno.h>
543 static inline int
544 __gthread_once (__gthread_once_t *once, void (*func) (void))
546 if (! __gthread_active_p ())
547 return -1;
548 else if (once == NULL || func == NULL)
549 return EINVAL;
551 if (! once->done)
553 if (InterlockedIncrement (&(once->started)) == 0)
555 (*func) ();
556 once->done = TRUE;
558 else
560 /* Another thread is currently executing the code, so wait for it
561 to finish; yield the CPU in the meantime. If performance
562 does become an issue, the solution is to use an Event that
563 we wait on here (and set above), but that implies a place to
564 create the event before this routine is called. */
565 while (! once->done)
566 Sleep (0);
570 return 0;
573 /* Windows32 thread local keys don't support destructors; this leads to
574 leaks, especially in threaded applications making extensive use of
575 C++ EH. Mingw uses a thread-support DLL to work-around this problem. */
576 static inline int
577 __gthread_key_create (__gthread_key_t *key,
578 void (*dtor) (void *) __attribute__((unused)))
580 int status = 0;
581 DWORD tls_index = TlsAlloc ();
582 if (tls_index != 0xFFFFFFFF)
584 *key = tls_index;
585 #ifdef MINGW32_SUPPORTS_MT_EH
586 /* Mingw runtime will run the dtors in reverse order for each thread
587 when the thread exits. */
588 status = __mingwthr_key_dtor (*key, dtor);
589 #endif
591 else
592 status = (int) GetLastError ();
593 return status;
596 static inline int
597 __gthread_key_delete (__gthread_key_t key)
599 return (TlsFree (key) != 0) ? 0 : (int) GetLastError ();
602 static inline void *
603 __gthread_getspecific (__gthread_key_t key)
605 DWORD lasterror;
606 void *ptr;
608 lasterror = GetLastError ();
610 ptr = TlsGetValue (key);
612 SetLastError (lasterror);
614 return ptr;
617 static inline int
618 __gthread_setspecific (__gthread_key_t key, const void *ptr)
620 if (TlsSetValue (key, CONST_CAST2(void *, const void *, ptr)) != 0)
621 return 0;
622 else
623 return GetLastError ();
626 static inline void
627 __gthread_mutex_init_function (__gthread_mutex_t *mutex)
629 mutex->counter = -1;
630 mutex->sema = CreateSemaphore (NULL, 0, 65535, NULL);
633 static inline void
634 __gthread_mutex_destroy (__gthread_mutex_t *mutex)
636 CloseHandle ((HANDLE) mutex->sema);
639 static inline int
640 __gthread_mutex_lock (__gthread_mutex_t *mutex)
642 int status = 0;
644 if (__gthread_active_p ())
646 if (InterlockedIncrement (&mutex->counter) == 0 ||
647 WaitForSingleObject (mutex->sema, INFINITE) == WAIT_OBJECT_0)
648 status = 0;
649 else
651 /* WaitForSingleObject returns WAIT_FAILED, and we can only do
652 some best-effort cleanup here. */
653 InterlockedDecrement (&mutex->counter);
654 status = 1;
657 return status;
660 static inline int
661 __gthread_mutex_trylock (__gthread_mutex_t *mutex)
663 int status = 0;
665 if (__gthread_active_p ())
667 if (__GTHR_W32_InterlockedCompareExchange (&mutex->counter, 0, -1) < 0)
668 status = 0;
669 else
670 status = 1;
672 return status;
675 static inline int
676 __gthread_mutex_unlock (__gthread_mutex_t *mutex)
678 if (__gthread_active_p ())
680 if (InterlockedDecrement (&mutex->counter) >= 0)
681 return ReleaseSemaphore (mutex->sema, 1, NULL) ? 0 : 1;
683 return 0;
686 static inline void
687 __gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *mutex)
689 mutex->counter = -1;
690 mutex->depth = 0;
691 mutex->owner = 0;
692 mutex->sema = CreateSemaphore (NULL, 0, 65535, NULL);
695 static inline int
696 __gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex)
698 if (__gthread_active_p ())
700 DWORD me = GetCurrentThreadId();
701 if (InterlockedIncrement (&mutex->counter) == 0)
703 mutex->depth = 1;
704 mutex->owner = me;
706 else if (mutex->owner == me)
708 InterlockedDecrement (&mutex->counter);
709 ++(mutex->depth);
711 else if (WaitForSingleObject (mutex->sema, INFINITE) == WAIT_OBJECT_0)
713 mutex->depth = 1;
714 mutex->owner = me;
716 else
718 /* WaitForSingleObject returns WAIT_FAILED, and we can only do
719 some best-effort cleanup here. */
720 InterlockedDecrement (&mutex->counter);
721 return 1;
724 return 0;
727 static inline int
728 __gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex)
730 if (__gthread_active_p ())
732 DWORD me = GetCurrentThreadId();
733 if (__GTHR_W32_InterlockedCompareExchange (&mutex->counter, 0, -1) < 0)
735 mutex->depth = 1;
736 mutex->owner = me;
738 else if (mutex->owner == me)
739 ++(mutex->depth);
740 else
741 return 1;
743 return 0;
746 static inline int
747 __gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex)
749 if (__gthread_active_p ())
751 --(mutex->depth);
752 if (mutex->depth == 0)
754 mutex->owner = 0;
756 if (InterlockedDecrement (&mutex->counter) >= 0)
757 return ReleaseSemaphore (mutex->sema, 1, NULL) ? 0 : 1;
760 return 0;
763 #endif /* __GTHREAD_HIDE_WIN32API */
765 #ifdef __cplusplus
767 #endif
769 #endif /* _LIBOBJC */
771 #endif /* ! GCC_GTHR_WIN32_H */