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  extern __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#ifdef _POSIX_PRIORITY_SCHEDULING
95#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
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#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
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
112static inline int
113__gthread_active_p (void)
114{
115  static void *const __gthread_active_ptr
116    = __extension__ (void *) &__gthrw_(pthread_cancel);
117  return __gthread_active_ptr != 0;
118}
119
120#else /* not SUPPORTS_WEAK */
121
122static inline int
123__gthread_active_p (void)
124{
125  return 1;
126}
127
128#endif /* SUPPORTS_WEAK */
129
130#ifdef _LIBOBJC
131
132/* This is the config.h file in libobjc/ */
133#include <config.h>
134
135#ifdef HAVE_SCHED_H
136# include <sched.h>
137#endif
138
139/* Key structure for maintaining thread specific storage */
140static pthread_key_t _objc_thread_storage;
141static pthread_attr_t _objc_thread_attribs;
142
143/* Thread local storage for a single thread */
144static void *thread_local_storage = NULL;
145
146/* Backend initialization functions */
147
148/* Initialize the threads subsystem.  */
149static inline int
150__gthread_objc_init_thread_system (void)
151{
152  if (__gthread_active_p ())
153    {
154      /* Initialize the thread storage key.  */
155      if (__gthrw_(pthread_key_create) (&_objc_thread_storage, NULL) == 0)
156	{
157	  /* The normal default detach state for threads is
158	   * PTHREAD_CREATE_JOINABLE which causes threads to not die
159	   * when you think they should.  */
160	  if (__gthrw_(pthread_attr_init) (&_objc_thread_attribs) == 0
161	      && __gthrw_(pthread_attr_setdetachstate) (&_objc_thread_attribs,
162					      PTHREAD_CREATE_DETACHED) == 0)
163	    return 0;
164	}
165    }
166
167  return -1;
168}
169
170/* Close the threads subsystem.  */
171static inline int
172__gthread_objc_close_thread_system (void)
173{
174  if (__gthread_active_p ()
175      && __gthrw_(pthread_key_delete) (_objc_thread_storage) == 0
176      && __gthrw_(pthread_attr_destroy) (&_objc_thread_attribs) == 0)
177    return 0;
178
179  return -1;
180}
181
182/* Backend thread functions */
183
184/* Create a new thread of execution.  */
185static inline objc_thread_t
186__gthread_objc_thread_detach (void (*func)(void *), void *arg)
187{
188  objc_thread_t thread_id;
189  pthread_t new_thread_handle;
190
191  if (!__gthread_active_p ())
192    return NULL;
193
194  if (!(__gthrw_(pthread_create) (&new_thread_handle, NULL, (void *) func, arg)))
195    thread_id = (objc_thread_t) new_thread_handle;
196  else
197    thread_id = NULL;
198
199  return thread_id;
200}
201
202/* Set the current thread's priority.  */
203static inline int
204__gthread_objc_thread_set_priority (int priority)
205{
206  if (!__gthread_active_p ())
207    return -1;
208  else
209    {
210#ifdef _POSIX_PRIORITY_SCHEDULING
211#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
212      pthread_t thread_id = __gthrw_(pthread_self) ();
213      int policy;
214      struct sched_param params;
215      int priority_min, priority_max;
216
217      if (__gthrw_(pthread_getschedparam) (thread_id, &policy, &params) == 0)
218	{
219	  if ((priority_max = __gthrw_(sched_get_priority_max) (policy)) == -1)
220	    return -1;
221
222	  if ((priority_min = __gthrw_(sched_get_priority_min) (policy)) == -1)
223	    return -1;
224
225	  if (priority > priority_max)
226	    priority = priority_max;
227	  else if (priority < priority_min)
228	    priority = priority_min;
229	  params.sched_priority = priority;
230
231	  /*
232	   * The solaris 7 and several other man pages incorrectly state that
233	   * this should be a pointer to policy but pthread.h is universally
234	   * at odds with this.
235	   */
236	  if (__gthrw_(pthread_setschedparam) (thread_id, policy, &params) == 0)
237	    return 0;
238	}
239#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
240#endif /* _POSIX_PRIORITY_SCHEDULING */
241      return -1;
242    }
243}
244
245/* Return the current thread's priority.  */
246static inline int
247__gthread_objc_thread_get_priority (void)
248{
249#ifdef _POSIX_PRIORITY_SCHEDULING
250#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
251  if (__gthread_active_p ())
252    {
253      int policy;
254      struct sched_param params;
255
256      if (__gthrw_(pthread_getschedparam) (__gthrw_(pthread_self) (), &policy, &params) == 0)
257	return params.sched_priority;
258      else
259	return -1;
260    }
261  else
262#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
263#endif /* _POSIX_PRIORITY_SCHEDULING */
264    return OBJC_THREAD_INTERACTIVE_PRIORITY;
265}
266
267/* Yield our process time to another thread.  */
268static inline void
269__gthread_objc_thread_yield (void)
270{
271  if (__gthread_active_p ())
272    __gthrw_(sched_yield) ();
273}
274
275/* Terminate the current thread.  */
276static inline int
277__gthread_objc_thread_exit (void)
278{
279  if (__gthread_active_p ())
280    /* exit the thread */
281    __gthrw_(pthread_exit) (&__objc_thread_exit_status);
282
283  /* Failed if we reached here */
284  return -1;
285}
286
287/* Returns an integer value which uniquely describes a thread.  */
288static inline objc_thread_t
289__gthread_objc_thread_id (void)
290{
291  if (__gthread_active_p ())
292    return (objc_thread_t) __gthrw_(pthread_self) ();
293  else
294    return (objc_thread_t) 1;
295}
296
297/* Sets the thread's local storage pointer.  */
298static inline int
299__gthread_objc_thread_set_data (void *value)
300{
301  if (__gthread_active_p ())
302    return __gthrw_(pthread_setspecific) (_objc_thread_storage, value);
303  else
304    {
305      thread_local_storage = value;
306      return 0;
307    }
308}
309
310/* Returns the thread's local storage pointer.  */
311static inline void *
312__gthread_objc_thread_get_data (void)
313{
314  if (__gthread_active_p ())
315    return __gthrw_(pthread_getspecific) (_objc_thread_storage);
316  else
317    return thread_local_storage;
318}
319
320/* Backend mutex functions */
321
322/* Allocate a mutex.  */
323static inline int
324__gthread_objc_mutex_allocate (objc_mutex_t mutex)
325{
326  if (__gthread_active_p ())
327    {
328      mutex->backend = objc_malloc (sizeof (pthread_mutex_t));
329
330      if (__gthrw_(pthread_mutex_init) ((pthread_mutex_t *) mutex->backend, NULL))
331	{
332	  objc_free (mutex->backend);
333	  mutex->backend = NULL;
334	  return -1;
335	}
336    }
337
338  return 0;
339}
340
341/* Deallocate a mutex.  */
342static inline int
343__gthread_objc_mutex_deallocate (objc_mutex_t mutex)
344{
345  if (__gthread_active_p ())
346    {
347      int count;
348
349      /*
350       * Posix Threads specifically require that the thread be unlocked
351       * for __gthrw_(pthread_mutex_destroy) to work.
352       */
353
354      do
355	{
356	  count = __gthrw_(pthread_mutex_unlock) ((pthread_mutex_t *) mutex->backend);
357	  if (count < 0)
358	    return -1;
359	}
360      while (count);
361
362      if (__gthrw_(pthread_mutex_destroy) ((pthread_mutex_t *) mutex->backend))
363	return -1;
364
365      objc_free (mutex->backend);
366      mutex->backend = NULL;
367    }
368  return 0;
369}
370
371/* Grab a lock on a mutex.  */
372static inline int
373__gthread_objc_mutex_lock (objc_mutex_t mutex)
374{
375  if (__gthread_active_p ()
376      && __gthrw_(pthread_mutex_lock) ((pthread_mutex_t *) mutex->backend) != 0)
377    {
378      return -1;
379    }
380
381  return 0;
382}
383
384/* Try to grab a lock on a mutex.  */
385static inline int
386__gthread_objc_mutex_trylock (objc_mutex_t mutex)
387{
388  if (__gthread_active_p ()
389      && __gthrw_(pthread_mutex_trylock) ((pthread_mutex_t *) mutex->backend) != 0)
390    {
391      return -1;
392    }
393
394  return 0;
395}
396
397/* Unlock the mutex */
398static inline int
399__gthread_objc_mutex_unlock (objc_mutex_t mutex)
400{
401  if (__gthread_active_p ()
402      && __gthrw_(pthread_mutex_unlock) ((pthread_mutex_t *) mutex->backend) != 0)
403    {
404      return -1;
405    }
406
407  return 0;
408}
409
410/* Backend condition mutex functions */
411
412/* Allocate a condition.  */
413static inline int
414__gthread_objc_condition_allocate (objc_condition_t condition)
415{
416  if (__gthread_active_p ())
417    {
418      condition->backend = objc_malloc (sizeof (pthread_cond_t));
419
420      if (__gthrw_(pthread_cond_init) ((pthread_cond_t *) condition->backend, NULL))
421	{
422	  objc_free (condition->backend);
423	  condition->backend = NULL;
424	  return -1;
425	}
426    }
427
428  return 0;
429}
430
431/* Deallocate a condition.  */
432static inline int
433__gthread_objc_condition_deallocate (objc_condition_t condition)
434{
435  if (__gthread_active_p ())
436    {
437      if (__gthrw_(pthread_cond_destroy) ((pthread_cond_t *) condition->backend))
438	return -1;
439
440      objc_free (condition->backend);
441      condition->backend = NULL;
442    }
443  return 0;
444}
445
446/* Wait on the condition */
447static inline int
448__gthread_objc_condition_wait (objc_condition_t condition, objc_mutex_t mutex)
449{
450  if (__gthread_active_p ())
451    return __gthrw_(pthread_cond_wait) ((pthread_cond_t *) condition->backend,
452			      (pthread_mutex_t *) mutex->backend);
453  else
454    return 0;
455}
456
457/* Wake up all threads waiting on this condition.  */
458static inline int
459__gthread_objc_condition_broadcast (objc_condition_t condition)
460{
461  if (__gthread_active_p ())
462    return __gthrw_(pthread_cond_broadcast) ((pthread_cond_t *) condition->backend);
463  else
464    return 0;
465}
466
467/* Wake up one thread waiting on this condition.  */
468static inline int
469__gthread_objc_condition_signal (objc_condition_t condition)
470{
471  if (__gthread_active_p ())
472    return __gthrw_(pthread_cond_signal) ((pthread_cond_t *) condition->backend);
473  else
474    return 0;
475}
476
477#else /* _LIBOBJC */
478
479static inline int
480__gthread_once (__gthread_once_t *once, void (*func) (void))
481{
482  if (__gthread_active_p ())
483    return __gthrw_(pthread_once) (once, func);
484  else
485    return -1;
486}
487
488static inline int
489__gthread_key_create (__gthread_key_t *key, void (*dtor) (void *))
490{
491  return __gthrw_(pthread_key_create) (key, dtor);
492}
493
494static inline int
495__gthread_key_delete (__gthread_key_t key)
496{
497  return __gthrw_(pthread_key_delete) (key);
498}
499
500static inline void *
501__gthread_getspecific (__gthread_key_t key)
502{
503  return __gthrw_(pthread_getspecific) (key);
504}
505
506static inline int
507__gthread_setspecific (__gthread_key_t key, const void *ptr)
508{
509  return __gthrw_(pthread_setspecific) (key, ptr);
510}
511
512static inline int
513__gthread_mutex_lock (__gthread_mutex_t *mutex)
514{
515  if (__gthread_active_p ())
516    return __gthrw_(pthread_mutex_lock) (mutex);
517  else
518    return 0;
519}
520
521static inline int
522__gthread_mutex_trylock (__gthread_mutex_t *mutex)
523{
524  if (__gthread_active_p ())
525    return __gthrw_(pthread_mutex_trylock) (mutex);
526  else
527    return 0;
528}
529
530static inline int
531__gthread_mutex_unlock (__gthread_mutex_t *mutex)
532{
533  if (__gthread_active_p ())
534    return __gthrw_(pthread_mutex_unlock) (mutex);
535  else
536    return 0;
537}
538
539static inline int
540__gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *mutex)
541{
542  mutex->depth = 0;
543  mutex->owner = (pthread_t) 0;
544  return __gthrw_(pthread_mutex_init) (&mutex->actual, NULL);
545}
546
547static inline int
548__gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex)
549{
550  if (__gthread_active_p ())
551    {
552      pthread_t me = __gthrw_(pthread_self) ();
553
554      if (mutex->owner != me)
555	{
556	  __gthrw_(pthread_mutex_lock) (&mutex->actual);
557	  mutex->owner = me;
558	}
559
560      mutex->depth++;
561    }
562  return 0;
563}
564
565static inline int
566__gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex)
567{
568  if (__gthread_active_p ())
569    {
570      pthread_t me = __gthrw_(pthread_self) ();
571
572      if (mutex->owner != me)
573	{
574	  if (__gthrw_(pthread_mutex_trylock) (&mutex->actual))
575	    return 1;
576	  mutex->owner = me;
577	}
578
579      mutex->depth++;
580    }
581  return 0;
582}
583
584static inline int
585__gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex)
586{
587  if (__gthread_active_p ())
588    {
589      if (--mutex->depth == 0)
590	{
591	   mutex->owner = (pthread_t) 0;
592	   __gthrw_(pthread_mutex_unlock) (&mutex->actual);
593	}
594    }
595  return 0;
596}
597
598#endif /* _LIBOBJC */
599
600#endif /* ! GCC_GTHR_POSIX_H */
601