gthr-posix.h 13.6 KB
Newer Older
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
4
   Free Software Foundation, Inc.
5

6
This file is part of GCC.
7

8 9 10 11
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.
12

13 14 15 16
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.
17 18

You should have received a copy of the GNU General Public License
19 20 21
along with GCC; see the file COPYING.  If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.  */
22 23 24 25 26 27 28 29

/* As a special exception, if you link this library with other files,
   some of which are compiled with GCC, to produce an executable,
   this library does not by itself cause the resulting executable
   to be covered by the GNU General Public License.
   This exception does not however invalidate any other reasons why
   the executable file might be covered by the GNU General Public License.  */

30 31
#ifndef GCC_GTHR_POSIX_H
#define GCC_GTHR_POSIX_H
32 33

/* POSIX threads specific definitions.
34
   Easy, since the interface is just one-to-one mapping.  */
35 36 37

#define __GTHREADS 1

38 39 40 41 42
/* Some implementations of <pthread.h> require this to be defined.  */
#ifndef _REENTRANT
#define _REENTRANT 1
#endif

43
#include <pthread.h>
44
#include <unistd.h>
45 46 47 48

typedef pthread_key_t __gthread_key_t;
typedef pthread_once_t __gthread_once_t;
typedef pthread_mutex_t __gthread_mutex_t;
49
typedef pthread_mutex_t __gthread_recursive_mutex_t;
50 51 52

#define __GTHREAD_MUTEX_INIT PTHREAD_MUTEX_INITIALIZER
#define __GTHREAD_ONCE_INIT PTHREAD_ONCE_INIT
53 54 55 56
#if defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER)
#define __GTHREAD_RECURSIVE_MUTEX_INIT PTHREAD_RECURSIVE_MUTEX_INITIALIZER
#elif defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP)
#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 62

#if SUPPORTS_WEAK && GTHREAD_USE_WEAK

63 64 65 66 67 68
#pragma weak pthread_once
#pragma weak pthread_key_create
#pragma weak pthread_key_delete
#pragma weak pthread_getspecific
#pragma weak pthread_setspecific
#pragma weak pthread_create
69
#pragma weak pthread_cancel
70

71 72 73
#pragma weak pthread_mutex_lock
#pragma weak pthread_mutex_trylock
#pragma weak pthread_mutex_unlock
74 75 76 77 78
#pragma weak pthread_mutexattr_init
#pragma weak pthread_mutexattr_settype
#pragma weak pthread_mutexattr_destroy

#pragma weak pthread_mutex_init
79

80
#if defined(_LIBOBJC) || defined(_LIBOBJC_WEAK)
81
/* Objective-C.  */
82 83 84 85 86 87 88 89
#pragma weak pthread_cond_broadcast
#pragma weak pthread_cond_destroy
#pragma weak pthread_cond_init
#pragma weak pthread_cond_signal
#pragma weak pthread_cond_wait
#pragma weak pthread_exit
#pragma weak pthread_mutex_destroy
#pragma weak pthread_self
90
#ifdef _POSIX_PRIORITY_SCHEDULING
91
#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
92 93
#pragma weak sched_get_priority_max
#pragma weak sched_get_priority_min
94
#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
95
#endif /* _POSIX_PRIORITY_SCHEDULING */
96
#pragma weak sched_yield
97 98 99
#pragma weak pthread_attr_destroy
#pragma weak pthread_attr_init
#pragma weak pthread_attr_setdetachstate
100
#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
101 102
#pragma weak pthread_getschedparam
#pragma weak pthread_setschedparam
103
#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
104
#endif /* _LIBOBJC || _LIBOBJC_WEAK */
105 106

static inline int
107
__gthread_active_p (void)
108
{
109
  static void *const __gthread_active_ptr 
110
    = __extension__ (void *) &pthread_cancel;
111 112 113 114 115 116
  return __gthread_active_ptr != 0;
}

#else /* not SUPPORTS_WEAK */

static inline int
117
__gthread_active_p (void)
118 119 120 121 122 123
{
  return 1;
}

#endif /* SUPPORTS_WEAK */

124 125
#ifdef _LIBOBJC

