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