gthr-posix.h revision 90075
190075Sobrien/* Threads compatibility routines for libgcc2 and libobjc.  */
250397Sobrien/* Compile this one with gcc.  */
390075Sobrien/* Copyright (C) 1997, 1999, 2000, 2001 Free Software Foundation, Inc.
450397Sobrien
590075SobrienThis file is part of GCC.
650397Sobrien
790075SobrienGCC is free software; you can redistribute it and/or modify it under
890075Sobrienthe terms of the GNU General Public License as published by the Free
990075SobrienSoftware Foundation; either version 2, or (at your option) any later
1090075Sobrienversion.
1150397Sobrien
1290075SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY
1390075SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or
1490075SobrienFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1590075Sobrienfor more details.
1650397Sobrien
1750397SobrienYou should have received a copy of the GNU General Public License
1890075Sobrienalong with GCC; see the file COPYING.  If not, write to the Free
1990075SobrienSoftware Foundation, 59 Temple Place - Suite 330, Boston, MA
2090075Sobrien02111-1307, USA.  */
2150397Sobrien
2250397Sobrien/* As a special exception, if you link this library with other files,
2350397Sobrien   some of which are compiled with GCC, to produce an executable,
2450397Sobrien   this library does not by itself cause the resulting executable
2550397Sobrien   to be covered by the GNU General Public License.
2650397Sobrien   This exception does not however invalidate any other reasons why
2750397Sobrien   the executable file might be covered by the GNU General Public License.  */
2850397Sobrien
2990075Sobrien#ifndef GCC_GTHR_POSIX_H
3090075Sobrien#define GCC_GTHR_POSIX_H
3150397Sobrien
3250397Sobrien/* POSIX threads specific definitions.
3390075Sobrien   Easy, since the interface is just one-to-one mapping.  */
3450397Sobrien
3550397Sobrien#define __GTHREADS 1
3650397Sobrien
3750397Sobrien#include <pthread.h>
3850397Sobrien
3950397Sobrientypedef pthread_key_t __gthread_key_t;
4050397Sobrientypedef pthread_once_t __gthread_once_t;
4150397Sobrientypedef pthread_mutex_t __gthread_mutex_t;
4250397Sobrien
4350397Sobrien#define __GTHREAD_MUTEX_INIT PTHREAD_MUTEX_INITIALIZER
4450397Sobrien#define __GTHREAD_ONCE_INIT PTHREAD_ONCE_INIT
4550397Sobrien
4650397Sobrien#if SUPPORTS_WEAK && GTHREAD_USE_WEAK
4750397Sobrien
4850397Sobrien#pragma weak pthread_once
4950397Sobrien#pragma weak pthread_key_create
5050397Sobrien#pragma weak pthread_key_delete
5150397Sobrien#pragma weak pthread_getspecific
5250397Sobrien#pragma weak pthread_setspecific
5350397Sobrien#pragma weak pthread_create
5450397Sobrien
5550397Sobrien#pragma weak pthread_mutex_lock
5650397Sobrien#pragma weak pthread_mutex_trylock
5750397Sobrien#pragma weak pthread_mutex_unlock
5850397Sobrien
5990075Sobrien#ifdef _LIBOBJC
6090075Sobrien/* Objective C.  */
6190075Sobrien#pragma weak pthread_cond_broadcast
6290075Sobrien#pragma weak pthread_cond_destroy
6390075Sobrien#pragma weak pthread_cond_init
6490075Sobrien#pragma weak pthread_cond_signal
6590075Sobrien#pragma weak pthread_cond_wait
6690075Sobrien#pragma weak pthread_exit
6790075Sobrien#pragma weak pthread_mutex_init
6890075Sobrien#pragma weak pthread_mutex_destroy
6990075Sobrien#pragma weak pthread_self
7090075Sobrien#pragma weak sched_get_priority_max
7190075Sobrien#pragma weak sched_get_priority_min
7290075Sobrien#pragma weak sched_yield
7390075Sobrien#pragma weak pthread_attr_destroy
7490075Sobrien#pragma weak pthread_attr_init
7590075Sobrien#pragma weak pthread_attr_setdetachstate
7690075Sobrien#pragma weak pthread_getschedparam
7790075Sobrien#pragma weak pthread_setschedparam
7890075Sobrien#endif
7950397Sobrien
8090075Sobrienstatic void *__gthread_active_ptr = (void *) &pthread_create;
8190075Sobrien
8250397Sobrienstatic inline int
8390075Sobrien__gthread_active_p (void)
8450397Sobrien{
8550397Sobrien  return __gthread_active_ptr != 0;
8650397Sobrien}
8750397Sobrien
8850397Sobrien#else /* not SUPPORTS_WEAK */
8950397Sobrien
9050397Sobrienstatic inline int
9190075Sobrien__gthread_active_p (void)
9250397Sobrien{
9350397Sobrien  return 1;
9450397Sobrien}
9550397Sobrien
9650397Sobrien#endif /* SUPPORTS_WEAK */
9750397Sobrien
9890075Sobrien#ifdef _LIBOBJC
9990075Sobrien
10090075Sobrien/* This is the config.h file in libobjc/ */
10190075Sobrien#include <config.h>
10290075Sobrien
10390075Sobrien#ifdef HAVE_SCHED_H
10490075Sobrien# include <sched.h>
10590075Sobrien#endif
10690075Sobrien
10790075Sobrien/* Key structure for maintaining thread specific storage */
10890075Sobrienstatic pthread_key_t _objc_thread_storage;
10990075Sobrienstatic pthread_attr_t _objc_thread_attribs;
11090075Sobrien
11190075Sobrien/* Thread local storage for a single thread */
11290075Sobrienstatic void *thread_local_storage = NULL;
11390075Sobrien
11490075Sobrien/* Backend initialization functions */
11590075Sobrien
11690075Sobrien/* Initialize the threads subsystem.  */
11750397Sobrienstatic inline int
11890075Sobrien__gthread_objc_init_thread_system(void)
11950397Sobrien{
12050397Sobrien  if (__gthread_active_p ())
12190075Sobrien    {
12290075Sobrien      /* Initialize the thread storage key */
12390075Sobrien      if (pthread_key_create(&_objc_thread_storage, NULL) == 0)
12490075Sobrien        {
12590075Sobrien          /* The normal default detach state for threads is
12690075Sobrien           * PTHREAD_CREATE_JOINABLE which causes threads to not die
12790075Sobrien           * when you think they should.  */
12890075Sobrien          if (pthread_attr_init(&_objc_thread_attribs) == 0
12990075Sobrien              && pthread_attr_setdetachstate(&_objc_thread_attribs,
13090075Sobrien                                             PTHREAD_CREATE_DETACHED) == 0)
13190075Sobrien            return 0;
13290075Sobrien        }
13390075Sobrien    }
13490075Sobrien
13590075Sobrien  return -1;
13690075Sobrien}
13790075Sobrien
13890075Sobrien/* Close the threads subsystem.  */
13990075Sobrienstatic inline int
14090075Sobrien__gthread_objc_close_thread_system(void)
14190075Sobrien{
14290075Sobrien  if (__gthread_active_p ()
14390075Sobrien      && pthread_key_delete(_objc_thread_storage) == 0
14490075Sobrien      && pthread_attr_destroy(&_objc_thread_attribs) == 0)
14590075Sobrien    return 0;
14690075Sobrien
14790075Sobrien  return -1;
14890075Sobrien}
14990075Sobrien
15090075Sobrien/* Backend thread functions */
15190075Sobrien
15290075Sobrien/* Create a new thread of execution.  */
15390075Sobrienstatic inline objc_thread_t
15490075Sobrien__gthread_objc_thread_detach(void (*func)(void *), void *arg)
15590075Sobrien{
15690075Sobrien  objc_thread_t thread_id;
15790075Sobrien  pthread_t new_thread_handle;
15890075Sobrien
15990075Sobrien  if (!__gthread_active_p ())
16090075Sobrien    return NULL;
16190075Sobrien
16290075Sobrien  if ( !(pthread_create(&new_thread_handle, NULL, (void *)func, arg)) )
16390075Sobrien    thread_id = (objc_thread_t) new_thread_handle;
16490075Sobrien  else
16590075Sobrien    thread_id = NULL;
16690075Sobrien
16790075Sobrien  return thread_id;
16890075Sobrien}
16990075Sobrien
17090075Sobrien/* Set the current thread's priority.  */
17190075Sobrienstatic inline int
17290075Sobrien__gthread_objc_thread_set_priority(int priority)
17390075Sobrien{
17490075Sobrien  if (!__gthread_active_p())
17590075Sobrien    return -1;
17690075Sobrien  else {
17790075Sobrien    pthread_t thread_id = pthread_self();
17890075Sobrien    int policy;
17990075Sobrien    struct sched_param params;
18090075Sobrien    int priority_min, priority_max;
18190075Sobrien
18290075Sobrien    if (pthread_getschedparam(thread_id, &policy, &params) == 0)
18390075Sobrien      {
18490075Sobrien        if ((priority_max = sched_get_priority_max(policy)) != 0)
18590075Sobrien          return -1;
18690075Sobrien
18790075Sobrien        if ((priority_min = sched_get_priority_min(policy)) != 0)
18890075Sobrien          return -1;
18990075Sobrien
19090075Sobrien        if (priority > priority_max)
19190075Sobrien          priority = priority_max;
19290075Sobrien        else if (priority < priority_min)
19390075Sobrien          priority = priority_min;
19490075Sobrien        params.sched_priority = priority;
19590075Sobrien
19690075Sobrien        /*
19790075Sobrien         * The solaris 7 and several other man pages incorrectly state that
19890075Sobrien         * this should be a pointer to policy but pthread.h is universally
19990075Sobrien         * at odds with this.
20090075Sobrien         */
20190075Sobrien        if (pthread_setschedparam(thread_id, policy, &params) == 0)
20290075Sobrien          return 0;
20390075Sobrien      }
20490075Sobrien    return -1;
20590075Sobrien  }
20690075Sobrien}
20790075Sobrien
20890075Sobrien/* Return the current thread's priority.  */
20990075Sobrienstatic inline int
21090075Sobrien__gthread_objc_thread_get_priority(void)
21190075Sobrien{
21290075Sobrien  if (__gthread_active_p ())
21390075Sobrien    {
21490075Sobrien      int policy;
21590075Sobrien      struct sched_param params;
21690075Sobrien
21790075Sobrien      if (pthread_getschedparam(pthread_self(), &policy, &params) == 0)
21890075Sobrien        return params.sched_priority;
21990075Sobrien      else
22090075Sobrien        return -1;
22190075Sobrien    }
22290075Sobrien  else
22390075Sobrien    return OBJC_THREAD_INTERACTIVE_PRIORITY;
22490075Sobrien}
22590075Sobrien
22690075Sobrien/* Yield our process time to another thread.  */
22790075Sobrienstatic inline void
22890075Sobrien__gthread_objc_thread_yield(void)
22990075Sobrien{
23090075Sobrien  if (__gthread_active_p ())
23190075Sobrien    sched_yield();
23290075Sobrien}
23390075Sobrien
23490075Sobrien/* Terminate the current thread.  */
23590075Sobrienstatic inline int
23690075Sobrien__gthread_objc_thread_exit(void)
23790075Sobrien{
23890075Sobrien  if (__gthread_active_p ())
23990075Sobrien    /* exit the thread */
24090075Sobrien    pthread_exit(&__objc_thread_exit_status);
24190075Sobrien
24290075Sobrien  /* Failed if we reached here */
24390075Sobrien  return -1;
24490075Sobrien}
24590075Sobrien
24690075Sobrien/* Returns an integer value which uniquely describes a thread.  */
24790075Sobrienstatic inline objc_thread_t
24890075Sobrien__gthread_objc_thread_id(void)
24990075Sobrien{
25090075Sobrien  if (__gthread_active_p ())
25190075Sobrien    return (objc_thread_t) pthread_self();
25290075Sobrien  else
25390075Sobrien    return (objc_thread_t) 1;
25490075Sobrien}
25590075Sobrien
25690075Sobrien/* Sets the thread's local storage pointer.  */
25790075Sobrienstatic inline int
25890075Sobrien__gthread_objc_thread_set_data(void *value)
25990075Sobrien{
26090075Sobrien  if (__gthread_active_p ())
26190075Sobrien    return pthread_setspecific(_objc_thread_storage, value);
26290075Sobrien  else
26390075Sobrien    {
26490075Sobrien      thread_local_storage = value;
26590075Sobrien      return 0;
26690075Sobrien    }
26790075Sobrien}
26890075Sobrien
26990075Sobrien/* Returns the thread's local storage pointer.  */
27090075Sobrienstatic inline void *
27190075Sobrien__gthread_objc_thread_get_data(void)
27290075Sobrien{
27390075Sobrien  if (__gthread_active_p ())
27490075Sobrien    return pthread_getspecific(_objc_thread_storage);
27590075Sobrien  else
27690075Sobrien    return thread_local_storage;
27790075Sobrien}
27890075Sobrien
27990075Sobrien/* Backend mutex functions */
28090075Sobrien
28190075Sobrien/* Allocate a mutex.  */
28290075Sobrienstatic inline int
28390075Sobrien__gthread_objc_mutex_allocate(objc_mutex_t mutex)
28490075Sobrien{
28590075Sobrien  if (__gthread_active_p ())
28690075Sobrien    {
28790075Sobrien      mutex->backend = objc_malloc(sizeof(pthread_mutex_t));
28890075Sobrien
28990075Sobrien      if (pthread_mutex_init((pthread_mutex_t *)mutex->backend, NULL))
29090075Sobrien	{
29190075Sobrien	  objc_free(mutex->backend);
29290075Sobrien	  mutex->backend = NULL;
29390075Sobrien	  return -1;
29490075Sobrien	}
29590075Sobrien    }
29690075Sobrien
29790075Sobrien  return 0;
29890075Sobrien}
29990075Sobrien
30090075Sobrien/* Deallocate a mutex.  */
30190075Sobrienstatic inline int
30290075Sobrien__gthread_objc_mutex_deallocate(objc_mutex_t mutex)
30390075Sobrien{
30490075Sobrien  if (__gthread_active_p ())
30590075Sobrien    {
30690075Sobrien      int count;
30790075Sobrien
30890075Sobrien      /*
30990075Sobrien       * Posix Threads specifically require that the thread be unlocked
31090075Sobrien       * for pthread_mutex_destroy to work.
31190075Sobrien       */
31290075Sobrien
31390075Sobrien      do
31490075Sobrien	{
31590075Sobrien	  count = pthread_mutex_unlock((pthread_mutex_t *)mutex->backend);
31690075Sobrien	  if (count < 0)
31790075Sobrien	    return -1;
31890075Sobrien	}
31990075Sobrien      while (count);
32090075Sobrien
32190075Sobrien      if (pthread_mutex_destroy((pthread_mutex_t *)mutex->backend))
32290075Sobrien	return -1;
32390075Sobrien
32490075Sobrien      objc_free(mutex->backend);
32590075Sobrien      mutex->backend = NULL;
32690075Sobrien    }
32790075Sobrien  return 0;
32890075Sobrien}
32990075Sobrien
33090075Sobrien/* Grab a lock on a mutex.  */
33190075Sobrienstatic inline int
33290075Sobrien__gthread_objc_mutex_lock(objc_mutex_t mutex)
33390075Sobrien{
33490075Sobrien  if (__gthread_active_p ()
33590075Sobrien      && pthread_mutex_lock((pthread_mutex_t *)mutex->backend) != 0)
33690075Sobrien    {
33790075Sobrien      return -1;
33890075Sobrien    }
33990075Sobrien
34090075Sobrien  return 0;
34190075Sobrien}
34290075Sobrien
34390075Sobrien/* Try to grab a lock on a mutex.  */
34490075Sobrienstatic inline int
34590075Sobrien__gthread_objc_mutex_trylock(objc_mutex_t mutex)
34690075Sobrien{
34790075Sobrien  if (__gthread_active_p ()
34890075Sobrien      && pthread_mutex_trylock((pthread_mutex_t *)mutex->backend) != 0)
34990075Sobrien    {
35090075Sobrien      return -1;
35190075Sobrien    }
35290075Sobrien
35390075Sobrien  return 0;
35490075Sobrien}
35590075Sobrien
35690075Sobrien/* Unlock the mutex */
35790075Sobrienstatic inline int
35890075Sobrien__gthread_objc_mutex_unlock(objc_mutex_t mutex)
35990075Sobrien{
36090075Sobrien  if (__gthread_active_p ()
36190075Sobrien      && pthread_mutex_unlock((pthread_mutex_t *)mutex->backend) != 0)
36290075Sobrien    {
36390075Sobrien      return -1;
36490075Sobrien    }
36590075Sobrien
36690075Sobrien  return 0;
36790075Sobrien}
36890075Sobrien
36990075Sobrien/* Backend condition mutex functions */
37090075Sobrien
37190075Sobrien/* Allocate a condition.  */
37290075Sobrienstatic inline int
37390075Sobrien__gthread_objc_condition_allocate(objc_condition_t condition)
37490075Sobrien{
37590075Sobrien  if (__gthread_active_p ())
37690075Sobrien    {
37790075Sobrien      condition->backend = objc_malloc(sizeof(pthread_cond_t));
37890075Sobrien
37990075Sobrien      if (pthread_cond_init((pthread_cond_t *)condition->backend, NULL))
38090075Sobrien	{
38190075Sobrien	  objc_free(condition->backend);
38290075Sobrien	  condition->backend = NULL;
38390075Sobrien	  return -1;
38490075Sobrien	}
38590075Sobrien    }
38690075Sobrien
38790075Sobrien  return 0;
38890075Sobrien}
38990075Sobrien
39090075Sobrien/* Deallocate a condition.  */
39190075Sobrienstatic inline int
39290075Sobrien__gthread_objc_condition_deallocate(objc_condition_t condition)
39390075Sobrien{
39490075Sobrien  if (__gthread_active_p ())
39590075Sobrien    {
39690075Sobrien      if (pthread_cond_destroy((pthread_cond_t *)condition->backend))
39790075Sobrien	return -1;
39890075Sobrien
39990075Sobrien      objc_free(condition->backend);
40090075Sobrien      condition->backend = NULL;
40190075Sobrien    }
40290075Sobrien  return 0;
40390075Sobrien}
40490075Sobrien
40590075Sobrien/* Wait on the condition */
40690075Sobrienstatic inline int
40790075Sobrien__gthread_objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex)
40890075Sobrien{
40990075Sobrien  if (__gthread_active_p ())
41090075Sobrien    return pthread_cond_wait((pthread_cond_t *)condition->backend,
41190075Sobrien			   (pthread_mutex_t *)mutex->backend);
41290075Sobrien  else
41390075Sobrien    return 0;
41490075Sobrien}
41590075Sobrien
41690075Sobrien/* Wake up all threads waiting on this condition.  */
41790075Sobrienstatic inline int
41890075Sobrien__gthread_objc_condition_broadcast(objc_condition_t condition)
41990075Sobrien{
42090075Sobrien  if (__gthread_active_p ())
42190075Sobrien    return pthread_cond_broadcast((pthread_cond_t *)condition->backend);
42290075Sobrien  else
42390075Sobrien    return 0;
42490075Sobrien}
42590075Sobrien
42690075Sobrien/* Wake up one thread waiting on this condition.  */
42790075Sobrienstatic inline int
42890075Sobrien__gthread_objc_condition_signal(objc_condition_t condition)
42990075Sobrien{
43090075Sobrien  if (__gthread_active_p ())
43190075Sobrien    return pthread_cond_signal((pthread_cond_t *)condition->backend);
43290075Sobrien  else
43390075Sobrien    return 0;
43490075Sobrien}
43590075Sobrien
43690075Sobrien#else /* _LIBOBJC */
43790075Sobrien
43890075Sobrienstatic inline int
43990075Sobrien__gthread_once (__gthread_once_t *once, void (*func) (void))
44090075Sobrien{
44190075Sobrien  if (__gthread_active_p ())
44250397Sobrien    return pthread_once (once, func);
44350397Sobrien  else
44450397Sobrien    return -1;
44550397Sobrien}
44650397Sobrien
44750397Sobrienstatic inline int
44850397Sobrien__gthread_key_create (__gthread_key_t *key, void (*dtor) (void *))
44950397Sobrien{
45050397Sobrien  return pthread_key_create (key, dtor);
45150397Sobrien}
45250397Sobrien
45350397Sobrienstatic inline int
45450397Sobrien__gthread_key_dtor (__gthread_key_t key, void *ptr)
45550397Sobrien{
45690075Sobrien  /* Just reset the key value to zero.  */
45750397Sobrien  if (ptr)
45850397Sobrien    return pthread_setspecific (key, 0);
45950397Sobrien  else
46050397Sobrien    return 0;
46150397Sobrien}
46250397Sobrien
46350397Sobrienstatic inline int
46450397Sobrien__gthread_key_delete (__gthread_key_t key)
46550397Sobrien{
46650397Sobrien  return pthread_key_delete (key);
46750397Sobrien}
46850397Sobrien
46950397Sobrienstatic inline void *
47050397Sobrien__gthread_getspecific (__gthread_key_t key)
47150397Sobrien{
47250397Sobrien  return pthread_getspecific (key);
47350397Sobrien}
47450397Sobrien
47550397Sobrienstatic inline int
47650397Sobrien__gthread_setspecific (__gthread_key_t key, const void *ptr)
47750397Sobrien{
47850397Sobrien  return pthread_setspecific (key, ptr);
47950397Sobrien}
48050397Sobrien
48150397Sobrienstatic inline int
48250397Sobrien__gthread_mutex_lock (__gthread_mutex_t *mutex)
48350397Sobrien{
48450397Sobrien  if (__gthread_active_p ())
48550397Sobrien    return pthread_mutex_lock (mutex);
48650397Sobrien  else
48750397Sobrien    return 0;
48850397Sobrien}
48950397Sobrien
49050397Sobrienstatic inline int
49150397Sobrien__gthread_mutex_trylock (__gthread_mutex_t *mutex)
49250397Sobrien{
49350397Sobrien  if (__gthread_active_p ())
49450397Sobrien    return pthread_mutex_trylock (mutex);
49550397Sobrien  else
49650397Sobrien    return 0;
49750397Sobrien}
49850397Sobrien
49950397Sobrienstatic inline int
50050397Sobrien__gthread_mutex_unlock (__gthread_mutex_t *mutex)
50150397Sobrien{
50250397Sobrien  if (__gthread_active_p ())
50350397Sobrien    return pthread_mutex_unlock (mutex);
50450397Sobrien  else
50550397Sobrien    return 0;
50650397Sobrien}
50750397Sobrien
50890075Sobrien#endif /* _LIBOBJC */
50990075Sobrien
51090075Sobrien#endif /* ! GCC_GTHR_POSIX_H */
511