190075Sobrien/* Threads compatibility routines for libgcc2 and libobjc.  */
250397Sobrien/* Compile this one with gcc.  */
3169689Skan/* Copyright (C) 1997, 1999, 2000, 2004, 2005, 2006
4169689Skan   Free Software Foundation, Inc.
550397Sobrien
690075SobrienThis file is part of GCC.
750397Sobrien
890075SobrienGCC is free software; you can redistribute it and/or modify it under
990075Sobrienthe terms of the GNU General Public License as published by the Free
1090075SobrienSoftware Foundation; either version 2, or (at your option) any later
1190075Sobrienversion.
1250397Sobrien
1390075SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY
1490075SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or
1590075SobrienFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1690075Sobrienfor more details.
1750397Sobrien
1850397SobrienYou should have received a copy of the GNU General Public License
1990075Sobrienalong with GCC; see the file COPYING.  If not, write to the Free
20169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
21169689Skan02110-1301, USA.  */
2250397Sobrien
2350397Sobrien/* As a special exception, if you link this library with other files,
2450397Sobrien   some of which are compiled with GCC, to produce an executable,
2550397Sobrien   this library does not by itself cause the resulting executable
2650397Sobrien   to be covered by the GNU General Public License.
2750397Sobrien   This exception does not however invalidate any other reasons why
2850397Sobrien   the executable file might be covered by the GNU General Public License.  */
2950397Sobrien
3090075Sobrien#ifndef GCC_GTHR_SOLARIS_H
3190075Sobrien#define GCC_GTHR_SOLARIS_H
3250397Sobrien
3350397Sobrien/* Solaris threads as found in Solaris 2.[456].
3450397Sobrien   Actually these are Unix International (UI) threads, but I don't
3590075Sobrien   know if anyone else implements these.  */
3650397Sobrien
3750397Sobrien#define __GTHREADS 1
3850397Sobrien
3950397Sobrien#include <thread.h>
4050397Sobrien#include <errno.h>
4150397Sobrien
42169689Skan#ifdef __cplusplus
43169689Skan#define UNUSED(x)
44169689Skan#else
45169689Skan#define UNUSED(x) x __attribute__((unused))
46169689Skan#endif
47169689Skan
4850397Sobrientypedef thread_key_t __gthread_key_t;
49117395Skantypedef struct {
5050397Sobrien  mutex_t mutex;
5150397Sobrien  int once;
5250397Sobrien} __gthread_once_t;
5350397Sobrientypedef mutex_t __gthread_mutex_t;
5450397Sobrien
55169689Skantypedef struct {
56169689Skan  long depth;
57169689Skan  thread_t owner;
58169689Skan  mutex_t actual;
59169689Skan} __gthread_recursive_mutex_t;
60169689Skan
6150397Sobrien#define __GTHREAD_ONCE_INIT { DEFAULTMUTEX, 0 }
6250397Sobrien#define __GTHREAD_MUTEX_INIT DEFAULTMUTEX
63169689Skan#define __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION __gthread_recursive_mutex_init_function
6450397Sobrien
6550397Sobrien#if SUPPORTS_WEAK && GTHREAD_USE_WEAK
66169689Skan# define __gthrw(name) \
67169689Skan  static __typeof(name) __gthrw_ ## name __attribute__ ((__weakref__(#name)));
68169689Skan# define __gthrw_(name) __gthrw_ ## name
69169689Skan#else
70169689Skan# define __gthrw(name)
71169689Skan# define __gthrw_(name) name
72169689Skan#endif
7350397Sobrien
74169689Skan__gthrw(thr_keycreate)
75169689Skan__gthrw(thr_getspecific)
76169689Skan__gthrw(thr_setspecific)
77169689Skan__gthrw(thr_create)
78169689Skan__gthrw(thr_self)
7950397Sobrien
80169689Skan__gthrw(mutex_init)
81169689Skan__gthrw(mutex_destroy)
82169689Skan__gthrw(mutex_lock)
83169689Skan__gthrw(mutex_trylock)
84169689Skan__gthrw(mutex_unlock)
8550397Sobrien
8690075Sobrien#ifdef _LIBOBJC
87169689Skan__gthrw(thr_exit)
88169689Skan__gthrw(thr_getprio)
89169689Skan__gthrw(thr_setprio)
90169689Skan__gthrw(thr_yield)
9190075Sobrien
92169689Skan__gthrw(cond_init)
93169689Skan__gthrw(cond_destroy)
94169689Skan__gthrw(cond_wait)
95169689Skan__gthrw(cond_broadcast)
96169689Skan__gthrw(cond_signal)
9790075Sobrien
9890075Sobrien#endif
9990075Sobrien
100169689Skan#if SUPPORTS_WEAK && GTHREAD_USE_WEAK
101169689Skan
10250397Sobrien/* This will not actually work in Solaris 2.5, since libc contains
10390075Sobrien   dummy symbols of all thr_* routines.  */
10450397Sobrien
10550397Sobrienstatic inline int
10690075Sobrien__gthread_active_p (void)
10750397Sobrien{
108169689Skan  static void *const __gthread_active_ptr = (void *) &__gthrw_(thr_create);
10950397Sobrien  return __gthread_active_ptr != 0;
11050397Sobrien}
11150397Sobrien
11250397Sobrien#else /* not SUPPORTS_WEAK */
11350397Sobrien
11450397Sobrienstatic inline int
11590075Sobrien__gthread_active_p (void)
11650397Sobrien{
11750397Sobrien  return 1;
11850397Sobrien}
11950397Sobrien
12050397Sobrien#endif /* SUPPORTS_WEAK */
12150397Sobrien
12290075Sobrien#ifdef _LIBOBJC
12390075Sobrien
12490075Sobrien/* Key structure for maintaining thread specific storage */
12590075Sobrienstatic thread_key_t _objc_thread_storage;
12690075Sobrien
12790075Sobrien/* Thread local storage for a single thread */
12890075Sobrienstatic void *thread_local_storage = NULL;
12990075Sobrien
13090075Sobrien/* Backend initialization functions */
13190075Sobrien
13290075Sobrien/* Initialize the threads subsystem.  */
13350397Sobrienstatic inline int
134117395Skan__gthread_objc_init_thread_system (void)
13550397Sobrien{
136169689Skan  /* Initialize the thread storage key.  */
13790075Sobrien  if (__gthread_active_p ()
138169689Skan      && __gthrw_(thr_keycreate) (&_objc_thread_storage, NULL) == 0)
13990075Sobrien    return 0;
14090075Sobrien
14190075Sobrien  return -1;
14290075Sobrien}
14390075Sobrien
14490075Sobrien/* Close the threads subsystem.  */
14590075Sobrienstatic inline int
146117395Skan__gthread_objc_close_thread_system (void)
14790075Sobrien{
14890075Sobrien  if (__gthread_active_p ())
14990075Sobrien    return 0;
15090075Sobrien  else
15190075Sobrien    return -1;
15290075Sobrien}
15390075Sobrien
15490075Sobrien/* Backend thread functions */
15590075Sobrien
15690075Sobrien/* Create a new thread of execution.  */
15790075Sobrienstatic inline objc_thread_t
158117395Skan__gthread_objc_thread_detach (void (*func)(void *), void *arg)
15990075Sobrien{
16090075Sobrien  objc_thread_t thread_id;
16190075Sobrien  thread_t new_thread_id = 0;
16290075Sobrien
16390075Sobrien  if (!__gthread_active_p ())
16490075Sobrien    return NULL;
165117395Skan
166169689Skan  if (__gthrw_(thr_create) (NULL, 0, (void *) func, arg,
167117395Skan		  THR_DETACHED | THR_NEW_LWP,
168117395Skan		  &new_thread_id) == 0)
169117395Skan    thread_id = *(objc_thread_t *) &new_thread_id;
17090075Sobrien  else
17190075Sobrien    thread_id = NULL;
172117395Skan
17390075Sobrien  return thread_id;
17490075Sobrien}
17590075Sobrien
17690075Sobrien/* Set the current thread's priority.  */
17790075Sobrienstatic inline int
178117395Skan__gthread_objc_thread_set_priority (int priority)
17990075Sobrien{
18090075Sobrien  int sys_priority = 0;
18190075Sobrien
18290075Sobrien  if (!__gthread_active_p ())
18390075Sobrien    return -1;
18490075Sobrien
18590075Sobrien  switch (priority)
18690075Sobrien    {
18790075Sobrien    case OBJC_THREAD_INTERACTIVE_PRIORITY:
18890075Sobrien      sys_priority = 300;
18990075Sobrien      break;
19090075Sobrien    default:
19190075Sobrien    case OBJC_THREAD_BACKGROUND_PRIORITY:
19290075Sobrien      sys_priority = 200;
19390075Sobrien      break;
19490075Sobrien    case OBJC_THREAD_LOW_PRIORITY:
19590075Sobrien      sys_priority = 1000;
19690075Sobrien      break;
19790075Sobrien    }
19890075Sobrien
19990075Sobrien  /* Change priority */
200169689Skan  if (__gthrw_(thr_setprio) (__gthrw_(thr_self) (), sys_priority) == 0)
20190075Sobrien    return 0;
20290075Sobrien  else
20390075Sobrien    return -1;
20490075Sobrien}
20590075Sobrien
20690075Sobrien/* Return the current thread's priority.  */
20790075Sobrienstatic inline int
208117395Skan__gthread_objc_thread_get_priority (void)
20990075Sobrien{
21090075Sobrien  int sys_priority;
21190075Sobrien
21290075Sobrien  if (!__gthread_active_p ())
21390075Sobrien    return OBJC_THREAD_INTERACTIVE_PRIORITY;
214117395Skan
215169689Skan  if (__gthrw_(thr_getprio) (__gthrw_(thr_self) (), &sys_priority) == 0)
21690075Sobrien    {
21790075Sobrien      if (sys_priority >= 250)
21890075Sobrien	return OBJC_THREAD_INTERACTIVE_PRIORITY;
21990075Sobrien      else if (sys_priority >= 150)
22090075Sobrien	return OBJC_THREAD_BACKGROUND_PRIORITY;
22190075Sobrien      return OBJC_THREAD_LOW_PRIORITY;
22290075Sobrien    }
22390075Sobrien
22490075Sobrien  /* Couldn't get priority.  */
22590075Sobrien  return -1;
22690075Sobrien}
22790075Sobrien
22890075Sobrien/* Yield our process time to another thread.  */
22990075Sobrienstatic inline void
230117395Skan__gthread_objc_thread_yield (void)
23190075Sobrien{
23290075Sobrien  if (__gthread_active_p ())
233169689Skan    __gthrw_(thr_yield) ();
23490075Sobrien}
23590075Sobrien
23690075Sobrien/* Terminate the current thread.  */
23790075Sobrienstatic inline int
238117395Skan__gthread_objc_thread_exit (void)
23990075Sobrien{
24090075Sobrien  if (__gthread_active_p ())
24190075Sobrien    /* exit the thread */
242169689Skan    __gthrw_(thr_exit) (&__objc_thread_exit_status);
24390075Sobrien
24490075Sobrien  /* Failed if we reached here */
24590075Sobrien  return -1;
24690075Sobrien}
24790075Sobrien
24890075Sobrien/* Returns an integer value which uniquely describes a thread.  */
24990075Sobrienstatic inline objc_thread_t
250117395Skan__gthread_objc_thread_id (void)
25190075Sobrien{
25290075Sobrien  if (__gthread_active_p ())
253169689Skan    return (objc_thread_t) __gthrw_(thr_self) ();
25490075Sobrien  else
255117395Skan    return (objc_thread_t) 1;
25690075Sobrien}
25790075Sobrien
25890075Sobrien/* Sets the thread's local storage pointer.  */
25990075Sobrienstatic inline int
260117395Skan__gthread_objc_thread_set_data (void *value)
26190075Sobrien{
26290075Sobrien  if (__gthread_active_p ())
26390075Sobrien    {
264169689Skan      if (__gthrw_(thr_setspecific) (_objc_thread_storage, value) == 0)
26590075Sobrien	return 0;
26690075Sobrien      else
26790075Sobrien	return -1;
26890075Sobrien    }
26990075Sobrien  else
27090075Sobrien    {
27190075Sobrien      thread_local_storage = value;
27290075Sobrien      return 0;
27390075Sobrien    }
27490075Sobrien}
27590075Sobrien
27690075Sobrien/* Returns the thread's local storage pointer.  */
27790075Sobrienstatic inline void *
278117395Skan__gthread_objc_thread_get_data (void)
27990075Sobrien{
28090075Sobrien  void *value = NULL;
28190075Sobrien
28290075Sobrien  if (__gthread_active_p ())
28390075Sobrien    {
284169689Skan      if (__gthrw_(thr_getspecific) (_objc_thread_storage, &value) == 0)
28590075Sobrien	return value;
28690075Sobrien      else
28790075Sobrien	return NULL;
28890075Sobrien    }
28990075Sobrien  else
29090075Sobrien    return thread_local_storage;
29190075Sobrien}
29290075Sobrien
29390075Sobrien/* Backend mutex functions */
29490075Sobrien
29590075Sobrien/* Allocate a mutex.  */
29690075Sobrienstatic inline int
297117395Skan__gthread_objc_mutex_allocate (objc_mutex_t mutex)
29890075Sobrien{
29990075Sobrien  if (__gthread_active_p ()
300169689Skan      && __gthrw_(mutex_init) ((mutex_t *) (&(mutex->backend)), USYNC_THREAD, 0))
30190075Sobrien    return -1;
30290075Sobrien
30390075Sobrien  return 0;
30490075Sobrien}
30590075Sobrien
30690075Sobrien/* Deallocate a mutex.  */
30790075Sobrienstatic inline int
308117395Skan__gthread_objc_mutex_deallocate (objc_mutex_t mutex)
30990075Sobrien{
31090075Sobrien  if (__gthread_active_p ())
311169689Skan    __gthrw_(mutex_destroy) ((mutex_t *) (&(mutex->backend)));
31290075Sobrien
31390075Sobrien  return 0;
31490075Sobrien}
31590075Sobrien
31690075Sobrien/* Grab a lock on a mutex.  */
31790075Sobrienstatic inline int
318117395Skan__gthread_objc_mutex_lock (objc_mutex_t mutex)
31990075Sobrien{
32090075Sobrien  if (__gthread_active_p ()
321169689Skan      && __gthrw_(mutex_lock) ((mutex_t *) (&(mutex->backend))) != 0)
32290075Sobrien    return -1;
32390075Sobrien
32490075Sobrien  return 0;
32590075Sobrien}
32690075Sobrien
32790075Sobrien/* Try to grab a lock on a mutex.  */
32890075Sobrienstatic inline int
329117395Skan__gthread_objc_mutex_trylock (objc_mutex_t mutex)
33090075Sobrien{
33190075Sobrien  if (__gthread_active_p ()
332169689Skan      && __gthrw_(mutex_trylock) ((mutex_t *) (&(mutex->backend))) != 0)
33390075Sobrien    return -1;
33490075Sobrien
33590075Sobrien  return 0;
33690075Sobrien}
33790075Sobrien
33890075Sobrien/* Unlock the mutex */
33990075Sobrienstatic inline int
340117395Skan__gthread_objc_mutex_unlock (objc_mutex_t mutex)
34190075Sobrien{
34290075Sobrien  if (__gthread_active_p ()
343169689Skan      && __gthrw_(mutex_unlock) ((mutex_t *) (&(mutex->backend))) != 0)
34490075Sobrien    return -1;
34590075Sobrien
34690075Sobrien  return 0;
34790075Sobrien}
34890075Sobrien
34990075Sobrien/* Backend condition mutex functions */
35090075Sobrien
35190075Sobrien/* Allocate a condition.  */
35290075Sobrienstatic inline int
353117395Skan__gthread_objc_condition_allocate (objc_condition_t condition)
35490075Sobrien{
35590075Sobrien  if (__gthread_active_p ())
356169689Skan    return __gthrw_(cond_init) ((cond_t *) (&(condition->backend)), USYNC_THREAD,
357117395Skan		      NULL);
35890075Sobrien  else
35990075Sobrien    return 0;
36090075Sobrien}
36190075Sobrien
36290075Sobrien/* Deallocate a condition.  */
36390075Sobrienstatic inline int
364117395Skan__gthread_objc_condition_deallocate (objc_condition_t condition)
36590075Sobrien{
36690075Sobrien  if (__gthread_active_p ())
367169689Skan    return __gthrw_(cond_destroy) ((cond_t *) (&(condition->backend)));
36890075Sobrien  else
36990075Sobrien    return 0;
37090075Sobrien}
37190075Sobrien
37290075Sobrien/* Wait on the condition */
37390075Sobrienstatic inline int
374117395Skan__gthread_objc_condition_wait (objc_condition_t condition, objc_mutex_t mutex)
37590075Sobrien{
37690075Sobrien  if (__gthread_active_p ())
377169689Skan    return __gthrw_(cond_wait) ((cond_t *) (&(condition->backend)),
378117395Skan		      (mutex_t *) (&(mutex->backend)));
37990075Sobrien  else
38090075Sobrien    return 0;
38190075Sobrien}
38290075Sobrien
38390075Sobrien/* Wake up all threads waiting on this condition.  */
38490075Sobrienstatic inline int
385117395Skan__gthread_objc_condition_broadcast (objc_condition_t condition)
38690075Sobrien{
38790075Sobrien  if (__gthread_active_p ())
388169689Skan    return __gthrw_(cond_broadcast) ((cond_t *) (&(condition->backend)));
38990075Sobrien  else
39090075Sobrien    return 0;
39190075Sobrien}
39290075Sobrien
39390075Sobrien/* Wake up one thread waiting on this condition.  */
39490075Sobrienstatic inline int
395117395Skan__gthread_objc_condition_signal (objc_condition_t condition)
39690075Sobrien{
39790075Sobrien  if (__gthread_active_p ())
398169689Skan    return __gthrw_(cond_signal) ((cond_t *) (&(condition->backend)));
39990075Sobrien  else
40090075Sobrien    return 0;
40190075Sobrien}
40290075Sobrien
40390075Sobrien#else /* _LIBOBJC */
40490075Sobrien
40590075Sobrienstatic inline int
40690075Sobrien__gthread_once (__gthread_once_t *once, void (*func) (void))
40790075Sobrien{
40850397Sobrien  if (! __gthread_active_p ())
40950397Sobrien    return -1;
41050397Sobrien
41150397Sobrien  if (once == 0 || func == 0)
41250397Sobrien    return EINVAL;
41350397Sobrien
41450397Sobrien  if (once->once == 0)
41550397Sobrien    {
416169689Skan      int status = __gthrw_(mutex_lock) (&once->mutex);
41750397Sobrien      if (status != 0)
41850397Sobrien	return status;
41950397Sobrien      if (once->once == 0)
42050397Sobrien	{
42150397Sobrien	  (*func) ();
422117395Skan	  once->once++;
42350397Sobrien	}
424169689Skan      __gthrw_(mutex_unlock) (&once->mutex);
42550397Sobrien    }
42650397Sobrien  return 0;
42750397Sobrien}
42850397Sobrien
42950397Sobrienstatic inline int
43050397Sobrien__gthread_key_create (__gthread_key_t *key, void (*dtor) (void *))
43150397Sobrien{
43250397Sobrien  /* Solaris 2.5 contains thr_* routines no-op in libc, so test if we actually
43390075Sobrien     got a reasonable key value, and if not, fail.  */
434169689Skan  *key = (__gthread_key_t)-1;
435169689Skan  if (__gthrw_(thr_keycreate) (key, dtor) != 0 || *key == (__gthread_key_t)-1)
43650397Sobrien    return -1;
43750397Sobrien  else
43850397Sobrien    return 0;
43950397Sobrien}
44050397Sobrien
44150397Sobrienstatic inline int
442169689Skan__gthread_key_delete (__gthread_key_t UNUSED (key))
44350397Sobrien{
44490075Sobrien  /* Not possible.  */
44550397Sobrien  return -1;
44650397Sobrien}
44750397Sobrien
44850397Sobrienstatic inline void *
44950397Sobrien__gthread_getspecific (__gthread_key_t key)
45050397Sobrien{
45150397Sobrien  void *ptr;
452169689Skan  if (__gthrw_(thr_getspecific) (key, &ptr) == 0)
45350397Sobrien    return ptr;
45450397Sobrien  else
45550397Sobrien    return 0;
45650397Sobrien}
45750397Sobrien
45850397Sobrienstatic inline int
45950397Sobrien__gthread_setspecific (__gthread_key_t key, const void *ptr)
46050397Sobrien{
461169689Skan  return __gthrw_(thr_setspecific) (key, (void *) ptr);
46250397Sobrien}
46350397Sobrien
46450397Sobrienstatic inline int
46550397Sobrien__gthread_mutex_lock (__gthread_mutex_t *mutex)
46650397Sobrien{
46750397Sobrien  if (__gthread_active_p ())
468169689Skan    return __gthrw_(mutex_lock) (mutex);
46950397Sobrien  else
47050397Sobrien    return 0;
47150397Sobrien}
47250397Sobrien
47350397Sobrienstatic inline int
47450397Sobrien__gthread_mutex_trylock (__gthread_mutex_t *mutex)
47550397Sobrien{
47650397Sobrien  if (__gthread_active_p ())
477169689Skan    return __gthrw_(mutex_trylock) (mutex);
47850397Sobrien  else
47950397Sobrien    return 0;
48050397Sobrien}
48150397Sobrien
48250397Sobrienstatic inline int
48350397Sobrien__gthread_mutex_unlock (__gthread_mutex_t *mutex)
48450397Sobrien{
48550397Sobrien  if (__gthread_active_p ())
486169689Skan    return __gthrw_(mutex_unlock) (mutex);
48750397Sobrien  else
48850397Sobrien    return 0;
48950397Sobrien}
49050397Sobrien
491169689Skanstatic inline int
492169689Skan__gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *mutex)
493169689Skan{
494169689Skan  mutex->depth = 0;
495169689Skan  mutex->owner = (thread_t) 0;
496169689Skan  return __gthrw_(mutex_init) (&mutex->actual, USYNC_THREAD, 0);
497169689Skan}
498169689Skan
499169689Skanstatic inline int
500169689Skan__gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex)
501169689Skan{
502169689Skan  if (__gthread_active_p ())
503169689Skan    {
504169689Skan      thread_t me = __gthrw_(thr_self) ();
505169689Skan
506169689Skan      if (mutex->owner != me)
507169689Skan	{
508169689Skan	  __gthrw_(mutex_lock) (&mutex->actual);
509169689Skan	  mutex->owner = me;
510169689Skan	}
511169689Skan
512169689Skan      mutex->depth++;
513169689Skan    }
514169689Skan  return 0;
515169689Skan}
516169689Skan
517169689Skanstatic inline int
518169689Skan__gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex)
519169689Skan{
520169689Skan  if (__gthread_active_p ())
521169689Skan    {
522169689Skan      thread_t me = __gthrw_(thr_self) ();
523169689Skan
524169689Skan      if (mutex->owner != me)
525169689Skan	{
526169689Skan	  if (__gthrw_(mutex_trylock) (&mutex->actual))
527169689Skan	    return 1;
528169689Skan	  mutex->owner = me;
529169689Skan	}
530169689Skan
531169689Skan      mutex->depth++;
532169689Skan    }
533169689Skan  return 0;
534169689Skan}
535169689Skan
536169689Skanstatic inline int
537169689Skan__gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex)
538169689Skan{
539169689Skan  if (__gthread_active_p ())
540169689Skan    {
541169689Skan      if (--mutex->depth == 0)
542169689Skan	{
543169689Skan	   mutex->owner = (thread_t) 0;
544169689Skan	   __gthrw_(mutex_unlock) (&mutex->actual);
545169689Skan	}
546169689Skan    }
547169689Skan  return 0;
548169689Skan}
549169689Skan
55090075Sobrien#endif /* _LIBOBJC */
55190075Sobrien
552169689Skan#undef UNUSED
553169689Skan
55490075Sobrien#endif /* ! GCC_GTHR_SOLARIS_H */
555