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