126 127 128 129 130 131 132
/* This is the config.h file in libobjc/ */
#include <config.h>

#ifdef HAVE_SCHED_H
# include <sched.h>
#endif

133 134
/* Key structure for maintaining thread specific storage */
static pthread_key_t _objc_thread_storage;
135
static pthread_attr_t _objc_thread_attribs;
136 137 138 139 140 141

/* Thread local storage for a single thread */
static void *thread_local_storage = NULL;

/* Backend initialization functions */

142
/* Initialize the threads subsystem.  */
143
static inline int
144
__gthread_objc_init_thread_system (void)
145 146
{
  if (__gthread_active_p ())
147
    {
148
      /* Initialize the thread storage key.  */
149
      if (pthread_key_create (&_objc_thread_storage, NULL) == 0)
150 151 152 153
	{
	  /* The normal default detach state for threads is
	   * PTHREAD_CREATE_JOINABLE which causes threads to not die
	   * when you think they should.  */
154 155 156
	  if (pthread_attr_init (&_objc_thread_attribs) == 0
	      && pthread_attr_setdetachstate (&_objc_thread_attribs,
					      PTHREAD_CREATE_DETACHED) == 0)
157 158
	    return 0;
	}
159
    }
160 161

  return -1;
162 163
}

164
/* Close the threads subsystem.  */
165
static inline int
166
__gthread_objc_close_thread_system (void)
167
{
168
  if (__gthread_active_p ()
169 170
      && pthread_key_delete (_objc_thread_storage) == 0
      && pthread_attr_destroy (&_objc_thread_attribs) == 0)
171
    return 0;
172 173

  return -1;
174 175 176 177
}

/* Backend thread functions */

178
/* Create a new thread of execution.  */
179
static inline objc_thread_t
180
__gthread_objc_thread_detach (void (*func)(void *), void *arg)
181 182 183 184 185 186
{
  objc_thread_t thread_id;
  pthread_t new_thread_handle;

  if (!__gthread_active_p ())
    return NULL;
187

188
  if (!(pthread_create (&new_thread_handle, NULL, (void *) func, arg)))
189
    thread_id = (objc_thread_t) new_thread_handle;
190 191
  else
    thread_id = NULL;
192

193 194 195
  return thread_id;
}

196
/* Set the current thread's priority.  */
197
static inline int
198
__gthread_objc_thread_set_priority (int priority)
199
{
200
  if (!__gthread_active_p ())
201
    return -1;
202 203
  else
    {
204
#ifdef _POSIX_PRIORITY_SCHEDULING
205
#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
206 207 208 209
      pthread_t thread_id = pthread_self ();
      int policy;
      struct sched_param params;
      int priority_min, priority_max;
210

211 212 213 214 215 216 217
      if (pthread_getschedparam (thread_id, &policy, &params) == 0)
	{
	  if ((priority_max = sched_get_priority_max (policy)) == -1)
	    return -1;

	  if ((priority_min = sched_get_priority_min (policy)) == -1)
	    return -1;
218

219 220 221 222 223 224 225 226 227 228 229 230 231 232
	  if (priority > priority_max)
	    priority = priority_max;
	  else if (priority < priority_min)
	    priority = priority_min;
	  params.sched_priority = priority;

	  /*
	   * The solaris 7 and several other man pages incorrectly state that
	   * this should be a pointer to policy but pthread.h is universally
	   * at odds with this.
	   */
	  if (pthread_setschedparam (thread_id, policy, &params) == 0)
	    return 0;
	}
233
#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
234
#endif /* _POSIX_PRIORITY_SCHEDULING */
235 236
      return -1;
    }
237 238
}

239
/* Return the current thread's priority.  */
240
static inline int
241
__gthread_objc_thread_get_priority (void)
242
{
243
#ifdef _POSIX_PRIORITY_SCHEDULING
244
#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
245
  if (__gthread_active_p ())
246 247 248 249
    {
      int policy;
      struct sched_param params;

250
      if (pthread_getschedparam (pthread_self (), &policy, &params) == 0)
251
	return params.sched_priority;
252
      else
253
	return -1;
254
    }
255
  else
256
#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
257
#endif /* _POSIX_PRIORITY_SCHEDULING */
258 259 260
    return OBJC_THREAD_INTERACTIVE_PRIORITY;
}

