1/* Threads compatibility routines for libgcc2 and libobjc. */ 2/* Compile this one with gcc. */ 3/* Copyright (C) 1997, 1999, 2000, 2004, 2005, 2006 4 Free Software Foundation, Inc. 5 6This file is part of GCC. 7 8GCC is free software; you can redistribute it and/or modify it under 9the terms of the GNU General Public License as published by the Free 10Software Foundation; either version 2, or (at your option) any later 11version. 12 13GCC is distributed in the hope that it will be useful, but WITHOUT ANY 14WARRANTY; without even the implied warranty of MERCHANTABILITY or 15FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16for more details. 17 18You should have received a copy of the GNU General Public License 19along with GCC; see the file COPYING. If not, write to the Free 20Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 2102110-1301, USA. */ 22 23/* As a special exception, if you link this library with other files, 24 some of which are compiled with GCC, to produce an executable, 25 this library does not by itself cause the resulting executable 26 to be covered by the GNU General Public License. 27 This exception does not however invalidate any other reasons why 28 the executable file might be covered by the GNU General Public License. */ 29 30#ifndef GCC_GTHR_SOLARIS_H 31#define GCC_GTHR_SOLARIS_H 32 33/* Solaris threads as found in Solaris 2.[456]. 34 Actually these are Unix International (UI) threads, but I don't 35 know if anyone else implements these. */ 36 37#define __GTHREADS 1 38 39#include <thread.h> 40#include <errno.h> 41 42#ifdef __cplusplus 43#define UNUSED(x) 44#else 45#define UNUSED(x) x __attribute__((unused)) 46#endif 47 48typedef thread_key_t __gthread_key_t; 49typedef struct { 50 mutex_t mutex; 51 int once; 52} __gthread_once_t; 53typedef mutex_t __gthread_mutex_t; 54 55typedef struct { 56 long depth; 57 thread_t owner; 58 mutex_t actual; 59} __gthread_recursive_mutex_t; 60 61#define __GTHREAD_ONCE_INIT { DEFAULTMUTEX, 0 } 62#define __GTHREAD_MUTEX_INIT DEFAULTMUTEX 63#define __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION __gthread_recursive_mutex_init_function 64 65#if SUPPORTS_WEAK && GTHREAD_USE_WEAK 66# define __gthrw(name) \ 67 static __typeof(name) __gthrw_ ## name __attribute__ ((__weakref__(#name))); 68# define __gthrw_(name) __gthrw_ ## name 69#else 70# define __gthrw(name) 71# define __gthrw_(name) name 72#endif 73 74__gthrw(thr_keycreate) 75__gthrw(thr_getspecific) 76__gthrw(thr_setspecific) 77__gthrw(thr_create) 78__gthrw(thr_self) 79 80__gthrw(mutex_init) 81__gthrw(mutex_destroy) 82__gthrw(mutex_lock) 83__gthrw(mutex_trylock) 84__gthrw(mutex_unlock) 85 86#ifdef _LIBOBJC 87__gthrw(thr_exit) 88__gthrw(thr_getprio) 89__gthrw(thr_setprio) 90__gthrw(thr_yield) 91 92__gthrw(cond_init) 93__gthrw(cond_destroy) 94__gthrw(cond_wait) 95__gthrw(cond_broadcast) 96__gthrw(cond_signal) 97 98#endif 99 100#if SUPPORTS_WEAK && GTHREAD_USE_WEAK 101 102/* This will not actually work in Solaris 2.5, since libc contains 103 dummy symbols of all thr_* routines. */ 104 105static inline int 106__gthread_active_p (void) 107{ 108 static void *const __gthread_active_ptr = (void *) &__gthrw_(thr_create); 109 return __gthread_active_ptr != 0; 110} 111 112#else /* not SUPPORTS_WEAK */ 113 114static inline int 115__gthread_active_p (void) 116{ 117 return 1; 118} 119 120#endif /* SUPPORTS_WEAK */ 121 122#ifdef _LIBOBJC 123 124/* Key structure for maintaining thread specific storage */ 125static thread_key_t _objc_thread_storage; 126 127/* Thread local storage for a single thread */ 128static void *thread_local_storage = NULL; 129 130/* Backend initialization functions */ 131 132/* Initialize the threads subsystem. */ 133static inline int 134__gthread_objc_init_thread_system (void) 135{ 136 /* Initialize the thread storage key. */ 137 if (__gthread_active_p () 138 && __gthrw_(thr_keycreate) (&_objc_thread_storage, NULL) == 0) 139 return 0; 140 141 return -1; 142} 143 144/* Close the threads subsystem. */ 145static inline int 146__gthread_objc_close_thread_system (void) 147{ 148 if (__gthread_active_p ()) 149 return 0; 150 else 151 return -1; 152} 153 154/* Backend thread functions */ 155 156/* Create a new thread of execution. */ 157static inline objc_thread_t 158__gthread_objc_thread_detach (void (*func)(void *), void *arg) 159{ 160 objc_thread_t thread_id; 161 thread_t new_thread_id = 0; 162 163 if (!__gthread_active_p ()) 164 return NULL; 165 166 if (__gthrw_(thr_create) (NULL, 0, (void *) func, arg, 167 THR_DETACHED | THR_NEW_LWP, 168 &new_thread_id) == 0) 169 thread_id = *(objc_thread_t *) &new_thread_id; 170 else 171 thread_id = NULL; 172 173 return thread_id; 174} 175 176/* Set the current thread's priority. */ 177static inline int 178__gthread_objc_thread_set_priority (int priority) 179{ 180 int sys_priority = 0; 181 182 if (!__gthread_active_p ()) 183 return -1; 184 185 switch (priority) 186 { 187 case OBJC_THREAD_INTERACTIVE_PRIORITY: 188 sys_priority = 300; 189 break; 190 default: 191 case OBJC_THREAD_BACKGROUND_PRIORITY: 192 sys_priority = 200; 193 break; 194 case OBJC_THREAD_LOW_PRIORITY: 195 sys_priority = 1000; 196 break; 197 } 198 199 /* Change priority */ 200 if (__gthrw_(thr_setprio) (__gthrw_(thr_self) (), sys_priority) == 0) 201 return 0; 202 else 203 return -1; 204} 205 206/* Return the current thread's priority. */ 207static inline int 208__gthread_objc_thread_get_priority (void) 209{ 210 int sys_priority; 211 212 if (!__gthread_active_p ()) 213 return OBJC_THREAD_INTERACTIVE_PRIORITY; 214 215 if (__gthrw_(thr_getprio) (__gthrw_(thr_self) (), &sys_priority) == 0) 216 { 217 if (sys_priority >= 250) 218 return OBJC_THREAD_INTERACTIVE_PRIORITY; 219 else if (sys_priority >= 150) 220 return OBJC_THREAD_BACKGROUND_PRIORITY; 221 return OBJC_THREAD_LOW_PRIORITY; 222 } 223 224 /* Couldn't get priority. */ 225 return -1; 226} 227 228/* Yield our process time to another thread. */ 229static inline void 230__gthread_objc_thread_yield (void) 231{ 232 if (__gthread_active_p ()) 233 __gthrw_(thr_yield) (); 234} 235 236/* Terminate the current thread. */ 237static inline int 238__gthread_objc_thread_exit (void) 239{ 240 if (__gthread_active_p ()) 241 /* exit the thread */ 242 __gthrw_(thr_exit) (&__objc_thread_exit_status); 243 244 /* Failed if we reached here */ 245 return -1; 246} 247 248/* Returns an integer value which uniquely describes a thread. */ 249static inline objc_thread_t 250__gthread_objc_thread_id (void) 251{ 252 if (__gthread_active_p ()) 253 return (objc_thread_t) __gthrw_(thr_self) (); 254 else 255 return (objc_thread_t) 1; 256} 257 258/* Sets the thread's local storage pointer. */ 259static inline int 260__gthread_objc_thread_set_data (void *value) 261{ 262 if (__gthread_active_p ()) 263 { 264 if (__gthrw_(thr_setspecific) (_objc_thread_storage, value) == 0) 265 return 0; 266 else 267 return -1; 268 } 269 else 270 { 271 thread_local_storage = value; 272 return 0; 273 } 274} 275 276/* Returns the thread's local storage pointer. */ 277static inline void * 278__gthread_objc_thread_get_data (void) 279{ 280 void *value = NULL; 281 282 if (__gthread_active_p ()) 283 { 284 if (__gthrw_(thr_getspecific) (_objc_thread_storage, &value) == 0) 285 return value; 286 else 287 return NULL; 288 } 289 else 290 return thread_local_storage; 291} 292 293/* Backend mutex functions */ 294 295/* Allocate a mutex. */ 296static inline int 297__gthread_objc_mutex_allocate (objc_mutex_t mutex) 298{ 299 if (__gthread_active_p () 300 && __gthrw_(mutex_init) ((mutex_t *) (&(mutex->backend)), USYNC_THREAD, 0)) 301 return -1; 302 303 return 0; 304} 305 306/* Deallocate a mutex. */ 307static inline int 308__gthread_objc_mutex_deallocate (objc_mutex_t mutex) 309{ 310 if (__gthread_active_p ()) 311 __gthrw_(mutex_destroy) ((mutex_t *) (&(mutex->backend))); 312 313 return 0; 314} 315 316/* Grab a lock on a mutex. */ 317static inline int 318__gthread_objc_mutex_lock (objc_mutex_t mutex) 319{ 320 if (__gthread_active_p () 321 && __gthrw_(mutex_lock) ((mutex_t *) (&(mutex->backend))) != 0) 322 return -1; 323 324 return 0; 325} 326 327/* Try to grab a lock on a mutex. */ 328static inline int 329__gthread_objc_mutex_trylock (objc_mutex_t mutex) 330{ 331 if (__gthread_active_p () 332 && __gthrw_(mutex_trylock) ((mutex_t *) (&(mutex->backend))) != 0) 333 return -1; 334 335 return 0; 336} 337 338/* Unlock the mutex */ 339static inline int 340__gthread_objc_mutex_unlock (objc_mutex_t mutex) 341{ 342 if (__gthread_active_p () 343 && __gthrw_(mutex_unlock) ((mutex_t *) (&(mutex->backend))) != 0) 344 return -1; 345 346 return 0; 347} 348 349/* Backend condition mutex functions */ 350 351/* Allocate a condition. */ 352static inline int 353__gthread_objc_condition_allocate (objc_condition_t condition) 354{ 355 if (__gthread_active_p ()) 356 return __gthrw_(cond_init) ((cond_t *) (&(condition->backend)), USYNC_THREAD, 357 NULL); 358 else 359 return 0; 360} 361 362/* Deallocate a condition. */ 363static inline int 364__gthread_objc_condition_deallocate (objc_condition_t condition) 365{ 366 if (__gthread_active_p ()) 367 return __gthrw_(cond_destroy) ((cond_t *) (&(condition->backend))); 368 else 369 return 0; 370} 371 372/* Wait on the condition */ 373static inline int 374__gthread_objc_condition_wait (objc_condition_t condition, objc_mutex_t mutex) 375{ 376 if (__gthread_active_p ()) 377 return __gthrw_(cond_wait) ((cond_t *) (&(condition->backend)), 378 (mutex_t *) (&(mutex->backend))); 379 else 380 return 0; 381} 382 383/* Wake up all threads waiting on this condition. */ 384static inline int 385__gthread_objc_condition_broadcast (objc_condition_t condition) 386{ 387 if (__gthread_active_p ()) 388 return __gthrw_(cond_broadcast) ((cond_t *) (&(condition->backend))); 389 else 390 return 0; 391} 392 393/* Wake up one thread waiting on this condition. */ 394static inline int 395__gthread_objc_condition_signal (objc_condition_t condition) 396{ 397 if (__gthread_active_p ()) 398 return __gthrw_(cond_signal) ((cond_t *) (&(condition->backend))); 399 else 400 return 0; 401} 402 403#else /* _LIBOBJC */ 404 405static inline int 406__gthread_once (__gthread_once_t *once, void (*func) (void)) 407{ 408 if (! __gthread_active_p ()) 409 return -1; 410 411 if (once == 0 || func == 0) 412 return EINVAL; 413 414 if (once->once == 0) 415 { 416 int status = __gthrw_(mutex_lock) (&once->mutex); 417 if (status != 0) 418 return status; 419 if (once->once == 0) 420 { 421 (*func) (); 422 once->once++; 423 } 424 __gthrw_(mutex_unlock) (&once->mutex); 425 } 426 return 0; 427} 428 429static inline int 430__gthread_key_create (__gthread_key_t *key, void (*dtor) (void *)) 431{ 432 /* Solaris 2.5 contains thr_* routines no-op in libc, so test if we actually 433 got a reasonable key value, and if not, fail. */ 434 *key = (__gthread_key_t)-1; 435 if (__gthrw_(thr_keycreate) (key, dtor) != 0 || *key == (__gthread_key_t)-1) 436 return -1; 437 else 438 return 0; 439} 440 441static inline int 442__gthread_key_delete (__gthread_key_t UNUSED (key)) 443{ 444 /* Not possible. */ 445 return -1; 446} 447 448static inline void * 449__gthread_getspecific (__gthread_key_t key) 450{ 451 void *ptr; 452 if (__gthrw_(thr_getspecific) (key, &ptr) == 0) 453 return ptr; 454 else 455 return 0; 456} 457 458static inline int 459__gthread_setspecific (__gthread_key_t key, const void *ptr) 460{ 461 return __gthrw_(thr_setspecific) (key, (void *) ptr); 462} 463 464static inline int 465__gthread_mutex_lock (__gthread_mutex_t *mutex) 466{ 467 if (__gthread_active_p ()) 468 return __gthrw_(mutex_lock) (mutex); 469 else 470 return 0; 471} 472 473static inline int 474__gthread_mutex_trylock (__gthread_mutex_t *mutex) 475{ 476 if (__gthread_active_p ()) 477 return __gthrw_(mutex_trylock) (mutex); 478 else 479 return 0; 480} 481 482static inline int 483__gthread_mutex_unlock (__gthread_mutex_t *mutex) 484{ 485 if (__gthread_active_p ()) 486 return __gthrw_(mutex_unlock) (mutex); 487 else 488 return 0; 489} 490 491static inline int 492__gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *mutex) 493{ 494 mutex->depth = 0; 495 mutex->owner = (thread_t) 0; 496 return __gthrw_(mutex_init) (&mutex->actual, USYNC_THREAD, 0); 497} 498 499static inline int 500__gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex) 501{ 502 if (__gthread_active_p ()) 503 { 504 thread_t me = __gthrw_(thr_self) (); 505 506 if (mutex->owner != me) 507 { 508 __gthrw_(mutex_lock) (&mutex->actual); 509 mutex->owner = me; 510 } 511 512 mutex->depth++; 513 } 514 return 0; 515} 516 517static inline int 518__gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex) 519{ 520 if (__gthread_active_p ()) 521 { 522 thread_t me = __gthrw_(thr_self) (); 523 524 if (mutex->owner != me) 525 { 526 if (__gthrw_(mutex_trylock) (&mutex->actual)) 527 return 1; 528 mutex->owner = me; 529 } 530 531 mutex->depth++; 532 } 533 return 0; 534} 535 536static inline int 537__gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex) 538{ 539 if (__gthread_active_p ()) 540 { 541 if (--mutex->depth == 0) 542 { 543 mutex->owner = (thread_t) 0; 544 __gthrw_(mutex_unlock) (&mutex->actual); 545 } 546 } 547 return 0; 548} 549 550#endif /* _LIBOBJC */ 551 552#undef UNUSED 553 554#endif /* ! GCC_GTHR_SOLARIS_H */ 555