1 /* Threads compatibility routines for libgcc2 and libobjc. */
2 /* Compile this one with gcc. */
3 /* Copyright (C) 2004, 2005 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. On FreeBSD 6 and later, libc also
119 exposes a dummy POSIX threads interface, similar to what Solaris 2.6 up
120 to 9 does. FreeBSD >= 700014 even provides a pthread_cancel stub in libc,
121 which means the alternate __gthread_active_p below cannot be used there. */
126 #if defined(__FreeBSD__) || defined(__sun) && defined(__svr4__)
128 static volatile int __gthread_active = -1;
131 __gthread_trigger (void)
133 __gthread_active = 1;
137 __gthread_active_p (void)
139 static pthread_mutex_t __gthread_active_mutex = PTHREAD_MUTEX_INITIALIZER;
140 static pthread_once_t __gthread_active_once = PTHREAD_ONCE_INIT;
142 /* Avoid reading __gthread_active twice on the main code path. */
143 int __gthread_active_latest_value = __gthread_active;
145 /* This test is not protected to avoid taking a lock on the main code
146 path so every update of __gthread_active in a threaded program must
147 be atomic with regard to the result of the test. */
148 if (__builtin_expect (__gthread_active_latest_value < 0, 0))
150 if (__gthrw_(pthread_once))
152 /* If this really is a threaded program, then we must ensure that
153 __gthread_active has been set to 1 before exiting this block. */
154 __gthrw_(pthread_mutex_lock) (&__gthread_active_mutex);
155 __gthrw_(pthread_once) (&__gthread_active_once, __gthread_trigger);
156 __gthrw_(pthread_mutex_unlock) (&__gthread_active_mutex);
159 /* Make sure we'll never enter this block again. */
160 if (__gthread_active < 0)
161 __gthread_active = 0;
163 __gthread_active_latest_value = __gthread_active;
166 return __gthread_active_latest_value != 0;
169 #else /* neither FreeBSD nor Solaris */
172 __gthread_active_p (void)
174 static void *const __gthread_active_ptr
175 = __extension__ (void *) &__gthrw_(pthread_cancel);
176 return __gthread_active_ptr != 0;
179 #endif /* FreeBSD or Solaris */
181 #else /* not SUPPORTS_WEAK */
184 __gthread_active_p (void)
189 #endif /* SUPPORTS_WEAK */
193 /* This is the config.h file in libobjc/ */
200 /* Key structure for maintaining thread specific storage */
201 static pthread_key_t _objc_thread_storage;
202 static pthread_attr_t _objc_thread_attribs;
204 /* Thread local storage for a single thread */
205 static void *thread_local_storage = NULL;
207 /* Backend initialization functions */
209 /* Initialize the threads subsystem. */
211 __gthread_objc_init_thread_system (void)
213 if (__gthread_active_p ())
215 /* Initialize the thread storage key. */
216 if (__gthrw_(pthread_key_create) (&_objc_thread_storage, NULL) == 0)
218 /* The normal default detach state for threads is
219 * PTHREAD_CREATE_JOINABLE which causes threads to not die
220 * when you think they should. */
221 if (__gthrw_(pthread_attr_init) (&_objc_thread_attribs) == 0
222 && __gthrw_(pthread_attr_setdetachstate) (&_objc_thread_attribs,
223 PTHREAD_CREATE_DETACHED) == 0)
231 /* Close the threads subsystem. */
233 __gthread_objc_close_thread_system (void)
235 if (__gthread_active_p ()
236 && __gthrw_(pthread_key_delete) (_objc_thread_storage) == 0
237 && __gthrw_(pthread_attr_destroy) (&_objc_thread_attribs) == 0)
243 /* Backend thread functions */
245 /* Create a new thread of execution. */
246 static inline objc_thread_t
247 __gthread_objc_thread_detach (void (*func)(void *), void *arg)
249 objc_thread_t thread_id;
250 pthread_t new_thread_handle;
252 if (!__gthread_active_p ())
255 if (!(__gthrw_(pthread_create) (&new_thread_handle, NULL, (void *) func, arg)))
256 thread_id = (objc_thread_t) new_thread_handle;
263 /* Set the current thread's priority. */
265 __gthread_objc_thread_set_priority (int priority)
267 if (!__gthread_active_p ())
271 #ifdef _POSIX_PRIORITY_SCHEDULING
272 #ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
273 pthread_t thread_id = __gthrw_(pthread_self) ();
275 struct sched_param params;
276 int priority_min, priority_max;
278 if (__gthrw_(pthread_getschedparam) (thread_id, &policy, ¶ms) == 0)
280 if ((priority_max = __gthrw_(sched_get_priority_max) (policy)) == -1)
283 if ((priority_min = __gthrw_(sched_get_priority_min) (policy)) == -1)
286 if (priority > priority_max)
287 priority = priority_max;
288 else if (priority < priority_min)
289 priority = priority_min;
290 params.sched_priority = priority;
293 * The solaris 7 and several other man pages incorrectly state that
294 * this should be a pointer to policy but pthread.h is universally
297 if (__gthrw_(pthread_setschedparam) (thread_id, policy, ¶ms) == 0)
300 #endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
301 #endif /* _POSIX_PRIORITY_SCHEDULING */
306 /* Return the current thread's priority. */
308 __gthread_objc_thread_get_priority (void)
310 #ifdef _POSIX_PRIORITY_SCHEDULING
311 #ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
312 if (__gthread_active_p ())
315 struct sched_param params;
317 if (__gthrw_(pthread_getschedparam) (__gthrw_(pthread_self) (), &policy, ¶ms) == 0)
318 return params.sched_priority;
323 #endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
324 #endif /* _POSIX_PRIORITY_SCHEDULING */
325 return OBJC_THREAD_INTERACTIVE_PRIORITY;
328 /* Yield our process time to another thread. */
330 __gthread_objc_thread_yield (void)
332 if (__gthread_active_p ())
333 __gthrw_(sched_yield) ();
336 /* Terminate the current thread. */
338 __gthread_objc_thread_exit (void)
340 if (__gthread_active_p ())
341 /* exit the thread */
342 __gthrw_(pthread_exit) (&__objc_thread_exit_status);
344 /* Failed if we reached here */
348 /* Returns an integer value which uniquely describes a thread. */
349 static inline objc_thread_t
350 __gthread_objc_thread_id (void)
352 if (__gthread_active_p ())
353 return (objc_thread_t) __gthrw_(pthread_self) ();
355 return (objc_thread_t) 1;
358 /* Sets the thread's local storage pointer. */
360 __gthread_objc_thread_set_data (void *value)
362 if (__gthread_active_p ())
363 return __gthrw_(pthread_setspecific) (_objc_thread_storage, value);
366 thread_local_storage = value;
371 /* Returns the thread's local storage pointer. */
373 __gthread_objc_thread_get_data (void)
375 if (__gthread_active_p ())
376 return __gthrw_(pthread_getspecific) (_objc_thread_storage);
378 return thread_local_storage;
381 /* Backend mutex functions */
383 /* Allocate a mutex. */
385 __gthread_objc_mutex_allocate (objc_mutex_t mutex)
387 if (__gthread_active_p ())
389 mutex->backend = objc_malloc (sizeof (pthread_mutex_t));
391 if (__gthrw_(pthread_mutex_init) ((pthread_mutex_t *) mutex->backend, NULL))
393 objc_free (mutex->backend);
394 mutex->backend = NULL;
402 /* Deallocate a mutex. */
404 __gthread_objc_mutex_deallocate (objc_mutex_t mutex)
406 if (__gthread_active_p ())
411 * Posix Threads specifically require that the thread be unlocked
412 * for __gthrw_(pthread_mutex_destroy) to work.
417 count = __gthrw_(pthread_mutex_unlock) ((pthread_mutex_t *) mutex->backend);
423 if (__gthrw_(pthread_mutex_destroy) ((pthread_mutex_t *) mutex->backend))
426 objc_free (mutex->backend);
427 mutex->backend = NULL;
432 /* Grab a lock on a mutex. */
434 __gthread_objc_mutex_lock (objc_mutex_t mutex)
436 if (__gthread_active_p ()
437 && __gthrw_(pthread_mutex_lock) ((pthread_mutex_t *) mutex->backend) != 0)
445 /* Try to grab a lock on a mutex. */
447 __gthread_objc_mutex_trylock (objc_mutex_t mutex)
449 if (__gthread_active_p ()
450 && __gthrw_(pthread_mutex_trylock) ((pthread_mutex_t *) mutex->backend) != 0)
458 /* Unlock the mutex */
460 __gthread_objc_mutex_unlock (objc_mutex_t mutex)
462 if (__gthread_active_p ()
463 && __gthrw_(pthread_mutex_unlock) ((pthread_mutex_t *) mutex->backend) != 0)
471 /* Backend condition mutex functions */
473 /* Allocate a condition. */
475 __gthread_objc_condition_allocate (objc_condition_t condition)
477 if (__gthread_active_p ())
479 condition->backend = objc_malloc (sizeof (pthread_cond_t));
481 if (__gthrw_(pthread_cond_init) ((pthread_cond_t *) condition->backend, NULL))
483 objc_free (condition->backend);
484 condition->backend = NULL;
492 /* Deallocate a condition. */
494 __gthread_objc_condition_deallocate (objc_condition_t condition)
496 if (__gthread_active_p ())
498 if (__gthrw_(pthread_cond_destroy) ((pthread_cond_t *) condition->backend))
501 objc_free (condition->backend);
502 condition->backend = NULL;
507 /* Wait on the condition */
509 __gthread_objc_condition_wait (objc_condition_t condition, objc_mutex_t mutex)
511 if (__gthread_active_p ())
512 return __gthrw_(pthread_cond_wait) ((pthread_cond_t *) condition->backend,
513 (pthread_mutex_t *) mutex->backend);
518 /* Wake up all threads waiting on this condition. */
520 __gthread_objc_condition_broadcast (objc_condition_t condition)
522 if (__gthread_active_p ())
523 return __gthrw_(pthread_cond_broadcast) ((pthread_cond_t *) condition->backend);
528 /* Wake up one thread waiting on this condition. */
530 __gthread_objc_condition_signal (objc_condition_t condition)
532 if (__gthread_active_p ())
533 return __gthrw_(pthread_cond_signal) ((pthread_cond_t *) condition->backend);
541 __gthread_once (__gthread_once_t *once, void (*func) (void))
543 if (__gthread_active_p ())
544 return __gthrw_(pthread_once) (once, func);
550 __gthread_key_create (__gthread_key_t *key, void (*dtor) (void *))
552 return __gthrw_(pthread_key_create) (key, dtor);
556 __gthread_key_delete (__gthread_key_t key)
558 return __gthrw_(pthread_key_delete) (key);
562 __gthread_getspecific (__gthread_key_t key)
564 return __gthrw_(pthread_getspecific) (key);
568 __gthread_setspecific (__gthread_key_t key, const void *ptr)
570 return __gthrw_(pthread_setspecific) (key, ptr);
574 __gthread_mutex_lock (__gthread_mutex_t *mutex)
576 if (__gthread_active_p ())
577 return __gthrw_(pthread_mutex_lock) (mutex);
583 __gthread_mutex_trylock (__gthread_mutex_t *mutex)
585 if (__gthread_active_p ())
586 return __gthrw_(pthread_mutex_trylock) (mutex);
592 __gthread_mutex_unlock (__gthread_mutex_t *mutex)
594 if (__gthread_active_p ())
595 return __gthrw_(pthread_mutex_unlock) (mutex);
601 __gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *mutex)
604 mutex->owner = (pthread_t) 0;
605 return __gthrw_(pthread_mutex_init) (&mutex->actual, NULL);
609 __gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex)
611 if (__gthread_active_p ())
613 pthread_t me = __gthrw_(pthread_self) ();
615 if (mutex->owner != me)
617 __gthrw_(pthread_mutex_lock) (&mutex->actual);
627 __gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex)
629 if (__gthread_active_p ())
631 pthread_t me = __gthrw_(pthread_self) ();
633 if (mutex->owner != me)
635 if (__gthrw_(pthread_mutex_trylock) (&mutex->actual))
646 __gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex)
648 if (__gthread_active_p ())
650 if (--mutex->depth == 0)
652 mutex->owner = (pthread_t) 0;
653 __gthrw_(pthread_mutex_unlock) (&mutex->actual);
659 #endif /* _LIBOBJC */
661 #endif /* ! GCC_GTHR_POSIX_H */