261
/* Yield our process time to another thread.  */
262
static inline void
263
__gthread_objc_thread_yield (void)
264 265
{
  if (__gthread_active_p ())
266
    sched_yield ();
267 268
}

269
/* Terminate the current thread.  */
270
static inline int
271
__gthread_objc_thread_exit (void)
272 273 274
{
  if (__gthread_active_p ())
    /* exit the thread */
275
    pthread_exit (&__objc_thread_exit_status);
276 277 278 279 280

  /* Failed if we reached here */
  return -1;
}

281
/* Returns an integer value which uniquely describes a thread.  */
282
static inline objc_thread_t
283
__gthread_objc_thread_id (void)
284 285
{
  if (__gthread_active_p ())
286
    return (objc_thread_t) pthread_self ();
287
  else
288
    return (objc_thread_t) 1;
289 290
}

291
/* Sets the thread's local storage pointer.  */
292
static inline int
293
__gthread_objc_thread_set_data (void *value)
294 295
{
  if (__gthread_active_p ())
296
    return pthread_setspecific (_objc_thread_storage, value);
297 298 299 300 301 302 303
  else
    {
      thread_local_storage = value;
      return 0;
    }
}

304
/* Returns the thread's local storage pointer.  */
305
static inline void *
306
__gthread_objc_thread_get_data (void)
307 308
{
  if (__gthread_active_p ())
309
    return pthread_getspecific (_objc_thread_storage);
310 311 312 313 314 315
  else
    return thread_local_storage;
}

/* Backend mutex functions */

316
/* Allocate a mutex.  */
317
static inline int
318
__gthread_objc_mutex_allocate (objc_mutex_t mutex)
319 320 321
{
  if (__gthread_active_p ())
    {
322
      mutex->backend = objc_malloc (sizeof (pthread_mutex_t));
323

324
      if (pthread_mutex_init ((pthread_mutex_t *) mutex->backend, NULL))
325
	{
326
	  objc_free (mutex->backend);
327 328 329 330 331 332 333 334
	  mutex->backend = NULL;
	  return -1;
	}
    }

  return 0;
}

335
/* Deallocate a mutex.  */
336
static inline int
337
__gthread_objc_mutex_deallocate (objc_mutex_t mutex)
338 339 340 341 342 343 344 345 346 347 348 349
{
  if (__gthread_active_p ())
    {
      int count;

      /*
       * Posix Threads specifically require that the thread be unlocked
       * for pthread_mutex_destroy to work.
       */

      do
	{
350
	  count = pthread_mutex_unlock ((pthread_mutex_t *) mutex->backend);
351 352 353 354 355
	  if (count < 0)
	    return -1;
	}
      while (count);

356
      if (pthread_mutex_destroy ((pthread_mutex_t *) mutex->backend))
357 358
	return -1;

359
      objc_free (mutex->backend);
360 361 362 363 364
      mutex->backend = NULL;
    }
  return 0;
}

365
/* Grab a lock on a mutex.  */
366
static inline int
367
__gthread_objc_mutex_lock (objc_mutex_t mutex)
368
{
369
  if (__gthread_active_p ()
370
      && pthread_mutex_lock ((pthread_mutex_t *) mutex->backend) != 0)
371 372 373 374 375
    {
      return -1;
    }

  return 0;
376 377
}

378
/* Try to grab a lock on a mutex.  */
379
static inline int
380
__gthread_objc_mutex_trylock (objc_mutex_t mutex)
381
{
382
  if (__gthread_active_p ()
383
      && pthread_mutex_trylock ((pthread_mutex_t *) mutex->backend) != 0)
384 385 386 387 388
    {
      return -1;
    }

  return 0;
389 390 391 392
}

/* Unlock the mutex */
static inline int
393
__gthread_objc_mutex_unlock (objc_mutex_t mutex)
394
{
395
  if (__gthread_active_p ()
396
      && pthread_mutex_unlock ((pthread_mutex_t *) mutex->backend) != 0)
397 398 399 400 401
    {
      return -1;
    }

  return 0;
402 403 404 405
}

/* Backend condition mutex functions */

