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. */
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 */
178 __gthread_active_p (void)
183 #endif /* SUPPORTS_WEAK */
187 /* This is the config.h file in libobjc/ */
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. */
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)
225 /* Close the threads subsystem. */
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)
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 ())
249 if (!(__gthrw_(pthread_create
) (&new_thread_handle
, NULL
, (void *) func
, arg
)))
250 thread_id
= (objc_thread_t
) new_thread_handle
;
257 /* Set the current thread's priority. */
259 __gthread_objc_thread_set_priority (int priority
)
261 if (!__gthread_active_p ())
265 #ifdef _POSIX_PRIORITY_SCHEDULING
266 #ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
267 pthread_t thread_id
= __gthrw_(pthread_self
) ();
269 struct sched_param params
;
270 int priority_min
, priority_max
;
272 if (__gthrw_(pthread_getschedparam
) (thread_id
, &policy
, ¶ms
) == 0)
274 if ((priority_max
= __gthrw_(sched_get_priority_max
) (policy
)) == -1)
277 if ((priority_min
= __gthrw_(sched_get_priority_min
) (policy
)) == -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
291 if (__gthrw_(pthread_setschedparam
) (thread_id
, policy
, ¶ms
) == 0)
294 #endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
295 #endif /* _POSIX_PRIORITY_SCHEDULING */
300 /* Return the current thread's priority. */
302 __gthread_objc_thread_get_priority (void)
304 #ifdef _POSIX_PRIORITY_SCHEDULING
305 #ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
306 if (__gthread_active_p ())
309 struct sched_param params
;
311 if (__gthrw_(pthread_getschedparam
) (__gthrw_(pthread_self
) (), &policy
, ¶ms
) == 0)
312 return params
.sched_priority
;
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. */
324 __gthread_objc_thread_yield (void)
326 if (__gthread_active_p ())
327 __gthrw_(sched_yield
) ();
330 /* Terminate the current thread. */
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 */
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
) ();
349 return (objc_thread_t
) 1;
352 /* Sets the thread's local storage pointer. */
354 __gthread_objc_thread_set_data (void *value
)
356 if (__gthread_active_p ())
357 return __gthrw_(pthread_setspecific
) (_objc_thread_storage
, value
);
360 thread_local_storage
= value
;
365 /* Returns the thread's local storage pointer. */
367 __gthread_objc_thread_get_data (void)
369 if (__gthread_active_p ())
370 return __gthrw_(pthread_getspecific
) (_objc_thread_storage
);
372 return thread_local_storage
;
375 /* Backend mutex functions */
377 /* Allocate a mutex. */
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
;
396 /* Deallocate a mutex. */
398 __gthread_objc_mutex_deallocate (objc_mutex_t mutex
)
400 if (__gthread_active_p ())
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
);
417 if (__gthrw_(pthread_mutex_destroy
) ((pthread_mutex_t
*) mutex
->backend
))
420 objc_free (mutex
->backend
);
421 mutex
->backend
= NULL
;
426 /* Grab a lock on a mutex. */
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)
439 /* Try to grab a lock on a mutex. */
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)
452 /* Unlock the mutex */
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)
465 /* Backend condition mutex functions */
467 /* Allocate a condition. */
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
;
486 /* Deallocate a condition. */
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
))
495 objc_free (condition
->backend
);
496 condition
->backend
= NULL
;
501 /* Wait on the condition */
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
);
512 /* Wake up all threads waiting on this condition. */
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
);
522 /* Wake up one thread waiting on this condition. */
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
);
535 __gthread_once (__gthread_once_t
*once
, void (*func
) (void))
537 if (__gthread_active_p ())
538 return __gthrw_(pthread_once
) (once
, func
);
544 __gthread_key_create (__gthread_key_t
*key
, void (*dtor
) (void *))
546 return __gthrw_(pthread_key_create
) (key
, dtor
);
550 __gthread_key_delete (__gthread_key_t key
)
552 return __gthrw_(pthread_key_delete
) (key
);
556 __gthread_getspecific (__gthread_key_t key
)
558 return __gthrw_(pthread_getspecific
) (key
);
562 __gthread_setspecific (__gthread_key_t key
, const void *ptr
)
564 return __gthrw_(pthread_setspecific
) (key
, ptr
);
568 __gthread_mutex_lock (__gthread_mutex_t
*mutex
)
570 if (__gthread_active_p ())
571 return __gthrw_(pthread_mutex_lock
) (mutex
);
577 __gthread_mutex_trylock (__gthread_mutex_t
*mutex
)
579 if (__gthread_active_p ())
580 return __gthrw_(pthread_mutex_trylock
) (mutex
);
586 __gthread_mutex_unlock (__gthread_mutex_t
*mutex
)
588 if (__gthread_active_p ())
589 return __gthrw_(pthread_mutex_unlock
) (mutex
);
595 __gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t
*mutex
)
598 mutex
->owner
= (pthread_t
) 0;
599 return __gthrw_(pthread_mutex_init
) (&mutex
->actual
, NULL
);
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
);
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
))
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
);
653 #endif /* _LIBOBJC */
655 #endif /* ! GCC_GTHR_POSIX_H */