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, ¶ms) == 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, ¶ms) == 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, ¶ms) == 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