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