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