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