1 /* Threads compatibility routines for libgcc2 and libobjc. */
2 /* Compile this one with gcc. */
3 /* Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING. If not, write to the Free
19 Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
22 /* As a special exception, if you link this library with other files,
23 some of which are compiled with GCC, to produce an executable,
24 this library does not by itself cause the resulting executable
25 to be covered by the GNU General Public License.
26 This exception does not however invalidate any other reasons why
27 the executable file might be covered by the GNU General Public License. */
29 #ifndef GCC_GTHR_POSIX_H
30 #define GCC_GTHR_POSIX_H
32 /* POSIX threads specific definitions.
33 Easy, since the interface is just one-to-one mapping. */
37 /* Some implementations of <pthread.h> require this to be defined. */
45 typedef pthread_key_t __gthread_key_t;
46 typedef pthread_once_t __gthread_once_t;
47 typedef pthread_mutex_t __gthread_mutex_t;
52 pthread_mutex_t actual;
53 } __gthread_recursive_mutex_t;
55 #define __GTHREAD_MUTEX_INIT PTHREAD_MUTEX_INITIALIZER
56 #define __GTHREAD_ONCE_INIT PTHREAD_ONCE_INIT
57 #define __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION __gthread_recursive_mutex_init_function
59 #if SUPPORTS_WEAK && GTHREAD_USE_WEAK
60 # define __gthrw(name) \
61 static __typeof(name) __gthrw_ ## name __attribute__ ((__weakref__(#name)));
62 # define __gthrw_(name) __gthrw_ ## name
64 # define __gthrw(name)
65 # define __gthrw_(name) name
69 __gthrw(pthread_key_create)
70 __gthrw(pthread_key_delete)
71 __gthrw(pthread_getspecific)
72 __gthrw(pthread_setspecific)
73 __gthrw(pthread_create)
74 __gthrw(pthread_cancel)
77 __gthrw(pthread_mutex_lock)
78 __gthrw(pthread_mutex_trylock)
79 __gthrw(pthread_mutex_unlock)
80 __gthrw(pthread_mutexattr_init)
81 __gthrw(pthread_mutexattr_destroy)
83 __gthrw(pthread_mutex_init)
85 #if defined(_LIBOBJC) || defined(_LIBOBJC_WEAK)
87 __gthrw(pthread_cond_broadcast)
88 __gthrw(pthread_cond_destroy)
89 __gthrw(pthread_cond_init)
90 __gthrw(pthread_cond_signal)
91 __gthrw(pthread_cond_wait)
93 __gthrw(pthread_mutex_destroy)
94 #ifdef _POSIX_PRIORITY_SCHEDULING
95 #ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
96 __gthrw(sched_get_priority_max)
97 __gthrw(sched_get_priority_min)
98 #endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
99 #endif /* _POSIX_PRIORITY_SCHEDULING */
101 __gthrw(pthread_attr_destroy)
102 __gthrw(pthread_attr_init)
103 __gthrw(pthread_attr_setdetachstate)
104 #ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
105 __gthrw(pthread_getschedparam)
106 __gthrw(pthread_setschedparam)
107 #endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
108 #endif /* _LIBOBJC || _LIBOBJC_WEAK */
110 #if SUPPORTS_WEAK && GTHREAD_USE_WEAK
112 /* On Solaris 2.6 up to 9, the libc exposes a POSIX threads interface even if
113 -pthreads is not specified. The functions are dummies and most return an
114 error value. However pthread_once returns 0 without invoking the routine
115 it is passed so we cannot pretend that the interface is active if -pthreads
116 is not specified. On Solaris 2.5.1, the interface is not exposed at all so
117 we need to play the usual game with weak symbols. On Solaris 10 and up, a
118 working interface is always exposed. */
120 #if defined(__sun) && defined(__svr4__)
122 static volatile int __gthread_active = -1;
125 __gthread_trigger (void)
127 __gthread_active = 1;
131 __gthread_active_p (void)
133 static pthread_mutex_t __gthread_active_mutex = PTHREAD_MUTEX_INITIALIZER;
134 static pthread_once_t __gthread_active_once = PTHREAD_ONCE_INIT;
136 /* Avoid reading __gthread_active twice on the main code path. */
137 int __gthread_active_latest_value = __gthread_active;
139 /* This test is not protected to avoid taking a lock on the main code
140 path so every update of __gthread_active in a threaded program must
141 be atomic with regard to the result of the test. */
142 if (__builtin_expect (__gthread_active_latest_value < 0, 0))
144 if (__gthrw_(pthread_once))
146 /* If this really is a threaded program, then we must ensure that
147 __gthread_active has been set to 1 before exiting this block. */
148 __gthrw_(pthread_mutex_lock) (&__gthread_active_mutex);
149 __gthrw_(pthread_once) (&__gthread_active_once, __gthread_trigger);
150 __gthrw_(pthread_mutex_unlock) (&__gthread_active_mutex);
153 /* Make sure we'll never enter this block again. */
154 if (__gthread_active < 0)
155 __gthread_active = 0;
157 __gthread_active_latest_value = __gthread_active;
160 return __gthread_active_latest_value != 0;
163 #else /* not Solaris */
166 __gthread_active_p (void)
168 static void *const __gthread_active_ptr
169 = __extension__ (void *) &__gthrw_(pthread_cancel);
170 return __gthread_active_ptr != 0;
175 #else /* not SUPPORTS_WEAK */
177 /* Similar to Solaris, HP-UX 11 for PA-RISC provides stubs for pthread
178 calls in shared flavors of the HP-UX C library. Most of the stubs
179 have no functionality. The details are described in the "libc cumulative
180 patch" for each subversion of HP-UX 11. There are two special interfaces
181 provided for checking whether an application is linked to a pthread
182 library or not. However, these interfaces aren't available in early
183 libc versions. We also can't use pthread_once as some libc versions
184 call the init function. So, we use pthread_create to check whether it
185 is possible to create a thread or not. The stub implementation returns
186 the error number ENOSYS. */
188 #if defined(__hppa__) && defined(__hpux__)
192 static volatile int __gthread_active = -1;
195 __gthread_start (void *arg __attribute__((unused)))
200 static void __gthread_active_init (void) __attribute__((noinline));
202 __gthread_active_init (void)
204 static pthread_mutex_t __gthread_active_mutex = PTHREAD_MUTEX_INITIALIZER;
208 __gthrw_(pthread_mutex_lock) (&__gthread_active_mutex);
209 if (__gthread_active < 0)
211 result = __gthrw_(pthread_create) (&t, NULL, __gthread_start, NULL);
212 if (result != ENOSYS)
214 __gthread_active = 1;
216 __gthrw_(pthread_join) (t, NULL);
219 __gthread_active = 0;
221 __gthrw_(pthread_mutex_unlock) (&__gthread_active_mutex);
225 __gthread_active_p (void)
227 /* Avoid reading __gthread_active twice on the main code path. */
228 int __gthread_active_latest_value = __gthread_active;
230 /* This test is not protected to avoid taking a lock on the main code
231 path so every update of __gthread_active in a threaded program must
232 be atomic with regard to the result of the test. */
233 if (__builtin_expect (__gthread_active_latest_value < 0, 0))
235 __gthread_active_init ();
236 __gthread_active_latest_value = __gthread_active;
239 return __gthread_active_latest_value != 0;
242 #else /* not hppa-hpux */
245 __gthread_active_p (void)
250 #endif /* hppa-hpux */
252 #endif /* SUPPORTS_WEAK */
256 /* This is the config.h file in libobjc/ */
263 /* Key structure for maintaining thread specific storage */
264 static pthread_key_t _objc_thread_storage;
265 static pthread_attr_t _objc_thread_attribs;
267 /* Thread local storage for a single thread */
268 static void *thread_local_storage = NULL;
270 /* Backend initialization functions */
272 /* Initialize the threads subsystem. */
274 __gthread_objc_init_thread_system (void)
276 if (__gthread_active_p ())
278 /* Initialize the thread storage key. */
279 if (__gthrw_(pthread_key_create) (&_objc_thread_storage, NULL) == 0)
281 /* The normal default detach state for threads is
282 * PTHREAD_CREATE_JOINABLE which causes threads to not die
283 * when you think they should. */
284 if (__gthrw_(pthread_attr_init) (&_objc_thread_attribs) == 0
285 && __gthrw_(pthread_attr_setdetachstate) (&_objc_thread_attribs,
286 PTHREAD_CREATE_DETACHED) == 0)
294 /* Close the threads subsystem. */
296 __gthread_objc_close_thread_system (void)
298 if (__gthread_active_p ()
299 && __gthrw_(pthread_key_delete) (_objc_thread_storage) == 0
300 && __gthrw_(pthread_attr_destroy) (&_objc_thread_attribs) == 0)
306 /* Backend thread functions */
308 /* Create a new thread of execution. */
309 static inline objc_thread_t
310 __gthread_objc_thread_detach (void (*func)(void *), void *arg)
312 objc_thread_t thread_id;
313 pthread_t new_thread_handle;
315 if (!__gthread_active_p ())
318 if (!(__gthrw_(pthread_create) (&new_thread_handle, NULL, (void *) func, arg)))
319 thread_id = (objc_thread_t) new_thread_handle;
326 /* Set the current thread's priority. */
328 __gthread_objc_thread_set_priority (int priority)
330 if (!__gthread_active_p ())
334 #ifdef _POSIX_PRIORITY_SCHEDULING
335 #ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
336 pthread_t thread_id = __gthrw_(pthread_self) ();
338 struct sched_param params;
339 int priority_min, priority_max;
341 if (__gthrw_(pthread_getschedparam) (thread_id, &policy, ¶ms) == 0)
343 if ((priority_max = __gthrw_(sched_get_priority_max) (policy)) == -1)
346 if ((priority_min = __gthrw_(sched_get_priority_min) (policy)) == -1)
349 if (priority > priority_max)
350 priority = priority_max;
351 else if (priority < priority_min)
352 priority = priority_min;
353 params.sched_priority = priority;
356 * The solaris 7 and several other man pages incorrectly state that
357 * this should be a pointer to policy but pthread.h is universally
360 if (__gthrw_(pthread_setschedparam) (thread_id, policy, ¶ms) == 0)
363 #endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
364 #endif /* _POSIX_PRIORITY_SCHEDULING */
369 /* Return the current thread's priority. */
371 __gthread_objc_thread_get_priority (void)
373 #ifdef _POSIX_PRIORITY_SCHEDULING
374 #ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
375 if (__gthread_active_p ())
378 struct sched_param params;
380 if (__gthrw_(pthread_getschedparam) (__gthrw_(pthread_self) (), &policy, ¶ms) == 0)
381 return params.sched_priority;
386 #endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
387 #endif /* _POSIX_PRIORITY_SCHEDULING */
388 return OBJC_THREAD_INTERACTIVE_PRIORITY;
391 /* Yield our process time to another thread. */
393 __gthread_objc_thread_yield (void)
395 if (__gthread_active_p ())
396 __gthrw_(sched_yield) ();
399 /* Terminate the current thread. */
401 __gthread_objc_thread_exit (void)
403 if (__gthread_active_p ())
404 /* exit the thread */
405 __gthrw_(pthread_exit) (&__objc_thread_exit_status);
407 /* Failed if we reached here */
411 /* Returns an integer value which uniquely describes a thread. */
412 static inline objc_thread_t
413 __gthread_objc_thread_id (void)
415 if (__gthread_active_p ())
416 return (objc_thread_t) __gthrw_(pthread_self) ();
418 return (objc_thread_t) 1;
421 /* Sets the thread's local storage pointer. */
423 __gthread_objc_thread_set_data (void *value)
425 if (__gthread_active_p ())
426 return __gthrw_(pthread_setspecific) (_objc_thread_storage, value);
429 thread_local_storage = value;
434 /* Returns the thread's local storage pointer. */
436 __gthread_objc_thread_get_data (void)
438 if (__gthread_active_p ())
439 return __gthrw_(pthread_getspecific) (_objc_thread_storage);
441 return thread_local_storage;
444 /* Backend mutex functions */
446 /* Allocate a mutex. */
448 __gthread_objc_mutex_allocate (objc_mutex_t mutex)
450 if (__gthread_active_p ())
452 mutex->backend = objc_malloc (sizeof (pthread_mutex_t));
454 if (__gthrw_(pthread_mutex_init) ((pthread_mutex_t *) mutex->backend, NULL))
456 objc_free (mutex->backend);
457 mutex->backend = NULL;
465 /* Deallocate a mutex. */
467 __gthread_objc_mutex_deallocate (objc_mutex_t mutex)
469 if (__gthread_active_p ())
474 * Posix Threads specifically require that the thread be unlocked
475 * for __gthrw_(pthread_mutex_destroy) to work.
480 count = __gthrw_(pthread_mutex_unlock) ((pthread_mutex_t *) mutex->backend);
486 if (__gthrw_(pthread_mutex_destroy) ((pthread_mutex_t *) mutex->backend))
489 objc_free (mutex->backend);
490 mutex->backend = NULL;
495 /* Grab a lock on a mutex. */
497 __gthread_objc_mutex_lock (objc_mutex_t mutex)
499 if (__gthread_active_p ()
500 && __gthrw_(pthread_mutex_lock) ((pthread_mutex_t *) mutex->backend) != 0)
508 /* Try to grab a lock on a mutex. */
510 __gthread_objc_mutex_trylock (objc_mutex_t mutex)
512 if (__gthread_active_p ()
513 && __gthrw_(pthread_mutex_trylock) ((pthread_mutex_t *) mutex->backend) != 0)
521 /* Unlock the mutex */
523 __gthread_objc_mutex_unlock (objc_mutex_t mutex)
525 if (__gthread_active_p ()
526 && __gthrw_(pthread_mutex_unlock) ((pthread_mutex_t *) mutex->backend) != 0)
534 /* Backend condition mutex functions */
536 /* Allocate a condition. */
538 __gthread_objc_condition_allocate (objc_condition_t condition)
540 if (__gthread_active_p ())
542 condition->backend = objc_malloc (sizeof (pthread_cond_t));
544 if (__gthrw_(pthread_cond_init) ((pthread_cond_t *) condition->backend, NULL))
546 objc_free (condition->backend);
547 condition->backend = NULL;
555 /* Deallocate a condition. */
557 __gthread_objc_condition_deallocate (objc_condition_t condition)
559 if (__gthread_active_p ())
561 if (__gthrw_(pthread_cond_destroy) ((pthread_cond_t *) condition->backend))
564 objc_free (condition->backend);
565 condition->backend = NULL;
570 /* Wait on the condition */
572 __gthread_objc_condition_wait (objc_condition_t condition, objc_mutex_t mutex)
574 if (__gthread_active_p ())
575 return __gthrw_(pthread_cond_wait) ((pthread_cond_t *) condition->backend,
576 (pthread_mutex_t *) mutex->backend);
581 /* Wake up all threads waiting on this condition. */
583 __gthread_objc_condition_broadcast (objc_condition_t condition)
585 if (__gthread_active_p ())
586 return __gthrw_(pthread_cond_broadcast) ((pthread_cond_t *) condition->backend);
591 /* Wake up one thread waiting on this condition. */
593 __gthread_objc_condition_signal (objc_condition_t condition)
595 if (__gthread_active_p ())
596 return __gthrw_(pthread_cond_signal) ((pthread_cond_t *) condition->backend);
604 __gthread_once (__gthread_once_t *once, void (*func) (void))
606 if (__gthread_active_p ())
607 return __gthrw_(pthread_once) (once, func);
613 __gthread_key_create (__gthread_key_t *key, void (*dtor) (void *))
615 return __gthrw_(pthread_key_create) (key, dtor);
619 __gthread_key_delete (__gthread_key_t key)
621 return __gthrw_(pthread_key_delete) (key);
625 __gthread_getspecific (__gthread_key_t key)
627 return __gthrw_(pthread_getspecific) (key);
631 __gthread_setspecific (__gthread_key_t key, const void *ptr)
633 return __gthrw_(pthread_setspecific) (key, ptr);
637 __gthread_mutex_lock (__gthread_mutex_t *mutex)
639 if (__gthread_active_p ())
640 return __gthrw_(pthread_mutex_lock) (mutex);
646 __gthread_mutex_trylock (__gthread_mutex_t *mutex)
648 if (__gthread_active_p ())
649 return __gthrw_(pthread_mutex_trylock) (mutex);
655 __gthread_mutex_unlock (__gthread_mutex_t *mutex)
657 if (__gthread_active_p ())
658 return __gthrw_(pthread_mutex_unlock) (mutex);
664 __gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *mutex)
667 mutex->owner = (pthread_t) 0;
668 return __gthrw_(pthread_mutex_init) (&mutex->actual, NULL);
672 __gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex)
674 if (__gthread_active_p ())
676 pthread_t me = __gthrw_(pthread_self) ();
678 if (mutex->owner != me)
680 __gthrw_(pthread_mutex_lock) (&mutex->actual);
690 __gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex)
692 if (__gthread_active_p ())
694 pthread_t me = __gthrw_(pthread_self) ();
696 if (mutex->owner != me)
698 if (__gthrw_(pthread_mutex_trylock) (&mutex->actual))
709 __gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex)
711 if (__gthread_active_p ())
713 if (--mutex->depth == 0)
715 mutex->owner = (pthread_t) 0;
716 __gthrw_(pthread_mutex_unlock) (&mutex->actual);
722 #endif /* _LIBOBJC */
724 #endif /* ! GCC_GTHR_POSIX_H */