1/* Threads compatibility routines for libgcc2 and libobjc.  */
2/* Compile this one with gcc.  */
3/* Copyright (C) 1997, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
4   Free Software Foundation, Inc.
5
6This file is part of GCC.
7
8GCC is free software; you can redistribute it and/or modify it under
9the terms of the GNU General Public License as published by the Free
10Software Foundation; either version 2, or (at your option) any later
11version.
12
13GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14WARRANTY; without even the implied warranty of MERCHANTABILITY or
15FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16for more details.
17
18You should have received a copy of the GNU General Public License
19along with GCC; see the file COPYING.  If not, write to the Free
20Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
2102110-1301, USA.  */
22
23/* As a special exception, if you link this library with other files,
24   some of which are compiled with GCC, to produce an executable,
25   this library does not by itself cause the resulting executable
26   to be covered by the GNU General Public License.
27   This exception does not however invalidate any other reasons why
28   the executable file might be covered by the GNU General Public License.  */
29
30#ifndef GCC_GTHR_POSIX_H
31#define GCC_GTHR_POSIX_H
32
33/* POSIX threads specific definitions.
34   Easy, since the interface is just one-to-one mapping.  */
35
36#define __GTHREADS 1
37
38/* Some implementations of <pthread.h> require this to be defined.  */
39#if !defined(_REENTRANT) && defined(__osf__)
40#define _REENTRANT 1
41#endif
42
43#include <pthread.h>
44#include <unistd.h>
45
46typedef pthread_key_t __gthread_key_t;
47typedef pthread_once_t __gthread_once_t;
48typedef pthread_mutex_t __gthread_mutex_t;
49typedef pthread_mutex_t __gthread_recursive_mutex_t;
50
51#define __GTHREAD_MUTEX_INIT PTHREAD_MUTEX_INITIALIZER
52#define __GTHREAD_ONCE_INIT PTHREAD_ONCE_INIT
53#if defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER)
54#define __GTHREAD_RECURSIVE_MUTEX_INIT PTHREAD_RECURSIVE_MUTEX_INITIALIZER
55#elif defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP)
56#define __GTHREAD_RECURSIVE_MUTEX_INIT PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
57#else
58#define __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION __gthread_recursive_mutex_init_function
59#endif
60
61#if SUPPORTS_WEAK && GTHREAD_USE_WEAK
62# ifndef __gthrw_pragma
63#  define __gthrw_pragma(pragma)
64# endif
65# ifdef __clang__
66# define __gthrw2(name,name2,type) \
67  static __typeof(type) name __attribute__ ((__weakref__(#name2))); \
68  __gthrw_pragma(weak type)
69# else
70# define __gthrw2(name,name2,type) \
71  extern __typeof(type) name __attribute__ ((__weakref__(#name2))); \
72  __gthrw_pragma(weak type)
73# endif
74# define __gthrw_(name) __gthrw_ ## name
75#else
76# define __gthrw2(name,name2,type)
77# define __gthrw_(name) name
78#endif
79
80/* Typically, __gthrw_foo is a weak reference to symbol foo.  */
81#define __gthrw(name) __gthrw2(__gthrw_ ## name,name,name)
82
83/* On Tru64, /usr/include/pthread.h uses #pragma extern_prefix "__" to
84   map a subset of the POSIX pthread API to mangled versions of their
85   names.  */
86#if defined(__osf__) && defined(_PTHREAD_USE_MANGLED_NAMES_)
87#define __gthrw3(name) __gthrw2(__gthrw_ ## name, __ ## name, name)
88__gthrw3(pthread_once)
89__gthrw3(pthread_getspecific)
90__gthrw3(pthread_setspecific)
91__gthrw3(pthread_create)
92__gthrw3(pthread_cancel)
93__gthrw3(pthread_mutex_lock)
94__gthrw3(pthread_mutex_trylock)
95__gthrw3(pthread_mutex_unlock)
96__gthrw3(pthread_mutex_init)
97#else
98__gthrw(pthread_once)
99__gthrw(pthread_getspecific)
100__gthrw(pthread_setspecific)
101__gthrw(pthread_create)
102__gthrw(pthread_cancel)
103__gthrw(pthread_mutex_lock)
104__gthrw(pthread_mutex_trylock)
105__gthrw(pthread_mutex_unlock)
106__gthrw(pthread_mutex_init)
107#endif
108
109__gthrw(pthread_key_create)
110__gthrw(pthread_key_delete)
111__gthrw(pthread_mutexattr_init)
112__gthrw(pthread_mutexattr_settype)
113__gthrw(pthread_mutexattr_destroy)
114
115
116#if defined(_LIBOBJC) || defined(_LIBOBJC_WEAK)
117/* Objective-C.  */
118#if defined(__osf__) && defined(_PTHREAD_USE_MANGLED_NAMES_)
119__gthrw3(pthread_cond_broadcast)
120__gthrw3(pthread_cond_destroy)
121__gthrw3(pthread_cond_init)
122__gthrw3(pthread_cond_signal)
123__gthrw3(pthread_cond_wait)
124__gthrw3(pthread_exit)
125__gthrw3(pthread_mutex_destroy)
126__gthrw3(pthread_self)
127#else
128__gthrw(pthread_cond_broadcast)
129__gthrw(pthread_cond_destroy)
130__gthrw(pthread_cond_init)
131__gthrw(pthread_cond_signal)
132__gthrw(pthread_cond_wait)
133__gthrw(pthread_exit)
134__gthrw(pthread_mutex_destroy)
135__gthrw(pthread_self)
136#endif /* __osf__ && _PTHREAD_USE_MANGLED_NAMES_ */
137#ifdef _POSIX_PRIORITY_SCHEDULING
138#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
139__gthrw(sched_get_priority_max)
140__gthrw(sched_get_priority_min)
141#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
142#endif /* _POSIX_PRIORITY_SCHEDULING */
143__gthrw(sched_yield)
144__gthrw(pthread_attr_destroy)
145__gthrw(pthread_attr_init)
146__gthrw(pthread_attr_setdetachstate)
147#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
148__gthrw(pthread_getschedparam)
149__gthrw(pthread_setschedparam)
150#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
151#endif /* _LIBOBJC || _LIBOBJC_WEAK */
152
153#if SUPPORTS_WEAK && GTHREAD_USE_WEAK
154
155static inline int
156__gthread_active_p (void)
157{
158  static void *const __gthread_active_ptr
159    = __extension__ (void *) &__gthrw_(pthread_cancel);
160  return __gthread_active_ptr != 0;
161}
162
163#else /* not SUPPORTS_WEAK */
164
165static inline int
166__gthread_active_p (void)
167{
168  return 1;
169}
170
171#endif /* SUPPORTS_WEAK */
172
173#ifdef _LIBOBJC
174
175/* This is the config.h file in libobjc/ */
176#include <config.h>
177
178#ifdef HAVE_SCHED_H
179# include <sched.h>
180#endif
181
182/* Key structure for maintaining thread specific storage */
183static pthread_key_t _objc_thread_storage;
184static pthread_attr_t _objc_thread_attribs;
185
186/* Thread local storage for a single thread */
187static void *thread_local_storage = NULL;
188
189/* Backend initialization functions */
190
191/* Initialize the threads subsystem.  */
192static inline int
193__gthread_objc_init_thread_system (void)
194{
195  if (__gthread_active_p ())
196    {
197      /* Initialize the thread storage key.  */
198      if (__gthrw_(pthread_key_create) (&_objc_thread_storage, NULL) == 0)
199	{
200	  /* The normal default detach state for threads is
201	   * PTHREAD_CREATE_JOINABLE which causes threads to not die
202	   * when you think they should.  */
203	  if (__gthrw_(pthread_attr_init) (&_objc_thread_attribs) == 0
204	      && __gthrw_(pthread_attr_setdetachstate) (&_objc_thread_attribs,
205					      PTHREAD_CREATE_DETACHED) == 0)
206	    return 0;
207	}
208    }
209
210  return -1;
211}
212
213/* Close the threads subsystem.  */
214static inline int
215__gthread_objc_close_thread_system (void)
216{
217  if (__gthread_active_p ()
218      && __gthrw_(pthread_key_delete) (_objc_thread_storage) == 0
219      && __gthrw_(pthread_attr_destroy) (&_objc_thread_attribs) == 0)
220    return 0;
221
222  return -1;
223}
224
225/* Backend thread functions */
226
227/* Create a new thread of execution.  */
228static inline objc_thread_t
229__gthread_objc_thread_detach (void (*func)(void *), void *arg)
230{
231  objc_thread_t thread_id;
232  pthread_t new_thread_handle;
233
234  if (!__gthread_active_p ())
235    return NULL;
236
237  if (!(__gthrw_(pthread_create) (&new_thread_handle, NULL, (void *) func, arg)))
238    thread_id = (objc_thread_t) new_thread_handle;
239  else
240    thread_id = NULL;
241
242  return thread_id;
243}
244
245/* Set the current thread's priority.  */
246static inline int
247__gthread_objc_thread_set_priority (int priority)
248{
249  if (!__gthread_active_p ())
250    return -1;
251  else
252    {
253#ifdef _POSIX_PRIORITY_SCHEDULING
254#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
255      pthread_t thread_id = __gthrw_(pthread_self) ();
256      int policy;
257      struct sched_param params;
258      int priority_min, priority_max;
259
260      if (__gthrw_(pthread_getschedparam) (thread_id, &policy, &params) == 0)
261	{
262	  if ((priority_max = __gthrw_(sched_get_priority_max) (policy)) == -1)
263	    return -1;
264
265	  if ((priority_min = __gthrw_(sched_get_priority_min) (policy)) == -1)
266	    return -1;
267
268	  if (priority > priority_max)
269	    priority = priority_max;
270	  else if (priority < priority_min)
271	    priority = priority_min;
272	  params.sched_priority = priority;
273
274	  /*
275	   * The solaris 7 and several other man pages incorrectly state that
276	   * this should be a pointer to policy but pthread.h is universally
277	   * at odds with this.
278	   */
279	  if (__gthrw_(pthread_setschedparam) (thread_id, policy, &params) == 0)
280	    return 0;
281	}
282#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
283#endif /* _POSIX_PRIORITY_SCHEDULING */
284      return -1;
285    }
286}
287
288/* Return the current thread's priority.  */
289static inline int
290__gthread_objc_thread_get_priority (void)
291{
292#ifdef _POSIX_PRIORITY_SCHEDULING
293#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
294  if (__gthread_active_p ())
295    {
296      int policy;
297      struct sched_param params;
298
299      if (__gthrw_(pthread_getschedparam) (__gthrw_(pthread_self) (), &policy, &params) == 0)
300	return params.sched_priority;
301      else
302	return -1;
303    }
304  else
305#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
306#endif /* _POSIX_PRIORITY_SCHEDULING */
307    return OBJC_THREAD_INTERACTIVE_PRIORITY;
308}
309
310/* Yield our process time to another thread.  */
311static inline void
312__gthread_objc_thread_yield (void)
313{
314  if (__gthread_active_p ())
315    __gthrw_(sched_yield) ();
316}
317
318/* Terminate the current thread.  */
319static inline int
320__gthread_objc_thread_exit (void)
321{
322  if (__gthread_active_p ())
323    /* exit the thread */
324    __gthrw_(pthread_exit) (&__objc_thread_exit_status);
325
326  /* Failed if we reached here */
327  return -1;
328}
329
330/* Returns an integer value which uniquely describes a thread.  */
331static inline objc_thread_t
332__gthread_objc_thread_id (void)
333{
334  if (__gthread_active_p ())
335    return (objc_thread_t) __gthrw_(pthread_self) ();
336  else
337    return (objc_thread_t) 1;
338}
339
340/* Sets the thread's local storage pointer.  */
341static inline int
342__gthread_objc_thread_set_data (void *value)
343{
344  if (__gthread_active_p ())
345    return __gthrw_(pthread_setspecific) (_objc_thread_storage, value);
346  else
347    {
348      thread_local_storage = value;
349      return 0;
350    }
351}
352
353/* Returns the thread's local storage pointer.  */
354static inline void *
355__gthread_objc_thread_get_data (void)
356{
357  if (__gthread_active_p ())
358    return __gthrw_(pthread_getspecific) (_objc_thread_storage);
359  else
360    return thread_local_storage;
361}
362
363/* Backend mutex functions */
364
365/* Allocate a mutex.  */
366static inline int
367__gthread_objc_mutex_allocate (objc_mutex_t mutex)
368{
369  if (__gthread_active_p ())
370    {
371      mutex->backend = objc_malloc (sizeof (pthread_mutex_t));
372
373      if (__gthrw_(pthread_mutex_init) ((pthread_mutex_t *) mutex->backend, NULL))
374	{
375	  objc_free (mutex->backend);
376	  mutex->backend = NULL;
377	  return -1;
378	}
379    }
380
381  return 0;
382}
383
384/* Deallocate a mutex.  */
385static inline int
386__gthread_objc_mutex_deallocate (objc_mutex_t mutex)
387{
388  if (__gthread_active_p ())
389    {
390      int count;
391
392      /*
393       * Posix Threads specifically require that the thread be unlocked
394       * for __gthrw_(pthread_mutex_destroy) to work.
395       */
396
397      do
398	{
399	  count = __gthrw_(pthread_mutex_unlock) ((pthread_mutex_t *) mutex->backend);
400	  if (count < 0)
401	    return -1;
402	}
403      while (count);
404
405      if (__gthrw_(pthread_mutex_destroy) ((pthread_mutex_t *) mutex->backend))
406	return -1;
407
408      objc_free (mutex->backend);
409      mutex->backend = NULL;
410    }
411  return 0;
412}
413
414/* Grab a lock on a mutex.  */
415static inline int
416__gthread_objc_mutex_lock (objc_mutex_t mutex)
417{
418  if (__gthread_active_p ()
419      && __gthrw_(pthread_mutex_lock) ((pthread_mutex_t *) mutex->backend) != 0)
420    {
421      return -1;
422    }
423
424  return 0;
425}
426
427/* Try to grab a lock on a mutex.  */
428static inline int
429__gthread_objc_mutex_trylock (objc_mutex_t mutex)
430{
431  if (__gthread_active_p ()
432      && __gthrw_(pthread_mutex_trylock) ((pthread_mutex_t *) mutex->backend) != 0)
433    {
434      return -1;
435    }
436
437  return 0;
438}
439
440/* Unlock the mutex */
441static inline int
442__gthread_objc_mutex_unlock (objc_mutex_t mutex)
443{
444  if (__gthread_active_p ()
445      && __gthrw_(pthread_mutex_unlock) ((pthread_mutex_t *) mutex->backend) != 0)
446    {
447      return -1;
448    }
449
450  return 0;
451}
452
453/* Backend condition mutex functions */
454
455/* Allocate a condition.  */
456static inline int
457__gthread_objc_condition_allocate (objc_condition_t condition)
458{
459  if (__gthread_active_p ())
460    {
461      condition->backend = objc_malloc (sizeof (pthread_cond_t));
462
463      if (__gthrw_(pthread_cond_init) ((pthread_cond_t *) condition->backend, NULL))
464	{
465	  objc_free (condition->backend);
466	  condition->backend = NULL;
467	  return -1;
468	}
469    }
470
471  return 0;
472}
473
474/* Deallocate a condition.  */
475static inline int
476__gthread_objc_condition_deallocate (objc_condition_t condition)
477{
478  if (__gthread_active_p ())
479    {
480      if (__gthrw_(pthread_cond_destroy) ((pthread_cond_t *) condition->backend))
481	return -1;
482
483      objc_free (condition->backend);
484      condition->backend = NULL;
485    }
486  return 0;
487}
488
489/* Wait on the condition */
490static inline int
491__gthread_objc_condition_wait (objc_condition_t condition, objc_mutex_t mutex)
492{
493  if (__gthread_active_p ())
494    return __gthrw_(pthread_cond_wait) ((pthread_cond_t *) condition->backend,
495			      (pthread_mutex_t *) mutex->backend);
496  else
497    return 0;
498}
499
500/* Wake up all threads waiting on this condition.  */
501static inline int
502__gthread_objc_condition_broadcast (objc_condition_t condition)
503{
504  if (__gthread_active_p ())
505    return __gthrw_(pthread_cond_broadcast) ((pthread_cond_t *) condition->backend);
506  else
507    return 0;
508}
509
510/* Wake up one thread waiting on this condition.  */
511static inline int
512__gthread_objc_condition_signal (objc_condition_t condition)
513{
514  if (__gthread_active_p ())
515    return __gthrw_(pthread_cond_signal) ((pthread_cond_t *) condition->backend);
516  else
517    return 0;
518}
519
520#else /* _LIBOBJC */
521
522static inline int
523__gthread_once (__gthread_once_t *once, void (*func) (void))
524{
525  if (__gthread_active_p ())
526    return __gthrw_(pthread_once) (once, func);
527  else
528    return -1;
529}
530
531static inline int
532__gthread_key_create (__gthread_key_t *key, void (*dtor) (void *))
533{
534  return __gthrw_(pthread_key_create) (key, dtor);
535}
536
537static inline int
538__gthread_key_delete (__gthread_key_t key)
539{
540  return __gthrw_(pthread_key_delete) (key);
541}
542
543static inline void *
544__gthread_getspecific (__gthread_key_t key)
545{
546  return __gthrw_(pthread_getspecific) (key);
547}
548
549static inline int
550__gthread_setspecific (__gthread_key_t key, const void *ptr)
551{
552  return __gthrw_(pthread_setspecific) (key, ptr);
553}
554
555static inline int
556__gthread_mutex_lock (__gthread_mutex_t *mutex)
557{
558  if (__gthread_active_p ())
559    return __gthrw_(pthread_mutex_lock) (mutex);
560  else
561    return 0;
562}
563
564static inline int
565__gthread_mutex_trylock (__gthread_mutex_t *mutex)
566{
567  if (__gthread_active_p ())
568    return __gthrw_(pthread_mutex_trylock) (mutex);
569  else
570    return 0;
571}
572
573static inline int
574__gthread_mutex_unlock (__gthread_mutex_t *mutex)
575{
576  if (__gthread_active_p ())
577    return __gthrw_(pthread_mutex_unlock) (mutex);
578  else
579    return 0;
580}
581
582#ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
583static inline int
584__gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *mutex)
585{
586  if (__gthread_active_p ())
587    {
588      pthread_mutexattr_t attr;
589      int r;
590
591      r = __gthrw_(pthread_mutexattr_init) (&attr);
592      if (!r)
593	r = __gthrw_(pthread_mutexattr_settype) (&attr, PTHREAD_MUTEX_RECURSIVE);
594      if (!r)
595	r = __gthrw_(pthread_mutex_init) (mutex, &attr);
596      if (!r)
597	r = __gthrw_(pthread_mutexattr_destroy) (&attr);
598      return r;
599    }
600  return 0;
601}
602#endif
603
604static inline int
605__gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex)
606{
607  return __gthread_mutex_lock (mutex);
608}
609
610static inline int
611__gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex)
612{
613  return __gthread_mutex_trylock (mutex);
614}
615
616static inline int
617__gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex)
618{
619  return __gthread_mutex_unlock (mutex);
620}
621
622#endif /* _LIBOBJC */
623
624#endif /* ! GCC_GTHR_POSIX_H */
625