1/* Threads compatibility routines for libgcc2 and libobjc.  */
2/* Compile this one with gcc.  */
3/* Copyright (C) 2004, 2005 Free Software Foundation, Inc.
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 2, or (at your option) any later
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING.  If not, write to the Free
19Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
2002110-1301, USA.  */
21
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.  */
28
29#ifndef GCC_GTHR_POSIX_H
30#define GCC_GTHR_POSIX_H
31
32/* POSIX threads specific definitions.
33   Easy, since the interface is just one-to-one mapping.  */
34
35#define __GTHREADS 1
36
37/* Some implementations of <pthread.h> require this to be defined.  */
38#ifndef _REENTRANT
39#define _REENTRANT 1
40#endif
41
42#include <pthread.h>
43#include <unistd.h>
44
45typedef pthread_key_t __gthread_key_t;
46typedef pthread_once_t __gthread_once_t;
47typedef pthread_mutex_t __gthread_mutex_t;
48
49typedef struct {
50  long depth;
51  pthread_t owner;
52  pthread_mutex_t actual;
53} __gthread_recursive_mutex_t;
54
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
58
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
67
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)
76
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)
82
83__gthrw(pthread_mutex_init)
84
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#if defined(_POSIX_PRIORITY_SCHEDULING) && (_POSIX_PRIORITY_SCHEDULING > 0)
95#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && (_POSIX_THREAD_PRIORITY_SCHEDULING > 0)
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#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && (_POSIX_THREAD_PRIORITY_SCHEDULING > 0)
105__gthrw(pthread_getschedparam)
106__gthrw(pthread_setschedparam)
107#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
108#endif /* _LIBOBJC || _LIBOBJC_WEAK */
109
110#if SUPPORTS_WEAK && GTHREAD_USE_WEAK
111
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.  */
119
120#if defined(__sun) && defined(__svr4__)
121
122static volatile int __gthread_active = -1;
123
124static void
125__gthread_trigger (void)
126{
127  __gthread_active = 1;
128}
129
130static inline int
131__gthread_active_p (void)
132{
133  static pthread_mutex_t __gthread_active_mutex = PTHREAD_MUTEX_INITIALIZER;
134  static pthread_once_t __gthread_active_once = PTHREAD_ONCE_INIT;
135
136  /* Avoid reading __gthread_active twice on the main code path.  */
137  int __gthread_active_latest_value = __gthread_active;
138
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))
143    {
144      if (__gthrw_(pthread_once))
145	{
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);
151	}
152
153      /* Make sure we'll never enter this block again.  */
154      if (__gthread_active < 0)
155	__gthread_active = 0;
156
157      __gthread_active_latest_value = __gthread_active;
158    }
159
160  return __gthread_active_latest_value != 0;
161}
162
163#else /* not Solaris */
164
165static inline int
166__gthread_active_p (void)
167{
168  static void *const __gthread_active_ptr
169    = __extension__ (void *) &__gthrw_(pthread_cancel);
170  return __gthread_active_ptr != 0;
171}
172
173#endif /* Solaris */
174
175#else /* not SUPPORTS_WEAK */
176
177static inline int
178__gthread_active_p (void)
179{
180  return 1;
181}
182
183#endif /* SUPPORTS_WEAK */
184
185#ifdef _LIBOBJC
186
187/* This is the config.h file in libobjc/ */
188#include <config.h>
189
190#ifdef HAVE_SCHED_H
191# include <sched.h>
192#endif
193
194/* Key structure for maintaining thread specific storage */
195static pthread_key_t _objc_thread_storage;
196static pthread_attr_t _objc_thread_attribs;
197
198/* Thread local storage for a single thread */
199static void *thread_local_storage = NULL;
200
201/* Backend initialization functions */
202
203/* Initialize the threads subsystem.  */
204static inline int
205__gthread_objc_init_thread_system (void)
206{
207  if (__gthread_active_p ())
208    {
209      /* Initialize the thread storage key.  */
210      if (__gthrw_(pthread_key_create) (&_objc_thread_storage, NULL) == 0)
211	{
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;
219	}
220    }
221
222  return -1;
223}
224
225/* Close the threads subsystem.  */
226static inline int
227__gthread_objc_close_thread_system (void)
228{
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;
233
234  return -1;
235}
236
237/* Backend thread functions */
238
239/* Create a new thread of execution.  */
240static inline objc_thread_t
241__gthread_objc_thread_detach (void (*func)(void *), void *arg)
242{
243  objc_thread_t thread_id;
244  pthread_t new_thread_handle;
245
246  if (!__gthread_active_p ())
247    return NULL;
248
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;
253
254  return thread_id;
255}
256
257/* Set the current thread's priority.  */
258static inline int
259__gthread_objc_thread_set_priority (int priority)
260{
261  if (!__gthread_active_p ())
262    return -1;
263  else
264    {
265#if defined(_POSIX_PRIORITY_SCHEDULING) && (_POSIX_PRIORITY_SCHEDULING > 0)
266#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && (_POSIX_THREAD_PRIORITY_SCHEDULING > 0)
267      pthread_t thread_id = __gthrw_(pthread_self) ();
268      int policy;
269      struct sched_param params;
270      int priority_min, priority_max;
271
272      if (__gthrw_(pthread_getschedparam) (thread_id, &policy, &params) == 0)
273	{
274	  if ((priority_max = __gthrw_(sched_get_priority_max) (policy)) == -1)
275	    return -1;
276
277	  if ((priority_min = __gthrw_(sched_get_priority_min) (policy)) == -1)
278	    return -1;
279
280	  if (priority > priority_max)
281	    priority = priority_max;
282	  else if (priority < priority_min)
283	    priority = priority_min;
284	  params.sched_priority = priority;
285
286	  /*
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.
290	   */
291	  if (__gthrw_(pthread_setschedparam) (thread_id, policy, &params) == 0)
292	    return 0;
293	}
294#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
295#endif /* _POSIX_PRIORITY_SCHEDULING */
296      return -1;
297    }
298}
299
300/* Return the current thread's priority.  */
301static inline int
302__gthread_objc_thread_get_priority (void)
303{
304#if defined(_POSIX_PRIORITY_SCHEDULING) && (_POSIX_PRIORITY_SCHEDULING > 0)
305#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && (_POSIX_THREAD_PRIORITY_SCHEDULING > 0)
306  if (__gthread_active_p ())
307    {
308      int policy;
309      struct sched_param params;
310
311      if (__gthrw_(pthread_getschedparam) (__gthrw_(pthread_self) (), &policy, &params) == 0)
312	return params.sched_priority;
313      else
314	return -1;
315    }
316  else
317#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
318#endif /* _POSIX_PRIORITY_SCHEDULING */
319    return OBJC_THREAD_INTERACTIVE_PRIORITY;
320}
321
322/* Yield our process time to another thread.  */
323static inline void
324__gthread_objc_thread_yield (void)
325{
326  if (__gthread_active_p ())
327    __gthrw_(sched_yield) ();
328}
329
330/* Terminate the current thread.  */
331static inline int
332__gthread_objc_thread_exit (void)
333{
334  if (__gthread_active_p ())
335    /* exit the thread */
336    __gthrw_(pthread_exit) (&__objc_thread_exit_status);
337
338  /* Failed if we reached here */
339  return -1;
340}
341
342/* Returns an integer value which uniquely describes a thread.  */
343static inline objc_thread_t
344__gthread_objc_thread_id (void)
345{
346  if (__gthread_active_p ())
347    return (objc_thread_t) __gthrw_(pthread_self) ();
348  else
349    return (objc_thread_t) 1;
350}
351
352/* Sets the thread's local storage pointer.  */
353static inline int
354__gthread_objc_thread_set_data (void *value)
355{
356  if (__gthread_active_p ())
357    return __gthrw_(pthread_setspecific) (_objc_thread_storage, value);
358  else
359    {
360      thread_local_storage = value;
361      return 0;
362    }
363}
364
365/* Returns the thread's local storage pointer.  */
366static inline void *
367__gthread_objc_thread_get_data (void)
368{
369  if (__gthread_active_p ())
370    return __gthrw_(pthread_getspecific) (_objc_thread_storage);
371  else
372    return thread_local_storage;
373}
374
375/* Backend mutex functions */
376
377/* Allocate a mutex.  */
378static inline int
379__gthread_objc_mutex_allocate (objc_mutex_t mutex)
380{
381  if (__gthread_active_p ())
382    {
383      mutex->backend = objc_malloc (sizeof (pthread_mutex_t));
384
385      if (__gthrw_(pthread_mutex_init) ((pthread_mutex_t *) mutex->backend, NULL))
386	{
387	  objc_free (mutex->backend);
388	  mutex->backend = NULL;
389	  return -1;
390	}
391    }
392
393  return 0;
394}
395
396/* Deallocate a mutex.  */
397static inline int
398__gthread_objc_mutex_deallocate (objc_mutex_t mutex)
399{
400  if (__gthread_active_p ())
401    {
402      int count;
403
404      /*
405       * Posix Threads specifically require that the thread be unlocked
406       * for __gthrw_(pthread_mutex_destroy) to work.
407       */
408
409      do
410	{
411	  count = __gthrw_(pthread_mutex_unlock) ((pthread_mutex_t *) mutex->backend);
412	  if (count < 0)
413	    return -1;
414	}
415      while (count);
416
417      if (__gthrw_(pthread_mutex_destroy) ((pthread_mutex_t *) mutex->backend))
418	return -1;
419
420      objc_free (mutex->backend);
421      mutex->backend = NULL;
422    }
423  return 0;
424}
425
426/* Grab a lock on a mutex.  */
427static inline int
428__gthread_objc_mutex_lock (objc_mutex_t mutex)
429{
430  if (__gthread_active_p ()
431      && __gthrw_(pthread_mutex_lock) ((pthread_mutex_t *) mutex->backend) != 0)
432    {
433      return -1;
434    }
435
436  return 0;
437}
438
439/* Try to grab a lock on a mutex.  */
440static inline int
441__gthread_objc_mutex_trylock (objc_mutex_t mutex)
442{
443  if (__gthread_active_p ()
444      && __gthrw_(pthread_mutex_trylock) ((pthread_mutex_t *) mutex->backend) != 0)
445    {
446      return -1;
447    }
448
449  return 0;
450}
451
452/* Unlock the mutex */
453static inline int
454__gthread_objc_mutex_unlock (objc_mutex_t mutex)
455{
456  if (__gthread_active_p ()
457      && __gthrw_(pthread_mutex_unlock) ((pthread_mutex_t *) mutex->backend) != 0)
458    {
459      return -1;
460    }
461
462  return 0;
463}
464
465/* Backend condition mutex functions */
466
467/* Allocate a condition.  */
468static inline int
469__gthread_objc_condition_allocate (objc_condition_t condition)
470{
471  if (__gthread_active_p ())
472    {
473      condition->backend = objc_malloc (sizeof (pthread_cond_t));
474
475      if (__gthrw_(pthread_cond_init) ((pthread_cond_t *) condition->backend, NULL))
476	{
477	  objc_free (condition->backend);
478	  condition->backend = NULL;
479	  return -1;
480	}
481    }
482
483  return 0;
484}
485
486/* Deallocate a condition.  */
487static inline int
488__gthread_objc_condition_deallocate (objc_condition_t condition)
489{
490  if (__gthread_active_p ())
491    {
492      if (__gthrw_(pthread_cond_destroy) ((pthread_cond_t *) condition->backend))
493	return -1;
494
495      objc_free (condition->backend);
496      condition->backend = NULL;
497    }
498  return 0;
499}
500
501/* Wait on the condition */
502static inline int
503__gthread_objc_condition_wait (objc_condition_t condition, objc_mutex_t mutex)
504{
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;
510}
511
512/* Wake up all threads waiting on this condition.  */
513static inline int
514__gthread_objc_condition_broadcast (objc_condition_t condition)
515{
516  if (__gthread_active_p ())
517    return __gthrw_(pthread_cond_broadcast) ((pthread_cond_t *) condition->backend);
518  else
519    return 0;
520}
521
522/* Wake up one thread waiting on this condition.  */
523static inline int
524__gthread_objc_condition_signal (objc_condition_t condition)
525{
526  if (__gthread_active_p ())
527    return __gthrw_(pthread_cond_signal) ((pthread_cond_t *) condition->backend);
528  else
529    return 0;
530}
531
532#else /* _LIBOBJC */
533
534static inline int
535__gthread_once (__gthread_once_t *once, void (*func) (void))
536{
537  if (__gthread_active_p ())
538    return __gthrw_(pthread_once) (once, func);
539  else
540    return -1;
541}
542
543static inline int
544__gthread_key_create (__gthread_key_t *key, void (*dtor) (void *))
545{
546  return __gthrw_(pthread_key_create) (key, dtor);
547}
548
549static inline int
550__gthread_key_delete (__gthread_key_t key)
551{
552  return __gthrw_(pthread_key_delete) (key);
553}
554
555static inline void *
556__gthread_getspecific (__gthread_key_t key)
557{
558  return __gthrw_(pthread_getspecific) (key);
559}
560
561static inline int
562__gthread_setspecific (__gthread_key_t key, const void *ptr)
563{
564  return __gthrw_(pthread_setspecific) (key, ptr);
565}
566
567static inline int
568__gthread_mutex_lock (__gthread_mutex_t *mutex)
569{
570  if (__gthread_active_p ())
571    return __gthrw_(pthread_mutex_lock) (mutex);
572  else
573    return 0;
574}
575
576static inline int
577__gthread_mutex_trylock (__gthread_mutex_t *mutex)
578{
579  if (__gthread_active_p ())
580    return __gthrw_(pthread_mutex_trylock) (mutex);
581  else
582    return 0;
583}
584
585static inline int
586__gthread_mutex_unlock (__gthread_mutex_t *mutex)
587{
588  if (__gthread_active_p ())
589    return __gthrw_(pthread_mutex_unlock) (mutex);
590  else
591    return 0;
592}
593
594static inline int
595__gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *mutex)
596{
597  mutex->depth = 0;
598  mutex->owner = (pthread_t) 0;
599  return __gthrw_(pthread_mutex_init) (&mutex->actual, NULL);
600}
601
602static inline int
603__gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex)
604{
605  if (__gthread_active_p ())
606    {
607      pthread_t me = __gthrw_(pthread_self) ();
608
609      if (mutex->owner != me)
610	{
611	  __gthrw_(pthread_mutex_lock) (&mutex->actual);
612	  mutex->owner = me;
613	}
614
615      mutex->depth++;
616    }
617  return 0;
618}
619
620static inline int
621__gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex)
622{
623  if (__gthread_active_p ())
624    {
625      pthread_t me = __gthrw_(pthread_self) ();
626
627      if (mutex->owner != me)
628	{
629	  if (__gthrw_(pthread_mutex_trylock) (&mutex->actual))
630	    return 1;
631	  mutex->owner = me;
632	}
633
634      mutex->depth++;
635    }
636  return 0;
637}
638
639static inline int
640__gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex)
641{
642  if (__gthread_active_p ())
643    {
644      if (--mutex->depth == 0)
645	{
646	   mutex->owner = (pthread_t) 0;
647	   __gthrw_(pthread_mutex_unlock) (&mutex->actual);
648	}
649    }
650  return 0;
651}
652
653#endif /* _LIBOBJC */
654
655#endif /* ! GCC_GTHR_POSIX_H */
656