1/* Threads compatibility routines for libgcc2 and libobjc.  */
2/* Compile this one with gcc.  */
3/* Copyright (C) 1997, 1999, 2000, 2001, 2004, 2005, 2008, 2009
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 3, 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
18Under Section 7 of GPL version 3, you are granted additional
19permissions described in the GCC Runtime Library Exception, version
203.1, as published by the Free Software Foundation.
21
22You should have received a copy of the GNU General Public License and
23a copy of the GCC Runtime Library Exception along with this program;
24see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
25<http://www.gnu.org/licenses/>.  */
26
27#ifndef GCC_GTHR_DCE_H
28#define GCC_GTHR_DCE_H
29
30/* If _DCE_THREADS is not defined, then we're building the single
31   threaded version of the libraries and do not want to reference
32   anything related to pthreads or dce.  */
33#ifndef _DCE_THREADS
34#include "gthr-single.h"
35#else
36/* DCE threads interface.
37   DCE threads are based on POSIX threads draft 4, and many things
38   have changed since then.  */
39
40/* Make sure CONST_CAST2 (original in system.h) is defined.  */
41#ifndef CONST_CAST2
42#ifdef __cplusplus
43#define CONST_CAST2(TOTYPE,FROMTYPE,X) (const_cast<TOTYPE> (X))
44#else
45#define CONST_CAST2(TOTYPE,FROMTYPE,X) ((__extension__(union {FROMTYPE _q; TOTYPE _nq;})(X))._nq)
46#endif
47#endif
48
49#define __GTHREADS 1
50
51#include <pthread.h>
52
53typedef pthread_key_t __gthread_key_t;
54typedef pthread_once_t __gthread_once_t;
55typedef pthread_mutex_t __gthread_mutex_t;
56typedef pthread_mutex_t __gthread_recursive_mutex_t;
57
58#define __GTHREAD_ONCE_INIT pthread_once_init
59
60#define __GTHREAD_MUTEX_INIT_FUNCTION __gthread_mutex_init_function
61#define __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION __gthread_recursive_mutex_init_function
62
63#define __GTHREAD_MUTEX_INIT_DEFAULT pthread_once_init
64
65#if SUPPORTS_WEAK && GTHREAD_USE_WEAK
66# define __gthrw(name) \
67  static __typeof(name) __gthrw_ ## name __attribute__ ((__weakref__(#name)));
68# define __gthrw_(name) __gthrw_ ## name
69#else
70# define __gthrw(name)
71# define __gthrw_(name) name
72#endif
73
74__gthrw(pthread_once)
75__gthrw(pthread_keycreate)
76__gthrw(pthread_getspecific)
77__gthrw(pthread_setspecific)
78__gthrw(pthread_create)
79__gthrw(pthread_mutex_init)
80__gthrw(pthread_mutex_destroy)
81__gthrw(pthread_mutex_lock)
82__gthrw(pthread_mutex_trylock)
83__gthrw(pthread_mutex_unlock)
84__gthrw(pthread_mutexattr_create)
85__gthrw(pthread_mutexattr_setkind_np)
86__gthrw(pthread_mutexattr_delete)
87
88#ifdef _LIBOBJC
89/* Objective-C.  */
90__gthrw(pthread_cond_broadcast)
91__gthrw(pthread_cond_destroy)
92__gthrw(pthread_cond_init)
93__gthrw(pthread_cond_signal)
94__gthrw(pthread_cond_wait)
95__gthrw(pthread_exit)
96
97#ifdef pthread_getunique_np
98# define __gthrw_pthread_getunique_np pthread_getunique_np
99#else
100__gthrw(pthread_getunique_np)
101# define __gthrw_pthread_getunique_np __gthrw_(pthread_getunique_np)
102#endif
103
104__gthrw(pthread_mutex_destroy)
105__gthrw(pthread_self)
106__gthrw(pthread_yield)
107#endif
108
109#if SUPPORTS_WEAK && GTHREAD_USE_WEAK
110
111static inline int
112__gthread_active_p (void)
113{
114  static void *const __gthread_active_ptr = (void *) &__gthrw_(pthread_create);
115  return __gthread_active_ptr != 0;
116}
117
118#else /* not SUPPORTS_WEAK */
119
120static inline int
121__gthread_active_p (void)
122{
123  return 1;
124}
125
126#endif /* SUPPORTS_WEAK */
127
128#ifdef _LIBOBJC
129
130/* Key structure for maintaining thread specific storage */
131static pthread_key_t _objc_thread_storage;
132
133/* Thread local storage for a single thread */
134static void *thread_local_storage = NULL;
135
136/* Backend initialization functions */
137
138/* Initialize the threads subsystem.  */
139static inline int
140__gthread_objc_init_thread_system (void)
141{
142  if (__gthread_active_p ())
143    /* Initialize the thread storage key.  */
144    return __gthrw_(pthread_keycreate) (&_objc_thread_storage, NULL);
145  else
146    return -1;
147}
148
149/* Close the threads subsystem.  */
150static inline int
151__gthread_objc_close_thread_system (void)
152{
153  if (__gthread_active_p ())
154    return 0;
155  else
156    return -1;
157}
158
159/* Backend thread functions */
160
161/* Create a new thread of execution.  */
162static inline objc_thread_t
163__gthread_objc_thread_detach (void (*func)(void *), void *arg)
164{
165  objc_thread_t thread_id;
166  pthread_t new_thread_handle;
167
168  if (!__gthread_active_p ())
169    return NULL;
170
171  if (!(__gthrw_(pthread_create) (&new_thread_handle, pthread_attr_default,
172			(void *) func, arg)))
173    {
174      /* ??? May not work! (64bit) */
175      thread_id = *(objc_thread_t *) &new_thread_handle;
176      pthread_detach (&new_thread_handle); /* Fully detach thread.  */
177    }
178  else
179    thread_id = NULL;
180
181  return thread_id;
182}
183
184/* Set the current thread's priority.  */
185static inline int
186__gthread_objc_thread_set_priority (int priority)
187{
188  int sys_priority = 0;
189
190  if (!__gthread_active_p ())
191    return -1;
192
193  switch (priority)
194    {
195    case OBJC_THREAD_INTERACTIVE_PRIORITY:
196      sys_priority = (PRI_FG_MIN_NP + PRI_FG_MAX_NP) / 2;
197      break;
198    default:
199    case OBJC_THREAD_BACKGROUND_PRIORITY:
200      sys_priority = (PRI_BG_MIN_NP + PRI_BG_MAX_NP) / 2;
201      break;
202    case OBJC_THREAD_LOW_PRIORITY:
203      sys_priority = (PRI_BG_MIN_NP + PRI_BG_MAX_NP) / 2;
204      break;
205    }
206
207  /* Change the priority.  */
208  if (pthread_setprio (__gthrw_(pthread_self) (), sys_priority) >= 0)
209    return 0;
210  else
211    /* Failed */
212    return -1;
213}
214
215/* Return the current thread's priority.  */
216static inline int
217__gthread_objc_thread_get_priority (void)
218{
219  int sys_priority;
220
221  if (__gthread_active_p ())
222    {
223      if ((sys_priority = pthread_getprio (__gthrw_(pthread_self) ())) >= 0)
224	{
225	  if (sys_priority >= PRI_FG_MIN_NP
226	      && sys_priority <= PRI_FG_MAX_NP)
227	    return OBJC_THREAD_INTERACTIVE_PRIORITY;
228	  if (sys_priority >= PRI_BG_MIN_NP
229	      && sys_priority <= PRI_BG_MAX_NP)
230	    return OBJC_THREAD_BACKGROUND_PRIORITY;
231	  return OBJC_THREAD_LOW_PRIORITY;
232	}
233
234      /* Failed */
235      return -1;
236    }
237  else
238    return OBJC_THREAD_INTERACTIVE_PRIORITY;
239}
240
241/* Yield our process time to another thread.  */
242static inline void
243__gthread_objc_thread_yield (void)
244{
245  if (__gthread_active_p ())
246    __gthrw_(pthread_yield) ();
247}
248
249/* Terminate the current thread.  */
250static inline int
251__gthread_objc_thread_exit (void)
252{
253  if (__gthread_active_p ())
254    /* exit the thread */
255    __gthrw_(pthread_exit) (&__objc_thread_exit_status);
256
257  /* Failed if we reached here */
258  return -1;
259}
260
261/* Returns an integer value which uniquely describes a thread.  */
262static inline objc_thread_t
263__gthread_objc_thread_id (void)
264{
265  if (__gthread_active_p ())
266    {
267      pthread_t self = __gthrw_(pthread_self) ();
268
269      return (objc_thread_t) __gthrw_pthread_getunique_np (&self);
270    }
271  else
272    return (objc_thread_t) 1;
273}
274
275/* Sets the thread's local storage pointer.  */
276static inline int
277__gthread_objc_thread_set_data (void *value)
278{
279  if (__gthread_active_p ())
280    return __gthrw_(pthread_setspecific) (_objc_thread_storage, value);
281  else
282    {
283      thread_local_storage = value;
284      return 0;
285    }
286}
287
288/* Returns the thread's local storage pointer.  */
289static inline void *
290__gthread_objc_thread_get_data (void)
291{
292  void *value = NULL;
293
294  if (__gthread_active_p ())
295    {
296      if (!(__gthrw_(pthread_getspecific) (_objc_thread_storage, &value)))
297	return value;
298
299      return NULL;
300    }
301  else
302    return thread_local_storage;
303}
304
305/* Backend mutex functions */
306
307/* Allocate a mutex.  */
308static inline int
309__gthread_objc_mutex_allocate (objc_mutex_t mutex)
310{
311  if (__gthread_active_p ())
312    {
313      mutex->backend = objc_malloc (sizeof (pthread_mutex_t));
314
315      if (__gthrw_(pthread_mutex_init) ((pthread_mutex_t *) mutex->backend,
316			      pthread_mutexattr_default))
317	{
318	  objc_free (mutex->backend);
319	  mutex->backend = NULL;
320	  return -1;
321	}
322    }
323
324  return 0;
325}
326
327/* Deallocate a mutex.  */
328static inline int
329__gthread_objc_mutex_deallocate (objc_mutex_t mutex)
330{
331  if (__gthread_active_p ())
332    {
333      if (__gthrw_(pthread_mutex_destroy) ((pthread_mutex_t *) mutex->backend))
334	return -1;
335
336      objc_free (mutex->backend);
337      mutex->backend = NULL;
338    }
339
340  return 0;
341}
342
343/* Grab a lock on a mutex.  */
344static inline int
345__gthread_objc_mutex_lock (objc_mutex_t mutex)
346{
347  if (__gthread_active_p ())
348    return __gthrw_(pthread_mutex_lock) ((pthread_mutex_t *) mutex->backend);
349  else
350    return 0;
351}
352
353/* Try to grab a lock on a mutex.  */
354static inline int
355__gthread_objc_mutex_trylock (objc_mutex_t mutex)
356{
357  if (__gthread_active_p ()
358      && __gthrw_(pthread_mutex_trylock) ((pthread_mutex_t *) mutex->backend) != 1)
359    return -1;
360
361  return 0;
362}
363
364/* Unlock the mutex */
365static inline int
366__gthread_objc_mutex_unlock (objc_mutex_t mutex)
367{
368  if (__gthread_active_p ())
369    return __gthrw_(pthread_mutex_unlock) ((pthread_mutex_t *) mutex->backend);
370  else
371    return 0;
372}
373
374/* Backend condition mutex functions */
375
376/* Allocate a condition.  */
377static inline int
378__gthread_objc_condition_allocate (objc_condition_t condition
379				   __attribute__ ((__unused__)))
380{
381  if (__gthread_active_p ())
382    /* Unimplemented.  */
383    return -1;
384  else
385    return 0;
386}
387
388/* Deallocate a condition.  */
389static inline int
390__gthread_objc_condition_deallocate (objc_condition_t condition
391				     __attribute__ ((__unused__)))
392{
393  if (__gthread_active_p ())
394    /* Unimplemented.  */
395    return -1;
396  else
397    return 0;
398}
399
400/* Wait on the condition */
401static inline int
402__gthread_objc_condition_wait (objc_condition_t condition
403			       __attribute__ ((__unused__)),
404			       objc_mutex_t mutex __attribute__ ((__unused__)))
405{
406  if (__gthread_active_p ())
407    /* Unimplemented.  */
408    return -1;
409  else
410    return 0;
411}
412
413/* Wake up all threads waiting on this condition.  */
414static inline int
415__gthread_objc_condition_broadcast (objc_condition_t condition
416				    __attribute__ ((__unused__)))
417{
418  if (__gthread_active_p ())
419    /* Unimplemented.  */
420    return -1;
421  else
422    return 0;
423}
424
425/* Wake up one thread waiting on this condition.  */
426static inline int
427__gthread_objc_condition_signal (objc_condition_t condition
428				 __attribute__ ((__unused__)))
429{
430  if (__gthread_active_p ())
431    /* Unimplemented.  */
432    return -1;
433  else
434    return 0;
435}
436
437#else /* _LIBOBJC */
438
439static inline int
440__gthread_once (__gthread_once_t *__once, void (*__func) (void))
441{
442  if (__gthread_active_p ())
443    return __gthrw_(pthread_once) (__once, __func);
444  else
445    return -1;
446}
447
448static inline int
449__gthread_key_create (__gthread_key_t *__key, void (*__dtor) (void *))
450{
451  return __gthrw_(pthread_keycreate) (__key, __dtor);
452}
453
454static inline int
455__gthread_key_delete (__gthread_key_t __key __attribute__ ((__unused__)))
456{
457  /* Operation is not supported.  */
458  return -1;
459}
460
461static inline void *
462__gthread_getspecific (__gthread_key_t __key)
463{
464  void *__ptr;
465  if (__gthrw_(pthread_getspecific) (__key, &__ptr) == 0)
466    return __ptr;
467  else
468    return 0;
469}
470
471static inline int
472__gthread_setspecific (__gthread_key_t __key, const void *__ptr)
473{
474  return __gthrw_(pthread_setspecific)
475    (__key, CONST_CAST2(void *, const void *, __ptr));
476}
477
478static inline void
479__gthread_mutex_init_function (__gthread_mutex_t *__mutex)
480{
481  if (__gthread_active_p ())
482    __gthrw_(pthread_mutex_init) (__mutex, pthread_mutexattr_default);
483}
484
485static inline int
486__gthread_mutx_destroy (__gthread_mutex_t *__mutex)
487{
488  if (__gthread_active_p ())
489    return __gthrw_(pthread_mutex_destroy) (__mutex);
490  else
491    return 0;
492}
493
494static inline int
495__gthread_mutex_lock (__gthread_mutex_t *__mutex)
496{
497  if (__gthread_active_p ())
498    return __gthrw_(pthread_mutex_lock) (__mutex);
499  else
500    return 0;
501}
502
503static inline int
504__gthread_mutex_trylock (__gthread_mutex_t *__mutex)
505{
506  if (__gthread_active_p ())
507    return __gthrw_(pthread_mutex_trylock) (__mutex);
508  else
509    return 0;
510}
511
512static inline int
513__gthread_mutex_unlock (__gthread_mutex_t *__mutex)
514{
515  if (__gthread_active_p ())
516    return __gthrw_(pthread_mutex_unlock) (__mutex);
517  else
518    return 0;
519}
520
521static inline int
522__gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *__mutex)
523{
524  if (__gthread_active_p ())
525    {
526      pthread_mutexattr_t __attr;
527      int __r;
528
529      __r = __gthrw_(pthread_mutexattr_create) (&__attr);
530      if (!__r)
531	__r = __gthrw_(pthread_mutexattr_setkind_np) (&__attr,
532						      MUTEX_RECURSIVE_NP);
533      if (!__r)
534	__r = __gthrw_(pthread_mutex_init) (__mutex, __attr);
535      if (!__r)
536	__r = __gthrw_(pthread_mutexattr_delete) (&__attr);
537      return __r;
538    }
539  return 0;
540}
541
542static inline int
543__gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *__mutex)
544{
545  return __gthread_mutex_lock (__mutex);
546}
547
548static inline int
549__gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *__mutex)
550{
551  return __gthread_mutex_trylock (__mutex);
552}
553
554static inline int
555__gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *__mutex)
556{
557  return __gthread_mutex_unlock (__mutex);
558}
559
560#endif /* _LIBOBJC */
561
562#endif
563#endif /* ! GCC_GTHR_DCE_H */
564