1/* Threads compatibility routines for libgcc2 and libobjc.  */
2/* Compile this one with gcc.  */
3/* Copyright (C) 1997, 1999, 2000, 2004, 2005, 2006
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_SOLARIS_H
31#define GCC_GTHR_SOLARIS_H
32
33/* Solaris threads as found in Solaris 2.[456].
34   Actually these are Unix International (UI) threads, but I don't
35   know if anyone else implements these.  */
36
37#define __GTHREADS 1
38
39#include <thread.h>
40#include <errno.h>
41
42#ifdef __cplusplus
43#define UNUSED(x)
44#else
45#define UNUSED(x) x __attribute__((unused))
46#endif
47
48typedef thread_key_t __gthread_key_t;
49typedef struct {
50  mutex_t mutex;
51  int once;
52} __gthread_once_t;
53typedef mutex_t __gthread_mutex_t;
54
55typedef struct {
56  long depth;
57  thread_t owner;
58  mutex_t actual;
59} __gthread_recursive_mutex_t;
60
61#define __GTHREAD_ONCE_INIT { DEFAULTMUTEX, 0 }
62#define __GTHREAD_MUTEX_INIT DEFAULTMUTEX
63#define __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION __gthread_recursive_mutex_init_function
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(thr_keycreate)
75__gthrw(thr_getspecific)
76__gthrw(thr_setspecific)
77__gthrw(thr_create)
78__gthrw(thr_self)
79
80__gthrw(mutex_init)
81__gthrw(mutex_destroy)
82__gthrw(mutex_lock)
83__gthrw(mutex_trylock)
84__gthrw(mutex_unlock)
85
86#ifdef _LIBOBJC
87__gthrw(thr_exit)
88__gthrw(thr_getprio)
89__gthrw(thr_setprio)
90__gthrw(thr_yield)
91
92__gthrw(cond_init)
93__gthrw(cond_destroy)
94__gthrw(cond_wait)
95__gthrw(cond_broadcast)
96__gthrw(cond_signal)
97
98#endif
99
100#if SUPPORTS_WEAK && GTHREAD_USE_WEAK
101
102/* This will not actually work in Solaris 2.5, since libc contains
103   dummy symbols of all thr_* routines.  */
104
105static inline int
106__gthread_active_p (void)
107{
108  static void *const __gthread_active_ptr = (void *) &__gthrw_(thr_create);
109  return __gthread_active_ptr != 0;
110}
111
112#else /* not SUPPORTS_WEAK */
113
114static inline int
115__gthread_active_p (void)
116{
117  return 1;
118}
119
120#endif /* SUPPORTS_WEAK */
121
122#ifdef _LIBOBJC
123
124/* Key structure for maintaining thread specific storage */
125static thread_key_t _objc_thread_storage;
126
127/* Thread local storage for a single thread */
128static void *thread_local_storage = NULL;
129
130/* Backend initialization functions */
131
132/* Initialize the threads subsystem.  */
133static inline int
134__gthread_objc_init_thread_system (void)
135{
136  /* Initialize the thread storage key.  */
137  if (__gthread_active_p ()
138      && __gthrw_(thr_keycreate) (&_objc_thread_storage, NULL) == 0)
139    return 0;
140
141  return -1;
142}
143
144/* Close the threads subsystem.  */
145static inline int
146__gthread_objc_close_thread_system (void)
147{
148  if (__gthread_active_p ())
149    return 0;
150  else
151    return -1;
152}
153
154/* Backend thread functions */
155
156/* Create a new thread of execution.  */
157static inline objc_thread_t
158__gthread_objc_thread_detach (void (*func)(void *), void *arg)
159{
160  objc_thread_t thread_id;
161  thread_t new_thread_id = 0;
162
163  if (!__gthread_active_p ())
164    return NULL;
165
166  if (__gthrw_(thr_create) (NULL, 0, (void *) func, arg,
167		  THR_DETACHED | THR_NEW_LWP,
168		  &new_thread_id) == 0)
169    thread_id = *(objc_thread_t *) &new_thread_id;
170  else
171    thread_id = NULL;
172
173  return thread_id;
174}
175
176/* Set the current thread's priority.  */
177static inline int
178__gthread_objc_thread_set_priority (int priority)
179{
180  int sys_priority = 0;
181
182  if (!__gthread_active_p ())
183    return -1;
184
185  switch (priority)
186    {
187    case OBJC_THREAD_INTERACTIVE_PRIORITY:
188      sys_priority = 300;
189      break;
190    default:
191    case OBJC_THREAD_BACKGROUND_PRIORITY:
192      sys_priority = 200;
193      break;
194    case OBJC_THREAD_LOW_PRIORITY:
195      sys_priority = 1000;
196      break;
197    }
198
199  /* Change priority */
200  if (__gthrw_(thr_setprio) (__gthrw_(thr_self) (), sys_priority) == 0)
201    return 0;
202  else
203    return -1;
204}
205
206/* Return the current thread's priority.  */
207static inline int
208__gthread_objc_thread_get_priority (void)
209{
210  int sys_priority;
211
212  if (!__gthread_active_p ())
213    return OBJC_THREAD_INTERACTIVE_PRIORITY;
214
215  if (__gthrw_(thr_getprio) (__gthrw_(thr_self) (), &sys_priority) == 0)
216    {
217      if (sys_priority >= 250)
218	return OBJC_THREAD_INTERACTIVE_PRIORITY;
219      else if (sys_priority >= 150)
220	return OBJC_THREAD_BACKGROUND_PRIORITY;
221      return OBJC_THREAD_LOW_PRIORITY;
222    }
223
224  /* Couldn't get priority.  */
225  return -1;
226}
227
228/* Yield our process time to another thread.  */
229static inline void
230__gthread_objc_thread_yield (void)
231{
232  if (__gthread_active_p ())
233    __gthrw_(thr_yield) ();
234}
235
236/* Terminate the current thread.  */
237static inline int
238__gthread_objc_thread_exit (void)
239{
240  if (__gthread_active_p ())
241    /* exit the thread */
242    __gthrw_(thr_exit) (&__objc_thread_exit_status);
243
244  /* Failed if we reached here */
245  return -1;
246}
247
248/* Returns an integer value which uniquely describes a thread.  */
249static inline objc_thread_t
250__gthread_objc_thread_id (void)
251{
252  if (__gthread_active_p ())
253    return (objc_thread_t) __gthrw_(thr_self) ();
254  else
255    return (objc_thread_t) 1;
256}
257
258/* Sets the thread's local storage pointer.  */
259static inline int
260__gthread_objc_thread_set_data (void *value)
261{
262  if (__gthread_active_p ())
263    {
264      if (__gthrw_(thr_setspecific) (_objc_thread_storage, value) == 0)
265	return 0;
266      else
267	return -1;
268    }
269  else
270    {
271      thread_local_storage = value;
272      return 0;
273    }
274}
275
276/* Returns the thread's local storage pointer.  */
277static inline void *
278__gthread_objc_thread_get_data (void)
279{
280  void *value = NULL;
281
282  if (__gthread_active_p ())
283    {
284      if (__gthrw_(thr_getspecific) (_objc_thread_storage, &value) == 0)
285	return value;
286      else
287	return NULL;
288    }
289  else
290    return thread_local_storage;
291}
292
293/* Backend mutex functions */
294
295/* Allocate a mutex.  */
296static inline int
297__gthread_objc_mutex_allocate (objc_mutex_t mutex)
298{
299  if (__gthread_active_p ()
300      && __gthrw_(mutex_init) ((mutex_t *) (&(mutex->backend)), USYNC_THREAD, 0))
301    return -1;
302
303  return 0;
304}
305
306/* Deallocate a mutex.  */
307static inline int
308__gthread_objc_mutex_deallocate (objc_mutex_t mutex)
309{
310  if (__gthread_active_p ())
311    __gthrw_(mutex_destroy) ((mutex_t *) (&(mutex->backend)));
312
313  return 0;
314}
315
316/* Grab a lock on a mutex.  */
317static inline int
318__gthread_objc_mutex_lock (objc_mutex_t mutex)
319{
320  if (__gthread_active_p ()
321      && __gthrw_(mutex_lock) ((mutex_t *) (&(mutex->backend))) != 0)
322    return -1;
323
324  return 0;
325}
326
327/* Try to grab a lock on a mutex.  */
328static inline int
329__gthread_objc_mutex_trylock (objc_mutex_t mutex)
330{
331  if (__gthread_active_p ()
332      && __gthrw_(mutex_trylock) ((mutex_t *) (&(mutex->backend))) != 0)
333    return -1;
334
335  return 0;
336}
337
338/* Unlock the mutex */
339static inline int
340__gthread_objc_mutex_unlock (objc_mutex_t mutex)
341{
342  if (__gthread_active_p ()
343      && __gthrw_(mutex_unlock) ((mutex_t *) (&(mutex->backend))) != 0)
344    return -1;
345
346  return 0;
347}
348
349/* Backend condition mutex functions */
350
351/* Allocate a condition.  */
352static inline int
353__gthread_objc_condition_allocate (objc_condition_t condition)
354{
355  if (__gthread_active_p ())
356    return __gthrw_(cond_init) ((cond_t *) (&(condition->backend)), USYNC_THREAD,
357		      NULL);
358  else
359    return 0;
360}
361
362/* Deallocate a condition.  */
363static inline int
364__gthread_objc_condition_deallocate (objc_condition_t condition)
365{
366  if (__gthread_active_p ())
367    return __gthrw_(cond_destroy) ((cond_t *) (&(condition->backend)));
368  else
369    return 0;
370}
371
372/* Wait on the condition */
373static inline int
374__gthread_objc_condition_wait (objc_condition_t condition, objc_mutex_t mutex)
375{
376  if (__gthread_active_p ())
377    return __gthrw_(cond_wait) ((cond_t *) (&(condition->backend)),
378		      (mutex_t *) (&(mutex->backend)));
379  else
380    return 0;
381}
382
383/* Wake up all threads waiting on this condition.  */
384static inline int
385__gthread_objc_condition_broadcast (objc_condition_t condition)
386{
387  if (__gthread_active_p ())
388    return __gthrw_(cond_broadcast) ((cond_t *) (&(condition->backend)));
389  else
390    return 0;
391}
392
393/* Wake up one thread waiting on this condition.  */
394static inline int
395__gthread_objc_condition_signal (objc_condition_t condition)
396{
397  if (__gthread_active_p ())
398    return __gthrw_(cond_signal) ((cond_t *) (&(condition->backend)));
399  else
400    return 0;
401}
402
403#else /* _LIBOBJC */
404
405static inline int
406__gthread_once (__gthread_once_t *once, void (*func) (void))
407{
408  if (! __gthread_active_p ())
409    return -1;
410
411  if (once == 0 || func == 0)
412    return EINVAL;
413
414  if (once->once == 0)
415    {
416      int status = __gthrw_(mutex_lock) (&once->mutex);
417      if (status != 0)
418	return status;
419      if (once->once == 0)
420	{
421	  (*func) ();
422	  once->once++;
423	}
424      __gthrw_(mutex_unlock) (&once->mutex);
425    }
426  return 0;
427}
428
429static inline int
430__gthread_key_create (__gthread_key_t *key, void (*dtor) (void *))
431{
432  /* Solaris 2.5 contains thr_* routines no-op in libc, so test if we actually
433     got a reasonable key value, and if not, fail.  */
434  *key = (__gthread_key_t)-1;
435  if (__gthrw_(thr_keycreate) (key, dtor) != 0 || *key == (__gthread_key_t)-1)
436    return -1;
437  else
438    return 0;
439}
440
441static inline int
442__gthread_key_delete (__gthread_key_t UNUSED (key))
443{
444  /* Not possible.  */
445  return -1;
446}
447
448static inline void *
449__gthread_getspecific (__gthread_key_t key)
450{
451  void *ptr;
452  if (__gthrw_(thr_getspecific) (key, &ptr) == 0)
453    return ptr;
454  else
455    return 0;
456}
457
458static inline int
459__gthread_setspecific (__gthread_key_t key, const void *ptr)
460{
461  return __gthrw_(thr_setspecific) (key, (void *) ptr);
462}
463
464static inline int
465__gthread_mutex_lock (__gthread_mutex_t *mutex)
466{
467  if (__gthread_active_p ())
468    return __gthrw_(mutex_lock) (mutex);
469  else
470    return 0;
471}
472
473static inline int
474__gthread_mutex_trylock (__gthread_mutex_t *mutex)
475{
476  if (__gthread_active_p ())
477    return __gthrw_(mutex_trylock) (mutex);
478  else
479    return 0;
480}
481
482static inline int
483__gthread_mutex_unlock (__gthread_mutex_t *mutex)
484{
485  if (__gthread_active_p ())
486    return __gthrw_(mutex_unlock) (mutex);
487  else
488    return 0;
489}
490
491static inline int
492__gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *mutex)
493{
494  mutex->depth = 0;
495  mutex->owner = (thread_t) 0;
496  return __gthrw_(mutex_init) (&mutex->actual, USYNC_THREAD, 0);
497}
498
499static inline int
500__gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex)
501{
502  if (__gthread_active_p ())
503    {
504      thread_t me = __gthrw_(thr_self) ();
505
506      if (mutex->owner != me)
507	{
508	  __gthrw_(mutex_lock) (&mutex->actual);
509	  mutex->owner = me;
510	}
511
512      mutex->depth++;
513    }
514  return 0;
515}
516
517static inline int
518__gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex)
519{
520  if (__gthread_active_p ())
521    {
522      thread_t me = __gthrw_(thr_self) ();
523
524      if (mutex->owner != me)
525	{
526	  if (__gthrw_(mutex_trylock) (&mutex->actual))
527	    return 1;
528	  mutex->owner = me;
529	}
530
531      mutex->depth++;
532    }
533  return 0;
534}
535
536static inline int
537__gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex)
538{
539  if (__gthread_active_p ())
540    {
541      if (--mutex->depth == 0)
542	{
543	   mutex->owner = (thread_t) 0;
544	   __gthrw_(mutex_unlock) (&mutex->actual);
545	}
546    }
547  return 0;
548}
549
550#endif /* _LIBOBJC */
551
552#undef UNUSED
553
554#endif /* ! GCC_GTHR_SOLARIS_H */
555