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
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
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
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
63 The basic framework should work well enough. In the long term, GCC
64 needs to use Structured Exception Handling on Windows32. */
75 /* This is necessary to prevent windef.h (included from windows.h) from
76 defining its own BOOL as a typedef. */
81 /* Now undef the windows 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. */
91 __gthread_objc_init_thread_system (void)
93 /* Initialize the thread storage key. */
94 if ((__gthread_objc_data_tls
= TlsAlloc ()) != (DWORD
) -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
);
109 /* Backend thread functions */
111 /* Create a new thread of execution. */
113 __gthread_objc_thread_detach (void (*func
)(void *arg
), void *arg
)
118 if (!(win32_handle
= CreateThread (NULL
, 0, (LPTHREAD_START_ROUTINE
) func
,
119 arg
, 0, &thread_id
)))
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;
133 case OBJC_THREAD_INTERACTIVE_PRIORITY
:
134 sys_priority
= THREAD_PRIORITY_NORMAL
;
137 case OBJC_THREAD_BACKGROUND_PRIORITY
:
138 sys_priority
= THREAD_PRIORITY_BELOW_NORMAL
;
140 case OBJC_THREAD_LOW_PRIORITY
:
141 sys_priority
= THREAD_PRIORITY_LOWEST
;
145 /* Change priority */
146 if (SetThreadPriority (GetCurrentThread (), sys_priority
))
152 /* Return the current thread's priority. */
154 __gthread_objc_thread_get_priority (void)
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
;
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. */
181 /* Yield our process time to another thread. */
183 __gthread_objc_thread_yield (void)
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 */
199 /* Returns an integer value which uniquely describes a thread. */
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
))
216 /* Returns the thread's local storage pointer. */
218 __gthread_objc_thread_get_data (void)
223 lasterror
= GetLastError ();
225 ptr
= TlsGetValue (__gthread_objc_data_tls
); /* Return thread data. */
227 SetLastError (lasterror
);
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
)
244 /* Deallocate a mutex. */
246 __gthread_objc_mutex_deallocate (objc_mutex_t mutex
)
248 CloseHandle ((HANDLE
) (mutex
->backend
));
252 /* Grab a lock on a mutex. */
254 __gthread_objc_mutex_lock (objc_mutex_t mutex
)
258 status
= WaitForSingleObject ((HANDLE
) (mutex
->backend
), INFINITE
);
259 if (status
!= WAIT_OBJECT_0
&& status
!= WAIT_ABANDONED
)
265 /* Try to grab a lock on a mutex. */
267 __gthread_objc_mutex_trylock (objc_mutex_t mutex
)
271 status
= WaitForSingleObject ((HANDLE
) (mutex
->backend
), 0);
272 if (status
!= WAIT_OBJECT_0
&& status
!= WAIT_ABANDONED
)
278 /* Unlock the mutex */
280 __gthread_objc_mutex_unlock (objc_mutex_t mutex
)
282 if (ReleaseMutex ((HANDLE
) (mutex
->backend
)) == 0)
288 /* Backend condition mutex functions */
290 /* Allocate a condition. */
292 __gthread_objc_condition_allocate (objc_condition_t condition
)
298 /* Deallocate a condition. */
300 __gthread_objc_condition_deallocate (objc_condition_t condition
)
306 /* Wait on the condition */
308 __gthread_objc_condition_wait (objc_condition_t condition
, objc_mutex_t mutex
)
314 /* Wake up all threads waiting on this condition. */
316 __gthread_objc_condition_broadcast (objc_condition_t condition
)
322 /* Wake up one thread waiting on this condition. */
324 __gthread_objc_condition_signal (objc_condition_t condition
)
336 typedef unsigned long __gthread_key_t
;
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 #if __MINGW32_MAJOR_VERSION >= 1 || \
363 (__MINGW32_MAJOR_VERSION == 0 && __MINGW32_MINOR_VERSION > 2)
364 #define MINGW32_SUPPORTS_MT_EH 1
365 /* Mingw runtime >= v0.3 provides a magic variable that is set to nonzero
366 if -mthreads option was specified, or 0 otherwise. This is to get around
367 the lack of weak symbols in PE-COFF. */
369 extern int __mingwthr_key_dtor (unsigned long, void (*) (void *));
370 #endif /* __MINGW32__ version */
372 /* The Windows95 kernel does not export InterlockedCompareExchange.
373 This provides a substitute. When building apps that reference
374 gthread_mutex_try_lock, the __GTHREAD_I486_INLINE_LOCK_PRIMITIVES
375 macro must be defined if Windows95 is a target. Currently
376 gthread_mutex_try_lock is not referenced by libgcc or libstdc++. */
377 #ifdef __GTHREAD_I486_INLINE_LOCK_PRIMITIVES
379 __gthr_i486_lock_cmp_xchg(long *dest
, long xchg
, long comperand
)
382 __asm__
__volatile__ ("\n\
384 cmpxchg{l} {%4, %1|%1, %4}\n"
385 : "=a" (result
), "=m" (*dest
)
386 : "0" (comperand
), "m" (*dest
), "r" (xchg
)
390 #define __GTHR_W32_InterlockedCompareExchange __gthr_i486_lock_cmp_xchg
391 #else /* __GTHREAD_I486_INLINE_LOCK_PRIMITIVES */
392 #define __GTHR_W32_InterlockedCompareExchange InterlockedCompareExchange
393 #endif /* __GTHREAD_I486_INLINE_LOCK_PRIMITIVES */
396 __gthread_active_p (void)
398 #ifdef MINGW32_SUPPORTS_MT_EH
405 #if __GTHREAD_HIDE_WIN32API
407 /* The implementations are in config/i386/gthr-win32.c in libgcc.a.
408 Only stubs are exposed to avoid polluting the C++ namespace with
409 windows api definitions. */
411 extern int __gthr_win32_once (__gthread_once_t
*, void (*) (void));
412 extern int __gthr_win32_key_create (__gthread_key_t
*, void (*) (void*));
413 extern int __gthr_win32_key_delete (__gthread_key_t
);
414 extern void * __gthr_win32_getspecific (__gthread_key_t
);
415 extern int __gthr_win32_setspecific (__gthread_key_t
, const void *);
416 extern void __gthr_win32_mutex_init_function (__gthread_mutex_t
*);
417 extern int __gthr_win32_mutex_lock (__gthread_mutex_t
*);
418 extern int __gthr_win32_mutex_trylock (__gthread_mutex_t
*);
419 extern int __gthr_win32_mutex_unlock (__gthread_mutex_t
*);
421 __gthr_win32_recursive_mutex_init_function (__gthread_recursive_mutex_t
*);
422 extern int __gthr_win32_recursive_mutex_lock (__gthread_recursive_mutex_t
*);
424 __gthr_win32_recursive_mutex_trylock (__gthread_recursive_mutex_t
*);
425 extern int __gthr_win32_recursive_mutex_unlock (__gthread_recursive_mutex_t
*);
426 extern void __gthr_win32_mutex_destroy (__gthread_mutex_t
*);
429 __gthread_once (__gthread_once_t
*once
, void (*func
) (void))
431 if (__gthread_active_p ())
432 return __gthr_win32_once (once
, func
);
438 __gthread_key_create (__gthread_key_t
*key
, void (*dtor
) (void *))
440 return __gthr_win32_key_create (key
, dtor
);
444 __gthread_key_delete (__gthread_key_t key
)
446 return __gthr_win32_key_delete (key
);
450 __gthread_getspecific (__gthread_key_t key
)
452 return __gthr_win32_getspecific (key
);
456 __gthread_setspecific (__gthread_key_t key
, const void *ptr
)
458 return __gthr_win32_setspecific (key
, ptr
);
462 __gthread_mutex_init_function (__gthread_mutex_t
*mutex
)
464 __gthr_win32_mutex_init_function (mutex
);
468 __gthread_mutex_destroy (__gthread_mutex_t
*mutex
)
470 __gthr_win32_mutex_destroy (mutex
);
474 __gthread_mutex_lock (__gthread_mutex_t
*mutex
)
476 if (__gthread_active_p ())
477 return __gthr_win32_mutex_lock (mutex
);
483 __gthread_mutex_trylock (__gthread_mutex_t
*mutex
)
485 if (__gthread_active_p ())
486 return __gthr_win32_mutex_trylock (mutex
);
492 __gthread_mutex_unlock (__gthread_mutex_t
*mutex
)
494 if (__gthread_active_p ())
495 return __gthr_win32_mutex_unlock (mutex
);
501 __gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t
*mutex
)
503 __gthr_win32_recursive_mutex_init_function (mutex
);
507 __gthread_recursive_mutex_lock (__gthread_recursive_mutex_t
*mutex
)
509 if (__gthread_active_p ())
510 return __gthr_win32_recursive_mutex_lock (mutex
);
516 __gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t
*mutex
)
518 if (__gthread_active_p ())
519 return __gthr_win32_recursive_mutex_trylock (mutex
);
525 __gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t
*mutex
)
527 if (__gthread_active_p ())
528 return __gthr_win32_recursive_mutex_unlock (mutex
);
533 #else /* ! __GTHREAD_HIDE_WIN32API */
539 __gthread_once (__gthread_once_t
*once
, void (*func
) (void))
541 if (! __gthread_active_p ())
543 else if (once
== NULL
|| func
== NULL
)
548 if (InterlockedIncrement (&(once
->started
)) == 0)
555 /* Another thread is currently executing the code, so wait for it
556 to finish; yield the CPU in the meantime. If performance
557 does become an issue, the solution is to use an Event that
558 we wait on here (and set above), but that implies a place to
559 create the event before this routine is called. */
568 /* Windows32 thread local keys don't support destructors; this leads to
569 leaks, especially in threaded applications making extensive use of
570 C++ EH. Mingw uses a thread-support DLL to work-around this problem. */
572 __gthread_key_create (__gthread_key_t
*key
,
573 void (*dtor
) (void *) __attribute__((unused
)))
576 DWORD tls_index
= TlsAlloc ();
577 if (tls_index
!= 0xFFFFFFFF)
580 #ifdef MINGW32_SUPPORTS_MT_EH
581 /* Mingw runtime will run the dtors in reverse order for each thread
582 when the thread exits. */
583 status
= __mingwthr_key_dtor (*key
, dtor
);
587 status
= (int) GetLastError ();
592 __gthread_key_delete (__gthread_key_t key
)
594 return (TlsFree (key
) != 0) ? 0 : (int) GetLastError ();
598 __gthread_getspecific (__gthread_key_t key
)
603 lasterror
= GetLastError ();
605 ptr
= TlsGetValue (key
);
607 SetLastError (lasterror
);
613 __gthread_setspecific (__gthread_key_t key
, const void *ptr
)
615 return (TlsSetValue (key
, (void*) ptr
) != 0) ? 0 : (int) GetLastError ();
619 __gthread_mutex_init_function (__gthread_mutex_t
*mutex
)
622 mutex
->sema
= CreateSemaphore (NULL
, 0, 65535, NULL
);
626 __gthread_mutex_destroy (__gthread_mutex_t
*mutex
)
628 CloseHandle ((HANDLE
) mutex
->sema
);
632 __gthread_mutex_lock (__gthread_mutex_t
*mutex
)
636 if (__gthread_active_p ())
638 if (InterlockedIncrement (&mutex
->counter
) == 0 ||
639 WaitForSingleObject (mutex
->sema
, INFINITE
) == WAIT_OBJECT_0
)
643 /* WaitForSingleObject returns WAIT_FAILED, and we can only do
644 some best-effort cleanup here. */
645 InterlockedDecrement (&mutex
->counter
);
653 __gthread_mutex_trylock (__gthread_mutex_t
*mutex
)
657 if (__gthread_active_p ())
659 if (__GTHR_W32_InterlockedCompareExchange (&mutex
->counter
, 0, -1) < 0)
668 __gthread_mutex_unlock (__gthread_mutex_t
*mutex
)
670 if (__gthread_active_p ())
672 if (InterlockedDecrement (&mutex
->counter
) >= 0)
673 return ReleaseSemaphore (mutex
->sema
, 1, NULL
) ? 0 : 1;
679 __gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t
*mutex
)
684 mutex
->sema
= CreateSemaphore (NULL
, 0, 65535, NULL
);
688 __gthread_recursive_mutex_lock (__gthread_recursive_mutex_t
*mutex
)
690 if (__gthread_active_p ())
692 DWORD me
= GetCurrentThreadId();
693 if (InterlockedIncrement (&mutex
->counter
) == 0)
698 else if (mutex
->owner
== me
)
700 InterlockedDecrement (&mutex
->counter
);
703 else if (WaitForSingleObject (mutex
->sema
, INFINITE
) == WAIT_OBJECT_0
)
710 /* WaitForSingleObject returns WAIT_FAILED, and we can only do
711 some best-effort cleanup here. */
712 InterlockedDecrement (&mutex
->counter
);
720 __gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t
*mutex
)
722 if (__gthread_active_p ())
724 DWORD me
= GetCurrentThreadId();
725 if (__GTHR_W32_InterlockedCompareExchange (&mutex
->counter
, 0, -1) < 0)
730 else if (mutex
->owner
== me
)
739 __gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t
*mutex
)
741 if (__gthread_active_p ())
744 if (mutex
->depth
== 0)
748 if (InterlockedDecrement (&mutex
->counter
) >= 0)
749 return ReleaseSemaphore (mutex
->sema
, 1, NULL
) ? 0 : 1;
755 #endif /* __GTHREAD_HIDE_WIN32API */
761 #endif /* _LIBOBJC */
763 #endif /* ! GCC_GTHR_WIN32_H */