406
/* Allocate a condition.  */
407
static inline int
408
__gthread_objc_condition_allocate (objc_condition_t condition)
409 410 411
{
  if (__gthread_active_p ())
    {
412
      condition->backend = objc_malloc (sizeof (pthread_cond_t));
413

414
      if (pthread_cond_init ((pthread_cond_t *) condition->backend, NULL))
415
	{
416
	  objc_free (condition->backend);
417 418 419 420 421 422 423 424
	  condition->backend = NULL;
	  return -1;
	}
    }

  return 0;
}

425
/* Deallocate a condition.  */
426
static inline int
427
__gthread_objc_condition_deallocate (objc_condition_t condition)
428 429 430
{
  if (__gthread_active_p ())
    {
431
      if (pthread_cond_destroy ((pthread_cond_t *) condition->backend))
432 433
	return -1;

434
      objc_free (condition->backend);
435 436 437 438 439 440 441
      condition->backend = NULL;
    }
  return 0;
}

/* Wait on the condition */
static inline int
442
__gthread_objc_condition_wait (objc_condition_t condition, objc_mutex_t mutex)
443 444
{
  if (__gthread_active_p ())
445 446
    return pthread_cond_wait ((pthread_cond_t *) condition->backend,
			      (pthread_mutex_t *) mutex->backend);
447 448 449 450
  else
    return 0;
}

451
/* Wake up all threads waiting on this condition.  */
452
static inline int
453
__gthread_objc_condition_broadcast (objc_condition_t condition)
454 455
{
  if (__gthread_active_p ())
456
    return pthread_cond_broadcast ((pthread_cond_t *) condition->backend);
457 458 459 460
  else
    return 0;
}

461
/* Wake up one thread waiting on this condition.  */
462
static inline int
463
__gthread_objc_condition_signal (objc_condition_t condition)
464 465
{
  if (__gthread_active_p ())
466
    return pthread_cond_signal ((pthread_cond_t *) condition->backend);
467 468 469 470 471 472
  else
    return 0;
}

#else /* _LIBOBJC */

473
static inline int
474
__gthread_once (__gthread_once_t *once, void (*func) (void))
475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532
{
  if (__gthread_active_p ())
    return pthread_once (once, func);
  else
    return -1;
}

static inline int
__gthread_key_create (__gthread_key_t *key, void (*dtor) (void *))
{
  return pthread_key_create (key, dtor);
}

static inline int
__gthread_key_delete (__gthread_key_t key)
{
  return pthread_key_delete (key);
}

static inline void *
__gthread_getspecific (__gthread_key_t key)
{
  return pthread_getspecific (key);
}

static inline int
__gthread_setspecific (__gthread_key_t key, const void *ptr)
{
  return pthread_setspecific (key, ptr);
}

static inline int
__gthread_mutex_lock (__gthread_mutex_t *mutex)
{
  if (__gthread_active_p ())
    return pthread_mutex_lock (mutex);
  else
    return 0;
}

static inline int
__gthread_mutex_trylock (__gthread_mutex_t *mutex)
{
  if (__gthread_active_p ())
    return pthread_mutex_trylock (mutex);
  else
    return 0;
}

static inline int
__gthread_mutex_unlock (__gthread_mutex_t *mutex)
{
  if (__gthread_active_p ())
    return pthread_mutex_unlock (mutex);
  else
    return 0;
}

533
#ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550
static inline int
__gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *mutex)
{
  if (__gthread_active_p ())
    {
      pthread_mutexattr_t attr;
      int r;

      r = pthread_mutexattr_init (&attr);
      if (!r)
	r = pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
      if (!r)
	r = pthread_mutex_init (mutex, &attr);
      if (!r)
	r = pthread_mutexattr_destroy (&attr);
      return r;
    }
551
  return 0;
552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572
}
#endif

static inline int
__gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex)
{
  return __gthread_mutex_lock (mutex);
}

static inline int
__gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex)
{
  return __gthread_mutex_trylock (mutex);
}

static inline int
__gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex)
{
  return __gthread_mutex_unlock (mutex);
}

573 574
#endif /* _LIBOBJC */

575
#endif /* ! GCC_GTHR_POSIX_H */