1 /* Threads compatibility routines for libgcc2 and libobjc. */
2 /* Compile this one with gcc. */
4 /* Copyright (C) 1999-2013 Free Software Foundation, Inc.
5 Contributed by Mumit Khan <khan@xraylith.wisc.edu>.
7 This file is part of GCC.
9 GCC is free software; you can redistribute it and/or modify it under
10 the terms of the GNU General Public License as published by the Free
11 Software Foundation; either version 3, or (at your option) any later
14 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 Under Section 7 of GPL version 3, you are granted additional
20 permissions described in the GCC Runtime Library Exception, version
21 3.1, as published by the Free Software Foundation.
23 You should have received a copy of the GNU General Public License and
24 a copy of the GCC Runtime Library Exception along with this program;
25 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
26 <http://www.gnu.org/licenses/>. */
28 #ifndef GCC_GTHR_WIN32_H
29 #define GCC_GTHR_WIN32_H
31 /* Make sure CONST_CAST2 (origin in system.h) is declared. */
33 #define CONST_CAST2(TOTYPE,FROMTYPE,X) ((__extension__(union {FROMTYPE _q; TOTYPE _nq;})(X))._nq)
36 /* Windows32 threads specific definitions. The windows32 threading model
37 does not map well into pthread-inspired gcc's threading model, and so
38 there are caveats one needs to be aware of.
40 1. The destructor supplied to __gthread_key_create is ignored for
41 generic x86-win32 ports. This will certainly cause memory leaks
42 due to unreclaimed eh contexts (sizeof (eh_context) is at least
43 24 bytes for x86 currently).
45 This memory leak may be significant for long-running applications
46 that make heavy use of C++ EH.
48 However, Mingw runtime (version 0.3 or newer) provides a mechanism
49 to emulate pthreads key dtors; the runtime provides a special DLL,
50 linked in if -mthreads option is specified, that runs the dtors in
51 the reverse order of registration when each thread exits. If
52 -mthreads option is not given, a stub is linked in instead of the
53 DLL, which results in memory leak. Other x86-win32 ports can use
54 the same technique of course to avoid the leak.
56 2. The error codes returned are non-POSIX like, and cast into ints.
57 This may cause incorrect error return due to truncation values on
58 hw where sizeof (DWORD) > sizeof (int).
60 3. We are currently using a special mutex instead of the Critical
61 Sections, since Win9x does not support TryEnterCriticalSection
64 The basic framework should work well enough. In the long term, GCC
65 needs to use Structured Exception Handling on Windows32. */
74 #ifndef __UNUSED_PARAM
75 #define __UNUSED_PARAM(x) x
80 /* This is necessary to prevent windef.h (included from windows.h) from
81 defining its own BOOL as a typedef. */
86 /* Now undef the windows 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. */
96 __gthread_objc_init_thread_system (void)
98 /* Initialize the thread storage key. */
99 if ((__gthread_objc_data_tls
= TlsAlloc ()) != (DWORD
) -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
);
114 /* Backend thread functions */
116 /* Create a new thread of execution. */
118 __gthread_objc_thread_detach (void (*func
)(void *arg
), void *arg
)
123 if (!(win32_handle
= CreateThread (NULL
, 0, (LPTHREAD_START_ROUTINE
) func
,
124 arg
, 0, &thread_id
)))
127 return (objc_thread_t
) (INT_PTR
) thread_id
;
130 /* Set the current thread's priority. */
132 __gthread_objc_thread_set_priority (int priority
)
134 int sys_priority
= 0;
138 case OBJC_THREAD_INTERACTIVE_PRIORITY
:
139 sys_priority
= THREAD_PRIORITY_NORMAL
;
142 case OBJC_THREAD_BACKGROUND_PRIORITY
:
143 sys_priority
= THREAD_PRIORITY_BELOW_NORMAL
;
145 case OBJC_THREAD_LOW_PRIORITY
:
146 sys_priority
= THREAD_PRIORITY_LOWEST
;
150 /* Change priority */
151 if (SetThreadPriority (GetCurrentThread (), sys_priority
))
157 /* Return the current thread's priority. */
159 __gthread_objc_thread_get_priority (void)
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
;
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. */
186 /* Yield our process time to another thread. */
188 __gthread_objc_thread_yield (void)
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 */
204 /* Returns an integer value which uniquely describes a thread. */
206 __gthread_objc_thread_id (void)
208 return (objc_thread_t
) (INT_PTR
) 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
))
221 /* Returns the thread's local storage pointer. */
223 __gthread_objc_thread_get_data (void)
228 lasterror
= GetLastError ();
230 ptr
= TlsGetValue (__gthread_objc_data_tls
); /* Return thread data. */
232 SetLastError (lasterror
);
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
)
249 /* Deallocate a mutex. */
251 __gthread_objc_mutex_deallocate (objc_mutex_t mutex
)
253 CloseHandle ((HANDLE
) (mutex
->backend
));
257 /* Grab a lock on a mutex. */
259 __gthread_objc_mutex_lock (objc_mutex_t mutex
)
263 status
= WaitForSingleObject ((HANDLE
) (mutex
->backend
), INFINITE
);
264 if (status
!= WAIT_OBJECT_0
&& status
!= WAIT_ABANDONED
)
270 /* Try to grab a lock on a mutex. */
272 __gthread_objc_mutex_trylock (objc_mutex_t mutex
)
276 status
= WaitForSingleObject ((HANDLE
) (mutex
->backend
), 0);
277 if (status
!= WAIT_OBJECT_0
&& status
!= WAIT_ABANDONED
)
283 /* Unlock the mutex */
285 __gthread_objc_mutex_unlock (objc_mutex_t mutex
)
287 if (ReleaseMutex ((HANDLE
) (mutex
->backend
)) == 0)
293 /* Backend condition mutex functions */
295 /* Allocate a condition. */
297 __gthread_objc_condition_allocate (objc_condition_t
__UNUSED_PARAM(condition
))
303 /* Deallocate a condition. */
305 __gthread_objc_condition_deallocate (objc_condition_t
__UNUSED_PARAM(condition
))
311 /* Wait on the condition */
313 __gthread_objc_condition_wait (objc_condition_t
__UNUSED_PARAM(condition
),
314 objc_mutex_t
__UNUSED_PARAM(mutex
))
320 /* Wake up all threads waiting on this condition. */
322 __gthread_objc_condition_broadcast (objc_condition_t
__UNUSED_PARAM(condition
))
328 /* Wake up one thread waiting on this condition. */
330 __gthread_objc_condition_signal (objc_condition_t
__UNUSED_PARAM(condition
))
342 typedef unsigned long __gthread_key_t
;
359 } __gthread_recursive_mutex_t
;
361 #define __GTHREAD_ONCE_INIT {0, -1}
362 #define __GTHREAD_MUTEX_INIT_FUNCTION __gthread_mutex_init_function
363 #define __GTHREAD_MUTEX_INIT_DEFAULT {-1, 0}
364 #define __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION \
365 __gthread_recursive_mutex_init_function
366 #define __GTHREAD_RECURSIVE_MUTEX_INIT_DEFAULT {-1, 0, 0, 0}
368 #if defined (_WIN32) && !defined(__CYGWIN__)
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. */
374 extern int __mingwthr_key_dtor (unsigned long, void (*) (void *));
375 #endif /* _WIN32 && !__CYGWIN__ */
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
384 __gthr_i486_lock_cmp_xchg(long *__dest
, long __xchg
, long __comperand
)
387 __asm__
__volatile__ ("\n\
389 cmpxchg{l} {%4, %1|%1, %4}\n"
390 : "=a" (result
), "=m" (*__dest
)
391 : "0" (__comperand
), "m" (*__dest
), "r" (__xchg
)
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 */
401 __gthread_active_p (void)
403 #ifdef MINGW32_SUPPORTS_MT_EH
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
*);
426 __gthr_win32_recursive_mutex_init_function (__gthread_recursive_mutex_t
*);
427 extern int __gthr_win32_recursive_mutex_lock (__gthread_recursive_mutex_t
*);
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 __gthr_win32_recursive_mutex_destroy (__gthread_recursive_mutex_t
*);
436 __gthread_once (__gthread_once_t
*__once
, void (*__func
) (void))
438 if (__gthread_active_p ())
439 return __gthr_win32_once (__once
, __func
);
445 __gthread_key_create (__gthread_key_t
*__key
, void (*__dtor
) (void *))
447 return __gthr_win32_key_create (__key
, __dtor
);
451 __gthread_key_delete (__gthread_key_t __key
)
453 return __gthr_win32_key_delete (__key
);
457 __gthread_getspecific (__gthread_key_t __key
)
459 return __gthr_win32_getspecific (__key
);
463 __gthread_setspecific (__gthread_key_t __key
, const void *__ptr
)
465 return __gthr_win32_setspecific (__key
, __ptr
);
469 __gthread_mutex_init_function (__gthread_mutex_t
*__mutex
)
471 __gthr_win32_mutex_init_function (__mutex
);
475 __gthread_mutex_destroy (__gthread_mutex_t
*__mutex
)
477 __gthr_win32_mutex_destroy (__mutex
);
481 __gthread_mutex_lock (__gthread_mutex_t
*__mutex
)
483 if (__gthread_active_p ())
484 return __gthr_win32_mutex_lock (__mutex
);
490 __gthread_mutex_trylock (__gthread_mutex_t
*__mutex
)
492 if (__gthread_active_p ())
493 return __gthr_win32_mutex_trylock (__mutex
);
499 __gthread_mutex_unlock (__gthread_mutex_t
*__mutex
)
501 if (__gthread_active_p ())
502 return __gthr_win32_mutex_unlock (__mutex
);
508 __gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t
*__mutex
)
510 __gthr_win32_recursive_mutex_init_function (__mutex
);
514 __gthread_recursive_mutex_lock (__gthread_recursive_mutex_t
*__mutex
)
516 if (__gthread_active_p ())
517 return __gthr_win32_recursive_mutex_lock (__mutex
);
523 __gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t
*__mutex
)
525 if (__gthread_active_p ())
526 return __gthr_win32_recursive_mutex_trylock (__mutex
);
532 __gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t
*__mutex
)
534 if (__gthread_active_p ())
535 return __gthr_win32_recursive_mutex_unlock (__mutex
);
541 __gthread_recursive_mutex_destroy (__gthread_recursive_mutex_t
*__mutex
)
543 return __gthr_win32_recursive_mutex_destroy (__mutex
);
546 #else /* ! __GTHREAD_HIDE_WIN32API */
552 __gthread_once (__gthread_once_t
*__once
, void (*__func
) (void))
554 if (! __gthread_active_p ())
556 else if (__once
== NULL
|| __func
== NULL
)
561 if (InterlockedIncrement (&(__once
->started
)) == 0)
568 /* Another thread is currently executing the code, so wait for it
569 to finish; yield the CPU in the meantime. If performance
570 does become an issue, the solution is to use an Event that
571 we wait on here (and set above), but that implies a place to
572 create the event before this routine is called. */
573 while (! __once
->done
)
581 /* Windows32 thread local keys don't support destructors; this leads to
582 leaks, especially in threaded applications making extensive use of
583 C++ EH. Mingw uses a thread-support DLL to work-around this problem. */
585 __gthread_key_create (__gthread_key_t
*__key
,
586 void (*__dtor
) (void *) __attribute__((unused
)))
589 DWORD __tls_index
= TlsAlloc ();
590 if (__tls_index
!= 0xFFFFFFFF)
592 *__key
= __tls_index
;
593 #ifdef MINGW32_SUPPORTS_MT_EH
594 /* Mingw runtime will run the dtors in reverse order for each thread
595 when the thread exits. */
596 __status
= __mingwthr_key_dtor (*__key
, __dtor
);
600 __status
= (int) GetLastError ();
605 __gthread_key_delete (__gthread_key_t __key
)
607 return (TlsFree (__key
) != 0) ? 0 : (int) GetLastError ();
611 __gthread_getspecific (__gthread_key_t __key
)
616 __lasterror
= GetLastError ();
618 __ptr
= TlsGetValue (__key
);
620 SetLastError (__lasterror
);
626 __gthread_setspecific (__gthread_key_t __key
, const void *__ptr
)
628 if (TlsSetValue (__key
, CONST_CAST2(void *, const void *, __ptr
)) != 0)
631 return GetLastError ();
635 __gthread_mutex_init_function (__gthread_mutex_t
*__mutex
)
637 __mutex
->counter
= -1;
638 __mutex
->sema
= CreateSemaphore (NULL
, 0, 65535, NULL
);
642 __gthread_mutex_destroy (__gthread_mutex_t
*__mutex
)
644 CloseHandle ((HANDLE
) __mutex
->sema
);
648 __gthread_mutex_lock (__gthread_mutex_t
*__mutex
)
652 if (__gthread_active_p ())
654 if (InterlockedIncrement (&__mutex
->counter
) == 0 ||
655 WaitForSingleObject (__mutex
->sema
, INFINITE
) == WAIT_OBJECT_0
)
659 /* WaitForSingleObject returns WAIT_FAILED, and we can only do
660 some best-effort cleanup here. */
661 InterlockedDecrement (&__mutex
->counter
);
669 __gthread_mutex_trylock (__gthread_mutex_t
*__mutex
)
673 if (__gthread_active_p ())
675 if (__GTHR_W32_InterlockedCompareExchange (&__mutex
->counter
, 0, -1) < 0)
684 __gthread_mutex_unlock (__gthread_mutex_t
*__mutex
)
686 if (__gthread_active_p ())
688 if (InterlockedDecrement (&__mutex
->counter
) >= 0)
689 return ReleaseSemaphore (__mutex
->sema
, 1, NULL
) ? 0 : 1;
695 __gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t
*__mutex
)
697 __mutex
->counter
= -1;
700 __mutex
->sema
= CreateSemaphore (NULL
, 0, 65535, NULL
);
704 __gthread_recursive_mutex_lock (__gthread_recursive_mutex_t
*__mutex
)
706 if (__gthread_active_p ())
708 DWORD __me
= GetCurrentThreadId();
709 if (InterlockedIncrement (&__mutex
->counter
) == 0)
712 __mutex
->owner
= __me
;
714 else if (__mutex
->owner
== __me
)
716 InterlockedDecrement (&__mutex
->counter
);
719 else if (WaitForSingleObject (__mutex
->sema
, INFINITE
) == WAIT_OBJECT_0
)
722 __mutex
->owner
= __me
;
726 /* WaitForSingleObject returns WAIT_FAILED, and we can only do
727 some best-effort cleanup here. */
728 InterlockedDecrement (&__mutex
->counter
);
736 __gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t
*__mutex
)
738 if (__gthread_active_p ())
740 DWORD __me
= GetCurrentThreadId();
741 if (__GTHR_W32_InterlockedCompareExchange (&__mutex
->counter
, 0, -1) < 0)
744 __mutex
->owner
= __me
;
746 else if (__mutex
->owner
== __me
)
755 __gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t
*__mutex
)
757 if (__gthread_active_p ())
760 if (__mutex
->depth
== 0)
764 if (InterlockedDecrement (&__mutex
->counter
) >= 0)
765 return ReleaseSemaphore (__mutex
->sema
, 1, NULL
) ? 0 : 1;
772 __gthread_recursive_mutex_destroy (__gthread_recursive_mutex_t
*__mutex
)
774 CloseHandle ((HANDLE
) __mutex
->sema
);
778 #endif /* __GTHREAD_HIDE_WIN32API */
784 #endif /* _LIBOBJC */
786 #endif /* ! GCC_GTHR_WIN32_H */