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#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 */
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. 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.  */
122
123
124 */
125
126#if defined(__FreeBSD__) || defined(__sun) && defined(__svr4__)
127
128static volatile int __gthread_active = -1;
129
130static void
131__gthread_trigger (void)
132{
133  __gthread_active = 1;
134}
135
136static inline int
137__gthread_active_p (void)
138{
139  static pthread_mutex_t __gthread_active_mutex = PTHREAD_MUTEX_INITIALIZER;
140  static pthread_once_t __gthread_active_once = PTHREAD_ONCE_INIT;
141
142  /* Avoid reading __gthread_active twice on the main code path.  */
143  int __gthread_active_latest_value = __gthread_active;
144
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))
149    {
150      if (__gthrw_(pthread_once))
151	{
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);
157	}
158
159      /* Make sure we'll never enter this block again.  */
160      if (__gthread_active < 0)
161	__gthread_active = 0;
162
163      __gthread_active_latest_value = __gthread_active;
164    }
165
166  return __gthread_active_latest_value != 0;
167}
168
169#else /* neither FreeBSD nor Solaris */
170
171static inline int
172__gthread_active_p (void)
173{
174  static void *const __gthread_active_ptr
175    = __extension__ (void *) &__gthrw_(pthread_cancel);
176  return __gthread_active_ptr != 0;
177}
178
179#endif /* FreeBSD or Solaris */
180
181#else /* not SUPPORTS_WEAK */
182
183static inline int
184__gthread_active_p (void)
185{
186  return 1;
187}
188
189#endif /* SUPPORTS_WEAK */
190
191#ifdef _LIBOBJC
192
193/* This is the config.h file in libobjc/ */
194#include <config.h>
195
196#ifdef HAVE_SCHED_H
197# include <sched.h>
198#endif
199
200/* Key structure for maintaining thread specific storage */
201static pthread_key_t _objc_thread_storage;
202static pthread_attr_t _objc_thread_attribs;
203
204/* Thread local storage for a single thread */
205static void *thread_local_storage = NULL;
206
207/* Backend initialization functions */
208
209/* Initialize the threads subsystem.  */
210static inline int
211__gthread_objc_init_thread_system (void)
212{
213  if (__gthread_active_p ())
214    {
215      /* Initialize the thread storage key.  */
216      if (__gthrw_(pthread_key_create) (&_objc_thread_storage, NULL) == 0)
217	{
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)
224	    return 0;
225	}
226    }
227
228  return -1;
229}
230
231/* Close the threads subsystem.  */
232static inline int
233__gthread_objc_close_thread_system (void)
234{
235  if (__gthread_active_p ()
236      && __gthrw_(pthread_key_delete) (_objc_thread_storage) == 0
237      && __gthrw_(pthread_attr_destroy) (&_objc_thread_attribs) == 0)
238    return 0;
239
240  return -1;
241}
242
243/* Backend thread functions */
244
245/* Create a new thread of execution.  */
246static inline objc_thread_t
247__gthread_objc_thread_detach (void (*func)(void *), void *arg)
248{
249  objc_thread_t thread_id;
250  pthread_t new_thread_handle;
251
252  if (!__gthread_active_p ())
253    return NULL;
254
255  if (!(__gthrw_(pthread_create) (&new_thread_handle, NULL, (void *) func, arg)))
256    thread_id = (objc_thread_t) new_thread_handle;
257  else
258    thread_id = NULL;
259
260  return thread_id;
261}
262
263/* Set the current thread's priority.  */
264static inline int
265__gthread_objc_thread_set_priority (int priority)
266{
267  if (!__gthread_active_p ())
268    return -1;
269  else
270    {
271#ifdef _POSIX_PRIORITY_SCHEDULING
272#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
273      pthread_t thread_id = __gthrw_(pthread_self) ();
274      int policy;
275      struct sched_param params;
276      int priority_min, priority_max;
277
278      if (__gthrw_(pthread_getschedparam) (thread_id, &policy, &params) == 0)
279	{
280	  if ((priority_max = __gthrw_(sched_get_priority_max) (policy)) == -1)
281	    return -1;
282
283	  if ((priority_min = __gthrw_(sched_get_priority_min) (policy)) == -1)
284	    return -1;
285
286	  if (priority > priority_max)
287	    priority = priority_max;
288	  else if (priority < priority_min)
289	    priority = priority_min;
290	  params.sched_priority = priority;
291
292	  /*
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
295	   * at odds with this.
296	   */
297	  if (__gthrw_(pthread_setschedparam) (thread_id, policy, &params) == 0)
298	    return 0;
299	}
300#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
301#endif /* _POSIX_PRIORITY_SCHEDULING */
302      return -1;
303    }
304}
305
306/* Return the current thread's priority.  */
307static inline int
308__gthread_objc_thread_get_priority (void)
309{
310#ifdef _POSIX_PRIORITY_SCHEDULING
311#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
312  if (__gthread_active_p ())
313    {
314      int policy;
315      struct sched_param params;
316
317      if (__gthrw_(pthread_getschedparam) (__gthrw_(pthread_self) (), &policy, &params) == 0)
318	return params.sched_priority;
319      else
320	return -1;
321    }
322  else
323#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
324#endif /* _POSIX_PRIORITY_SCHEDULING */
325    return OBJC_THREAD_INTERACTIVE_PRIORITY;
326}
327
328/* Yield our process time to another thread.  */
329static inline void
330__gthread_objc_thread_yield (void)
331{
332  if (__gthread_active_p ())
333    __gthrw_(sched_yield) ();
334}
335
336/* Terminate the current thread.  */
337static inline int
338__gthread_objc_thread_exit (void)
339{
340  if (__gthread_active_p ())
341    /* exit the thread */
342    __gthrw_(pthread_exit) (&__objc_thread_exit_status);
343
344  /* Failed if we reached here */
345  return -1;
346}
347
348/* Returns an integer value which uniquely describes a thread.  */
349static inline objc_thread_t
350__gthread_objc_thread_id (void)
351{
352  if (__gthread_active_p ())
353    return (objc_thread_t) __gthrw_(pthread_self) ();
354  else
355    return (objc_thread_t) 1;
356}
357
358/* Sets the thread's local storage pointer.  */
359static inline int
360__gthread_objc_thread_set_data (void *value)
361{
362  if (__gthread_active_p ())
363    return __gthrw_(pthread_setspecific) (_objc_thread_storage, value);
364  else
365    {
366      thread_local_storage = value;
367      return 0;
368    }
369}
370
371/* Returns the thread's local storage pointer.  */
372static inline void *
373__gthread_objc_thread_get_data (void)
374{
375  if (__gthread_active_p ())
376    return __gthrw_(pthread_getspecific) (_objc_thread_storage);
377  else
378    return thread_local_storage;
379}
380
381/* Backend mutex functions */
382
383/* Allocate a mutex.  */
384static inline int
385__gthread_objc_mutex_allocate (objc_mutex_t mutex)
386{
387  if (__gthread_active_p ())
388    {
389      mutex->backend = objc_malloc (sizeof (pthread_mutex_t));
390
391      if (__gthrw_(pthread_mutex_init) ((pthread_mutex_t *) mutex->backend, NULL))
392	{
393	  objc_free (mutex->backend);
394	  mutex->backend = NULL;
395	  return -1;
396	}
397    }
398
399  return 0;
400}
401
402/* Deallocate a mutex.  */
403static inline int
404__gthread_objc_mutex_deallocate (objc_mutex_t mutex)
405{
406  if (__gthread_active_p ())
407    {
408      int count;
409
410      /*
411       * Posix Threads specifically require that the thread be unlocked
412       * for __gthrw_(pthread_mutex_destroy) to work.
413       */
414
415      do
416	{
417	  count = __gthrw_(pthread_mutex_unlock) ((pthread_mutex_t *) mutex->backend);
418	  if (count < 0)
419	    return -1;
420	}
421      while (count);
422
423      if (__gthrw_(pthread_mutex_destroy) ((pthread_mutex_t *) mutex->backend))
424	return -1;
425
426      objc_free (mutex->backend);
427      mutex->backend = NULL;
428    }
429  return 0;
430}
431
432/* Grab a lock on a mutex.  */
433static inline int
434__gthread_objc_mutex_lock (objc_mutex_t mutex)
435{
436  if (__gthread_active_p ()
437      && __gthrw_(pthread_mutex_lock) ((pthread_mutex_t *) mutex->backend) != 0)
438    {
439      return -1;
440    }
441
442  return 0;
443}
444
445/* Try to grab a lock on a mutex.  */
446static inline int
447__gthread_objc_mutex_trylock (objc_mutex_t mutex)
448{
449  if (__gthread_active_p ()
450      && __gthrw_(pthread_mutex_trylock) ((pthread_mutex_t *) mutex->backend) != 0)
451    {
452      return -1;
453    }
454
455  return 0;
456}
457
458/* Unlock the mutex */
459static inline int
460__gthread_objc_mutex_unlock (objc_mutex_t mutex)
461{
462  if (__gthread_active_p ()
463      && __gthrw_(pthread_mutex_unlock) ((pthread_mutex_t *) mutex->backend) != 0)
464    {
465      return -1;
466    }
467
468  return 0;
469}
470
471/* Backend condition mutex functions */
472
473/* Allocate a condition.  */
474static inline int
475__gthread_objc_condition_allocate (objc_condition_t condition)
476{
477  if (__gthread_active_p ())
478    {
479      condition->backend = objc_malloc (sizeof (pthread_cond_t));
480
481      if (__gthrw_(pthread_cond_init) ((pthread_cond_t *) condition->backend, NULL))
482	{
483	  objc_free (condition->backend);
484	  condition->backend = NULL;
485	  return -1;
486	}
487    }
488
489  return 0;
490}
491
492/* Deallocate a condition.  */
493static inline int
494__gthread_objc_condition_deallocate (objc_condition_t condition)
495{
496  if (__gthread_active_p ())
497    {
498      if (__gthrw_(pthread_cond_destroy) ((pthread_cond_t *) condition->backend))
499	return -1;
500
501      objc_free (condition->backend);
502      condition->backend = NULL;
503    }
504  return 0;
505}
506
507/* Wait on the condition */
508static inline int
509__gthread_objc_condition_wait (objc_condition_t condition, objc_mutex_t mutex)
510{
511  if (__gthread_active_p ())
512    return __gthrw_(pthread_cond_wait) ((pthread_cond_t *) condition->backend,
513			      (pthread_mutex_t *) mutex->backend);
514  else
515    return 0;
516}
517
518/* Wake up all threads waiting on this condition.  */
519static inline int
520__gthread_objc_condition_broadcast (objc_condition_t condition)
521{
522  if (__gthread_active_p ())
523    return __gthrw_(pthread_cond_broadcast) ((pthread_cond_t *) condition->backend);
524  else
525    return 0;
526}
527
528/* Wake up one thread waiting on this condition.  */
529static inline int
530__gthread_objc_condition_signal (objc_condition_t condition)
531{
532  if (__gthread_active_p ())
533    return __gthrw_(pthread_cond_signal) ((pthread_cond_t *) condition->backend);
534  else
535    return 0;
536}
537
538#else /* _LIBOBJC */
539
540static inline int
541__gthread_once (__gthread_once_t *once, void (*func) (void))
542{
543  if (__gthread_active_p ())
544    return __gthrw_(pthread_once) (once, func);
545  else
546    return -1;
547}
548
549static inline int
550__gthread_key_create (__gthread_key_t *key, void (*dtor) (void *))
551{
552  return __gthrw_(pthread_key_create) (key, dtor);
553}
554
555static inline int
556__gthread_key_delete (__gthread_key_t key)
557{
558  return __gthrw_(pthread_key_delete) (key);
559}
560
561static inline void *
562__gthread_getspecific (__gthread_key_t key)
563{
564  return __gthrw_(pthread_getspecific) (key);
565}
566
567static inline int
568__gthread_setspecific (__gthread_key_t key, const void *ptr)
569{
570  return __gthrw_(pthread_setspecific) (key, ptr);
571}
572
573static inline int
574__gthread_mutex_lock (__gthread_mutex_t *mutex)
575{
576  if (__gthread_active_p ())
577    return __gthrw_(pthread_mutex_lock) (mutex);
578  else
579    return 0;
580}
581
582static inline int
583__gthread_mutex_trylock (__gthread_mutex_t *mutex)
584{
585  if (__gthread_active_p ())
586    return __gthrw_(pthread_mutex_trylock) (mutex);
587  else
588    return 0;
589}
590
591static inline int
592__gthread_mutex_unlock (__gthread_mutex_t *mutex)
593{
594  if (__gthread_active_p ())
595    return __gthrw_(pthread_mutex_unlock) (mutex);
596  else
597    return 0;
598}
599
600static inline int
601__gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *mutex)
602{
603  mutex->depth = 0;
604  mutex->owner = (pthread_t) 0;
605  return __gthrw_(pthread_mutex_init) (&mutex->actual, NULL);
606}
607
608static inline int
609__gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex)
610{
611  if (__gthread_active_p ())
612    {
613      pthread_t me = __gthrw_(pthread_self) ();
614
615      if (mutex->owner != me)
616	{
617	  __gthrw_(pthread_mutex_lock) (&mutex->actual);
618	  mutex->owner = me;
619	}
620
621      mutex->depth++;
622    }
623  return 0;
624}
625
626static inline int
627__gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex)
628{
629  if (__gthread_active_p ())
630    {
631      pthread_t me = __gthrw_(pthread_self) ();
632
633      if (mutex->owner != me)
634	{
635	  if (__gthrw_(pthread_mutex_trylock) (&mutex->actual))
636	    return 1;
637	  mutex->owner = me;
638	}
639
640      mutex->depth++;
641    }
642  return 0;
643}
644
645static inline int
646__gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex)
647{
648  if (__gthread_active_p ())
649    {
650      if (--mutex->depth == 0)
651	{
652	   mutex->owner = (pthread_t) 0;
653	   __gthrw_(pthread_mutex_unlock) (&mutex->actual);
654	}
655    }
656  return 0;
657}
658
659#endif /* _LIBOBJC */
660
661#endif /* ! GCC_GTHR_POSIX_H */
662