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