gthr-posix.h revision 169689
1/* Threads compatibility routines for libgcc2 and libobjc. */ 2/* Compile this one with gcc. */ 3/* Copyright (C) 1997, 1999, 2000, 2001, 2002, 2003, 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_POSIX_H 31#define GCC_GTHR_POSIX_H 32 33/* POSIX threads specific definitions. 34 Easy, since the interface is just one-to-one mapping. */ 35 36#define __GTHREADS 1 37 38/* Some implementations of <pthread.h> require this to be defined. */ 39#if !defined(_REENTRANT) && defined(__osf__) 40#define _REENTRANT 1 41#endif 42 43#include <pthread.h> 44#include <unistd.h> 45 46typedef pthread_key_t __gthread_key_t; 47typedef pthread_once_t __gthread_once_t; 48typedef pthread_mutex_t __gthread_mutex_t; 49typedef pthread_mutex_t __gthread_recursive_mutex_t; 50 51#define __GTHREAD_MUTEX_INIT PTHREAD_MUTEX_INITIALIZER 52#define __GTHREAD_ONCE_INIT PTHREAD_ONCE_INIT 53#if defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER) 54#define __GTHREAD_RECURSIVE_MUTEX_INIT PTHREAD_RECURSIVE_MUTEX_INITIALIZER 55#elif defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP) 56#define __GTHREAD_RECURSIVE_MUTEX_INIT PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP 57#else 58#define __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION __gthread_recursive_mutex_init_function 59#endif 60 61#if SUPPORTS_WEAK && GTHREAD_USE_WEAK 62# define __gthrw2(name,name2,type) \ 63 static __typeof(type) name __attribute__ ((__weakref__(#name2))); 64# define __gthrw_(name) __gthrw_ ## name 65#else 66# define __gthrw2(name,name2,type) 67# define __gthrw_(name) name 68#endif 69 70/* Typically, __gthrw_foo is a weak reference to symbol foo. */ 71#define __gthrw(name) __gthrw2(__gthrw_ ## name,name,name) 72 73/* On Tru64, /usr/include/pthread.h uses #pragma extern_prefix "__" to 74 map a subset of the POSIX pthread API to mangled versions of their 75 names. */ 76#if defined(__osf__) && defined(_PTHREAD_USE_MANGLED_NAMES_) 77#define __gthrw3(name) __gthrw2(__gthrw_ ## name, __ ## name, name) 78__gthrw3(pthread_once) 79__gthrw3(pthread_getspecific) 80__gthrw3(pthread_setspecific) 81__gthrw3(pthread_create) 82__gthrw3(pthread_cancel) 83__gthrw3(pthread_mutex_lock) 84__gthrw3(pthread_mutex_trylock) 85__gthrw3(pthread_mutex_unlock) 86__gthrw3(pthread_mutex_init) 87#else 88__gthrw(pthread_once) 89__gthrw(pthread_getspecific) 90__gthrw(pthread_setspecific) 91__gthrw(pthread_create) 92__gthrw(pthread_cancel) 93__gthrw(pthread_mutex_lock) 94__gthrw(pthread_mutex_trylock) 95__gthrw(pthread_mutex_unlock) 96__gthrw(pthread_mutex_init) 97#endif 98 99__gthrw(pthread_key_create) 100__gthrw(pthread_key_delete) 101__gthrw(pthread_mutexattr_init) 102__gthrw(pthread_mutexattr_settype) 103__gthrw(pthread_mutexattr_destroy) 104 105 106#if defined(_LIBOBJC) || defined(_LIBOBJC_WEAK) 107/* Objective-C. */ 108#if defined(__osf__) && defined(_PTHREAD_USE_MANGLED_NAMES_) 109__gthrw3(pthread_cond_broadcast) 110__gthrw3(pthread_cond_destroy) 111__gthrw3(pthread_cond_init) 112__gthrw3(pthread_cond_signal) 113__gthrw3(pthread_cond_wait) 114__gthrw3(pthread_exit) 115__gthrw3(pthread_mutex_destroy) 116__gthrw3(pthread_self) 117#else 118__gthrw(pthread_cond_broadcast) 119__gthrw(pthread_cond_destroy) 120__gthrw(pthread_cond_init) 121__gthrw(pthread_cond_signal) 122__gthrw(pthread_cond_wait) 123__gthrw(pthread_exit) 124__gthrw(pthread_mutex_destroy) 125__gthrw(pthread_self) 126#endif /* __osf__ && _PTHREAD_USE_MANGLED_NAMES_ */ 127#ifdef _POSIX_PRIORITY_SCHEDULING 128#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING 129__gthrw(sched_get_priority_max) 130__gthrw(sched_get_priority_min) 131#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */ 132#endif /* _POSIX_PRIORITY_SCHEDULING */ 133__gthrw(sched_yield) 134__gthrw(pthread_attr_destroy) 135__gthrw(pthread_attr_init) 136__gthrw(pthread_attr_setdetachstate) 137#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING 138__gthrw(pthread_getschedparam) 139__gthrw(pthread_setschedparam) 140#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */ 141#endif /* _LIBOBJC || _LIBOBJC_WEAK */ 142 143#if SUPPORTS_WEAK && GTHREAD_USE_WEAK 144 145/* On Solaris 2.6 up to 9, the libc exposes a POSIX threads interface even if 146 -pthreads is not specified. The functions are dummies and most return an 147 error value. However pthread_once returns 0 without invoking the routine 148 it is passed so we cannot pretend that the interface is active if -pthreads 149 is not specified. On Solaris 2.5.1, the interface is not exposed at all so 150 we need to play the usual game with weak symbols. On Solaris 10 and up, a 151 working interface is always exposed. */ 152 153#if defined(__sun) && defined(__svr4__) 154 155static volatile int __gthread_active = -1; 156 157static void 158__gthread_trigger (void) 159{ 160 __gthread_active = 1; 161} 162 163static inline int 164__gthread_active_p (void) 165{ 166 static pthread_mutex_t __gthread_active_mutex = PTHREAD_MUTEX_INITIALIZER; 167 static pthread_once_t __gthread_active_once = PTHREAD_ONCE_INIT; 168 169 /* Avoid reading __gthread_active twice on the main code path. */ 170 int __gthread_active_latest_value = __gthread_active; 171 172 /* This test is not protected to avoid taking a lock on the main code 173 path so every update of __gthread_active in a threaded program must 174 be atomic with regard to the result of the test. */ 175 if (__builtin_expect (__gthread_active_latest_value < 0, 0)) 176 { 177 if (__gthrw_(pthread_once)) 178 { 179 /* If this really is a threaded program, then we must ensure that 180 __gthread_active has been set to 1 before exiting this block. */ 181 __gthrw_(pthread_mutex_lock) (&__gthread_active_mutex); 182 __gthrw_(pthread_once) (&__gthread_active_once, __gthread_trigger); 183 __gthrw_(pthread_mutex_unlock) (&__gthread_active_mutex); 184 } 185 186 /* Make sure we'll never enter this block again. */ 187 if (__gthread_active < 0) 188 __gthread_active = 0; 189 190 __gthread_active_latest_value = __gthread_active; 191 } 192 193 return __gthread_active_latest_value != 0; 194} 195 196#else /* not Solaris */ 197 198static inline int 199__gthread_active_p (void) 200{ 201 static void *const __gthread_active_ptr 202 = __extension__ (void *) &__gthrw_(pthread_cancel); 203 return __gthread_active_ptr != 0; 204} 205 206#endif /* Solaris */ 207 208#else /* not SUPPORTS_WEAK */ 209 210static inline int 211__gthread_active_p (void) 212{ 213 return 1; 214} 215 216#endif /* SUPPORTS_WEAK */ 217 218#ifdef _LIBOBJC 219 220/* This is the config.h file in libobjc/ */ 221#include <config.h> 222 223#ifdef HAVE_SCHED_H 224# include <sched.h> 225#endif 226 227/* Key structure for maintaining thread specific storage */ 228static pthread_key_t _objc_thread_storage; 229static pthread_attr_t _objc_thread_attribs; 230 231/* Thread local storage for a single thread */ 232static void *thread_local_storage = NULL; 233 234/* Backend initialization functions */ 235 236/* Initialize the threads subsystem. */ 237static inline int 238__gthread_objc_init_thread_system (void) 239{ 240 if (__gthread_active_p ()) 241 { 242 /* Initialize the thread storage key. */ 243 if (__gthrw_(pthread_key_create) (&_objc_thread_storage, NULL) == 0) 244 { 245 /* The normal default detach state for threads is 246 * PTHREAD_CREATE_JOINABLE which causes threads to not die 247 * when you think they should. */ 248 if (__gthrw_(pthread_attr_init) (&_objc_thread_attribs) == 0 249 && __gthrw_(pthread_attr_setdetachstate) (&_objc_thread_attribs, 250 PTHREAD_CREATE_DETACHED) == 0) 251 return 0; 252 } 253 } 254 255 return -1; 256} 257 258/* Close the threads subsystem. */ 259static inline int 260__gthread_objc_close_thread_system (void) 261{ 262 if (__gthread_active_p () 263 && __gthrw_(pthread_key_delete) (_objc_thread_storage) == 0 264 && __gthrw_(pthread_attr_destroy) (&_objc_thread_attribs) == 0) 265 return 0; 266 267 return -1; 268} 269 270/* Backend thread functions */ 271 272/* Create a new thread of execution. */ 273static inline objc_thread_t 274__gthread_objc_thread_detach (void (*func)(void *), void *arg) 275{ 276 objc_thread_t thread_id; 277 pthread_t new_thread_handle; 278 279 if (!__gthread_active_p ()) 280 return NULL; 281 282 if (!(__gthrw_(pthread_create) (&new_thread_handle, NULL, (void *) func, arg))) 283 thread_id = (objc_thread_t) new_thread_handle; 284 else 285 thread_id = NULL; 286 287 return thread_id; 288} 289 290/* Set the current thread's priority. */ 291static inline int 292__gthread_objc_thread_set_priority (int priority) 293{ 294 if (!__gthread_active_p ()) 295 return -1; 296 else 297 { 298#ifdef _POSIX_PRIORITY_SCHEDULING 299#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING 300 pthread_t thread_id = __gthrw_(pthread_self) (); 301 int policy; 302 struct sched_param params; 303 int priority_min, priority_max; 304 305 if (__gthrw_(pthread_getschedparam) (thread_id, &policy, ¶ms) == 0) 306 { 307 if ((priority_max = __gthrw_(sched_get_priority_max) (policy)) == -1) 308 return -1; 309 310 if ((priority_min = __gthrw_(sched_get_priority_min) (policy)) == -1) 311 return -1; 312 313 if (priority > priority_max) 314 priority = priority_max; 315 else if (priority < priority_min) 316 priority = priority_min; 317 params.sched_priority = priority; 318 319 /* 320 * The solaris 7 and several other man pages incorrectly state that 321 * this should be a pointer to policy but pthread.h is universally 322 * at odds with this. 323 */ 324 if (__gthrw_(pthread_setschedparam) (thread_id, policy, ¶ms) == 0) 325 return 0; 326 } 327#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */ 328#endif /* _POSIX_PRIORITY_SCHEDULING */ 329 return -1; 330 } 331} 332 333/* Return the current thread's priority. */ 334static inline int 335__gthread_objc_thread_get_priority (void) 336{ 337#ifdef _POSIX_PRIORITY_SCHEDULING 338#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING 339 if (__gthread_active_p ()) 340 { 341 int policy; 342 struct sched_param params; 343 344 if (__gthrw_(pthread_getschedparam) (__gthrw_(pthread_self) (), &policy, ¶ms) == 0) 345 return params.sched_priority; 346 else 347 return -1; 348 } 349 else 350#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */ 351#endif /* _POSIX_PRIORITY_SCHEDULING */ 352 return OBJC_THREAD_INTERACTIVE_PRIORITY; 353} 354 355/* Yield our process time to another thread. */ 356static inline void 357__gthread_objc_thread_yield (void) 358{ 359 if (__gthread_active_p ()) 360 __gthrw_(sched_yield) (); 361} 362 363/* Terminate the current thread. */ 364static inline int 365__gthread_objc_thread_exit (void) 366{ 367 if (__gthread_active_p ()) 368 /* exit the thread */ 369 __gthrw_(pthread_exit) (&__objc_thread_exit_status); 370 371 /* Failed if we reached here */ 372 return -1; 373} 374 375/* Returns an integer value which uniquely describes a thread. */ 376static inline objc_thread_t 377__gthread_objc_thread_id (void) 378{ 379 if (__gthread_active_p ()) 380 return (objc_thread_t) __gthrw_(pthread_self) (); 381 else 382 return (objc_thread_t) 1; 383} 384 385/* Sets the thread's local storage pointer. */ 386static inline int 387__gthread_objc_thread_set_data (void *value) 388{ 389 if (__gthread_active_p ()) 390 return __gthrw_(pthread_setspecific) (_objc_thread_storage, value); 391 else 392 { 393 thread_local_storage = value; 394 return 0; 395 } 396} 397 398/* Returns the thread's local storage pointer. */ 399static inline void * 400__gthread_objc_thread_get_data (void) 401{ 402 if (__gthread_active_p ()) 403 return __gthrw_(pthread_getspecific) (_objc_thread_storage); 404 else 405 return thread_local_storage; 406} 407 408/* Backend mutex functions */ 409 410/* Allocate a mutex. */ 411static inline int 412__gthread_objc_mutex_allocate (objc_mutex_t mutex) 413{ 414 if (__gthread_active_p ()) 415 { 416 mutex->backend = objc_malloc (sizeof (pthread_mutex_t)); 417 418 if (__gthrw_(pthread_mutex_init) ((pthread_mutex_t *) mutex->backend, NULL)) 419 { 420 objc_free (mutex->backend); 421 mutex->backend = NULL; 422 return -1; 423 } 424 } 425 426 return 0; 427} 428 429/* Deallocate a mutex. */ 430static inline int 431__gthread_objc_mutex_deallocate (objc_mutex_t mutex) 432{ 433 if (__gthread_active_p ()) 434 { 435 int count; 436 437 /* 438 * Posix Threads specifically require that the thread be unlocked 439 * for __gthrw_(pthread_mutex_destroy) to work. 440 */ 441 442 do 443 { 444 count = __gthrw_(pthread_mutex_unlock) ((pthread_mutex_t *) mutex->backend); 445 if (count < 0) 446 return -1; 447 } 448 while (count); 449 450 if (__gthrw_(pthread_mutex_destroy) ((pthread_mutex_t *) mutex->backend)) 451 return -1; 452 453 objc_free (mutex->backend); 454 mutex->backend = NULL; 455 } 456 return 0; 457} 458 459/* Grab a lock on a mutex. */ 460static inline int 461__gthread_objc_mutex_lock (objc_mutex_t mutex) 462{ 463 if (__gthread_active_p () 464 && __gthrw_(pthread_mutex_lock) ((pthread_mutex_t *) mutex->backend) != 0) 465 { 466 return -1; 467 } 468 469 return 0; 470} 471 472/* Try to grab a lock on a mutex. */ 473static inline int 474__gthread_objc_mutex_trylock (objc_mutex_t mutex) 475{ 476 if (__gthread_active_p () 477 && __gthrw_(pthread_mutex_trylock) ((pthread_mutex_t *) mutex->backend) != 0) 478 { 479 return -1; 480 } 481 482 return 0; 483} 484 485/* Unlock the mutex */ 486static inline int 487__gthread_objc_mutex_unlock (objc_mutex_t mutex) 488{ 489 if (__gthread_active_p () 490 && __gthrw_(pthread_mutex_unlock) ((pthread_mutex_t *) mutex->backend) != 0) 491 { 492 return -1; 493 } 494 495 return 0; 496} 497 498/* Backend condition mutex functions */ 499 500/* Allocate a condition. */ 501static inline int 502__gthread_objc_condition_allocate (objc_condition_t condition) 503{ 504 if (__gthread_active_p ()) 505 { 506 condition->backend = objc_malloc (sizeof (pthread_cond_t)); 507 508 if (__gthrw_(pthread_cond_init) ((pthread_cond_t *) condition->backend, NULL)) 509 { 510 objc_free (condition->backend); 511 condition->backend = NULL; 512 return -1; 513 } 514 } 515 516 return 0; 517} 518 519/* Deallocate a condition. */ 520static inline int 521__gthread_objc_condition_deallocate (objc_condition_t condition) 522{ 523 if (__gthread_active_p ()) 524 { 525 if (__gthrw_(pthread_cond_destroy) ((pthread_cond_t *) condition->backend)) 526 return -1; 527 528 objc_free (condition->backend); 529 condition->backend = NULL; 530 } 531 return 0; 532} 533 534/* Wait on the condition */ 535static inline int 536__gthread_objc_condition_wait (objc_condition_t condition, objc_mutex_t mutex) 537{ 538 if (__gthread_active_p ()) 539 return __gthrw_(pthread_cond_wait) ((pthread_cond_t *) condition->backend, 540 (pthread_mutex_t *) mutex->backend); 541 else 542 return 0; 543} 544 545/* Wake up all threads waiting on this condition. */ 546static inline int 547__gthread_objc_condition_broadcast (objc_condition_t condition) 548{ 549 if (__gthread_active_p ()) 550 return __gthrw_(pthread_cond_broadcast) ((pthread_cond_t *) condition->backend); 551 else 552 return 0; 553} 554 555/* Wake up one thread waiting on this condition. */ 556static inline int 557__gthread_objc_condition_signal (objc_condition_t condition) 558{ 559 if (__gthread_active_p ()) 560 return __gthrw_(pthread_cond_signal) ((pthread_cond_t *) condition->backend); 561 else 562 return 0; 563} 564 565#else /* _LIBOBJC */ 566 567static inline int 568__gthread_once (__gthread_once_t *once, void (*func) (void)) 569{ 570 if (__gthread_active_p ()) 571 return __gthrw_(pthread_once) (once, func); 572 else 573 return -1; 574} 575 576static inline int 577__gthread_key_create (__gthread_key_t *key, void (*dtor) (void *)) 578{ 579 return __gthrw_(pthread_key_create) (key, dtor); 580} 581 582static inline int 583__gthread_key_delete (__gthread_key_t key) 584{ 585 return __gthrw_(pthread_key_delete) (key); 586} 587 588static inline void * 589__gthread_getspecific (__gthread_key_t key) 590{ 591 return __gthrw_(pthread_getspecific) (key); 592} 593 594static inline int 595__gthread_setspecific (__gthread_key_t key, const void *ptr) 596{ 597 return __gthrw_(pthread_setspecific) (key, ptr); 598} 599 600static inline int 601__gthread_mutex_lock (__gthread_mutex_t *mutex) 602{ 603 if (__gthread_active_p ()) 604 return __gthrw_(pthread_mutex_lock) (mutex); 605 else 606 return 0; 607} 608 609static inline int 610__gthread_mutex_trylock (__gthread_mutex_t *mutex) 611{ 612 if (__gthread_active_p ()) 613 return __gthrw_(pthread_mutex_trylock) (mutex); 614 else 615 return 0; 616} 617 618static inline int 619__gthread_mutex_unlock (__gthread_mutex_t *mutex) 620{ 621 if (__gthread_active_p ()) 622 return __gthrw_(pthread_mutex_unlock) (mutex); 623 else 624 return 0; 625} 626 627#ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP 628static inline int 629__gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *mutex) 630{ 631 if (__gthread_active_p ()) 632 { 633 pthread_mutexattr_t attr; 634 int r; 635 636 r = __gthrw_(pthread_mutexattr_init) (&attr); 637 if (!r) 638 r = __gthrw_(pthread_mutexattr_settype) (&attr, PTHREAD_MUTEX_RECURSIVE); 639 if (!r) 640 r = __gthrw_(pthread_mutex_init) (mutex, &attr); 641 if (!r) 642 r = __gthrw_(pthread_mutexattr_destroy) (&attr); 643 return r; 644 } 645 return 0; 646} 647#endif 648 649static inline int 650__gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex) 651{ 652 return __gthread_mutex_lock (mutex); 653} 654 655static inline int 656__gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex) 657{ 658 return __gthread_mutex_trylock (mutex); 659} 660 661static inline int 662__gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex) 663{ 664 return __gthread_mutex_unlock (mutex); 665} 666 667#endif /* _LIBOBJC */ 668 669#endif /* ! GCC_GTHR_POSIX_H */ 670