2007-05-04 Tobias Burnus <burnus@net-b.de>
[official-gcc.git] / gcc / gthr-posix95.h
blobfde264594f84da6800aa2e8a39fcefb7a4c44564
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
10 version.
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
15 for more details.
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
20 02110-1301, USA. */
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. */
35 #define __GTHREADS 1
37 /* Some implementations of <pthread.h> require this to be defined. */
38 #ifndef _REENTRANT
39 #define _REENTRANT 1
40 #endif
42 #include <pthread.h>
43 #include <unistd.h>
45 typedef pthread_key_t __gthread_key_t;
46 typedef pthread_once_t __gthread_once_t;
47 typedef pthread_mutex_t __gthread_mutex_t;
49 typedef struct {
50 long depth;
51 pthread_t owner;
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
63 #else
64 # define __gthrw(name)
65 # define __gthrw_(name) name
66 #endif
68 __gthrw(pthread_once)
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)
75 __gthrw(pthread_self)
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)
86 /* Objective-C. */
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)
92 __gthrw(pthread_exit)
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 */
100 __gthrw(sched_yield)
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;
124 static void
125 __gthread_trigger (void)
127 __gthread_active = 1;
130 static inline int
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 */
165 static inline int
166 __gthread_active_p (void)
168 static void *const __gthread_active_ptr
169 = __extension__ (void *) &__gthrw_(pthread_cancel);
170 return __gthread_active_ptr != 0;
173 #endif /* Solaris */
175 #else /* not SUPPORTS_WEAK */
177 static inline int
178 __gthread_active_p (void)
180 return 1;
183 #endif /* SUPPORTS_WEAK */
185 #ifdef _LIBOBJC
187 /* This is the config.h file in libobjc/ */
188 #include <config.h>
190 #ifdef HAVE_SCHED_H
191 # include <sched.h>
192 #endif
194 /* Key structure for maintaining thread specific storage */
195 static pthread_key_t _objc_thread_storage;
196 static pthread_attr_t _objc_thread_attribs;
198 /* Thread local storage for a single thread */
199 static void *thread_local_storage = NULL;
201 /* Backend initialization functions */
203 /* Initialize the threads subsystem. */
204 static inline int
205 __gthread_objc_init_thread_system (void)
207 if (__gthread_active_p ())
209 /* Initialize the thread storage key. */
210 if (__gthrw_(pthread_key_create) (&_objc_thread_storage, NULL) == 0)
212 /* The normal default detach state for threads is
213 * PTHREAD_CREATE_JOINABLE which causes threads to not die
214 * when you think they should. */
215 if (__gthrw_(pthread_attr_init) (&_objc_thread_attribs) == 0
216 && __gthrw_(pthread_attr_setdetachstate) (&_objc_thread_attribs,
217 PTHREAD_CREATE_DETACHED) == 0)
218 return 0;
222 return -1;
225 /* Close the threads subsystem. */
226 static inline int
227 __gthread_objc_close_thread_system (void)
229 if (__gthread_active_p ()
230 && __gthrw_(pthread_key_delete) (_objc_thread_storage) == 0
231 && __gthrw_(pthread_attr_destroy) (&_objc_thread_attribs) == 0)
232 return 0;
234 return -1;
237 /* Backend thread functions */
239 /* Create a new thread of execution. */
240 static inline objc_thread_t
241 __gthread_objc_thread_detach (void (*func)(void *), void *arg)
243 objc_thread_t thread_id;
244 pthread_t new_thread_handle;
246 if (!__gthread_active_p ())
247 return NULL;
249 if (!(__gthrw_(pthread_create) (&new_thread_handle, NULL, (void *) func, arg)))
250 thread_id = (objc_thread_t) new_thread_handle;
251 else
252 thread_id = NULL;
254 return thread_id;
257 /* Set the current thread's priority. */
258 static inline int
259 __gthread_objc_thread_set_priority (int priority)
261 if (!__gthread_active_p ())
262 return -1;
263 else
265 #ifdef _POSIX_PRIORITY_SCHEDULING
266 #ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
267 pthread_t thread_id = __gthrw_(pthread_self) ();
268 int policy;
269 struct sched_param params;
270 int priority_min, priority_max;
272 if (__gthrw_(pthread_getschedparam) (thread_id, &policy, &params) == 0)
274 if ((priority_max = __gthrw_(sched_get_priority_max) (policy)) == -1)
275 return -1;
277 if ((priority_min = __gthrw_(sched_get_priority_min) (policy)) == -1)
278 return -1;
280 if (priority > priority_max)
281 priority = priority_max;
282 else if (priority < priority_min)
283 priority = priority_min;
284 params.sched_priority = priority;
287 * The solaris 7 and several other man pages incorrectly state that
288 * this should be a pointer to policy but pthread.h is universally
289 * at odds with this.
291 if (__gthrw_(pthread_setschedparam) (thread_id, policy, &params) == 0)
292 return 0;
294 #endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
295 #endif /* _POSIX_PRIORITY_SCHEDULING */
296 return -1;
300 /* Return the current thread's priority. */
301 static inline int
302 __gthread_objc_thread_get_priority (void)
304 #ifdef _POSIX_PRIORITY_SCHEDULING
305 #ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
306 if (__gthread_active_p ())
308 int policy;
309 struct sched_param params;
311 if (__gthrw_(pthread_getschedparam) (__gthrw_(pthread_self) (), &policy, &params) == 0)
312 return params.sched_priority;
313 else
314 return -1;
316 else
317 #endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
318 #endif /* _POSIX_PRIORITY_SCHEDULING */
319 return OBJC_THREAD_INTERACTIVE_PRIORITY;
322 /* Yield our process time to another thread. */
323 static inline void
324 __gthread_objc_thread_yield (void)
326 if (__gthread_active_p ())
327 __gthrw_(sched_yield) ();
330 /* Terminate the current thread. */
331 static inline int
332 __gthread_objc_thread_exit (void)
334 if (__gthread_active_p ())
335 /* exit the thread */
336 __gthrw_(pthread_exit) (&__objc_thread_exit_status);
338 /* Failed if we reached here */
339 return -1;
342 /* Returns an integer value which uniquely describes a thread. */
343 static inline objc_thread_t
344 __gthread_objc_thread_id (void)
346 if (__gthread_active_p ())
347 return (objc_thread_t) __gthrw_(pthread_self) ();
348 else
349 return (objc_thread_t) 1;
352 /* Sets the thread's local storage pointer. */
353 static inline int
354 __gthread_objc_thread_set_data (void *value)
356 if (__gthread_active_p ())
357 return __gthrw_(pthread_setspecific) (_objc_thread_storage, value);
358 else
360 thread_local_storage = value;
361 return 0;
365 /* Returns the thread's local storage pointer. */
366 static inline void *
367 __gthread_objc_thread_get_data (void)
369 if (__gthread_active_p ())
370 return __gthrw_(pthread_getspecific) (_objc_thread_storage);
371 else
372 return thread_local_storage;
375 /* Backend mutex functions */
377 /* Allocate a mutex. */
378 static inline int
379 __gthread_objc_mutex_allocate (objc_mutex_t mutex)
381 if (__gthread_active_p ())
383 mutex->backend = objc_malloc (sizeof (pthread_mutex_t));
385 if (__gthrw_(pthread_mutex_init) ((pthread_mutex_t *) mutex->backend, NULL))
387 objc_free (mutex->backend);
388 mutex->backend = NULL;
389 return -1;
393 return 0;
396 /* Deallocate a mutex. */
397 static inline int
398 __gthread_objc_mutex_deallocate (objc_mutex_t mutex)
400 if (__gthread_active_p ())
402 int count;
405 * Posix Threads specifically require that the thread be unlocked
406 * for __gthrw_(pthread_mutex_destroy) to work.
411 count = __gthrw_(pthread_mutex_unlock) ((pthread_mutex_t *) mutex->backend);
412 if (count < 0)
413 return -1;
415 while (count);
417 if (__gthrw_(pthread_mutex_destroy) ((pthread_mutex_t *) mutex->backend))
418 return -1;
420 objc_free (mutex->backend);
421 mutex->backend = NULL;
423 return 0;
426 /* Grab a lock on a mutex. */
427 static inline int
428 __gthread_objc_mutex_lock (objc_mutex_t mutex)
430 if (__gthread_active_p ()
431 && __gthrw_(pthread_mutex_lock) ((pthread_mutex_t *) mutex->backend) != 0)
433 return -1;
436 return 0;
439 /* Try to grab a lock on a mutex. */
440 static inline int
441 __gthread_objc_mutex_trylock (objc_mutex_t mutex)
443 if (__gthread_active_p ()
444 && __gthrw_(pthread_mutex_trylock) ((pthread_mutex_t *) mutex->backend) != 0)
446 return -1;
449 return 0;
452 /* Unlock the mutex */
453 static inline int
454 __gthread_objc_mutex_unlock (objc_mutex_t mutex)
456 if (__gthread_active_p ()
457 && __gthrw_(pthread_mutex_unlock) ((pthread_mutex_t *) mutex->backend) != 0)
459 return -1;
462 return 0;
465 /* Backend condition mutex functions */
467 /* Allocate a condition. */
468 static inline int
469 __gthread_objc_condition_allocate (objc_condition_t condition)
471 if (__gthread_active_p ())
473 condition->backend = objc_malloc (sizeof (pthread_cond_t));
475 if (__gthrw_(pthread_cond_init) ((pthread_cond_t *) condition->backend, NULL))
477 objc_free (condition->backend);
478 condition->backend = NULL;
479 return -1;
483 return 0;
486 /* Deallocate a condition. */
487 static inline int
488 __gthread_objc_condition_deallocate (objc_condition_t condition)
490 if (__gthread_active_p ())
492 if (__gthrw_(pthread_cond_destroy) ((pthread_cond_t *) condition->backend))
493 return -1;
495 objc_free (condition->backend);
496 condition->backend = NULL;
498 return 0;
501 /* Wait on the condition */
502 static inline int
503 __gthread_objc_condition_wait (objc_condition_t condition, objc_mutex_t mutex)
505 if (__gthread_active_p ())
506 return __gthrw_(pthread_cond_wait) ((pthread_cond_t *) condition->backend,
507 (pthread_mutex_t *) mutex->backend);
508 else
509 return 0;
512 /* Wake up all threads waiting on this condition. */
513 static inline int
514 __gthread_objc_condition_broadcast (objc_condition_t condition)
516 if (__gthread_active_p ())
517 return __gthrw_(pthread_cond_broadcast) ((pthread_cond_t *) condition->backend);
518 else
519 return 0;
522 /* Wake up one thread waiting on this condition. */
523 static inline int
524 __gthread_objc_condition_signal (objc_condition_t condition)
526 if (__gthread_active_p ())
527 return __gthrw_(pthread_cond_signal) ((pthread_cond_t *) condition->backend);
528 else
529 return 0;
532 #else /* _LIBOBJC */
534 static inline int
535 __gthread_once (__gthread_once_t *once, void (*func) (void))
537 if (__gthread_active_p ())
538 return __gthrw_(pthread_once) (once, func);
539 else
540 return -1;
543 static inline int
544 __gthread_key_create (__gthread_key_t *key, void (*dtor) (void *))
546 return __gthrw_(pthread_key_create) (key, dtor);
549 static inline int
550 __gthread_key_delete (__gthread_key_t key)
552 return __gthrw_(pthread_key_delete) (key);
555 static inline void *
556 __gthread_getspecific (__gthread_key_t key)
558 return __gthrw_(pthread_getspecific) (key);
561 static inline int
562 __gthread_setspecific (__gthread_key_t key, const void *ptr)
564 return __gthrw_(pthread_setspecific) (key, ptr);
567 static inline int
568 __gthread_mutex_lock (__gthread_mutex_t *mutex)
570 if (__gthread_active_p ())
571 return __gthrw_(pthread_mutex_lock) (mutex);
572 else
573 return 0;
576 static inline int
577 __gthread_mutex_trylock (__gthread_mutex_t *mutex)
579 if (__gthread_active_p ())
580 return __gthrw_(pthread_mutex_trylock) (mutex);
581 else
582 return 0;
585 static inline int
586 __gthread_mutex_unlock (__gthread_mutex_t *mutex)
588 if (__gthread_active_p ())
589 return __gthrw_(pthread_mutex_unlock) (mutex);
590 else
591 return 0;
594 static inline int
595 __gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *mutex)
597 mutex->depth = 0;
598 mutex->owner = (pthread_t) 0;
599 return __gthrw_(pthread_mutex_init) (&mutex->actual, NULL);
602 static inline int
603 __gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex)
605 if (__gthread_active_p ())
607 pthread_t me = __gthrw_(pthread_self) ();
609 if (mutex->owner != me)
611 __gthrw_(pthread_mutex_lock) (&mutex->actual);
612 mutex->owner = me;
615 mutex->depth++;
617 return 0;
620 static inline int
621 __gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex)
623 if (__gthread_active_p ())
625 pthread_t me = __gthrw_(pthread_self) ();
627 if (mutex->owner != me)
629 if (__gthrw_(pthread_mutex_trylock) (&mutex->actual))
630 return 1;
631 mutex->owner = me;
634 mutex->depth++;
636 return 0;
639 static inline int
640 __gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex)
642 if (__gthread_active_p ())
644 if (--mutex->depth == 0)
646 mutex->owner = (pthread_t) 0;
647 __gthrw_(pthread_mutex_unlock) (&mutex->actual);
650 return 0;
653 #endif /* _LIBOBJC */
655 #endif /* ! GCC_GTHR_POSIX_H */