Merge from vendor branch GCC:
[dragonfly.git] / contrib / gcc-3.4 / gcc / gthr-solaris.h
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
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING.  If not, write to the Free
19 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20 02111-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
41 typedef thread_key_t __gthread_key_t;
42 typedef struct {
43   mutex_t mutex;
44   int once;
45 } __gthread_once_t;
46 typedef 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
83 static 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
92 static 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 */
103 static thread_key_t _objc_thread_storage;
104
105 /* Thread local storage for a single thread */
106 static void *thread_local_storage = NULL;
107
108 /* Backend initialization functions */
109
110 /* Initialize the threads subsystem.  */
111 static 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.  */
123 static 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.  */
135 static 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.  */
155 static 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.  */
185 static 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.  */
207 static inline void
208 __gthread_objc_thread_yield (void)
209 {
210   if (__gthread_active_p ())
211     thr_yield ();
212 }
213
214 /* Terminate the current thread.  */
215 static 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.  */
227 static 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.  */
237 static 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.  */
255 static 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.  */
274 static 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.  */
285 static 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.  */
295 static 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.  */
306 static 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 */
317 static 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.  */
330 static 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.  */
341 static 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 */
351 static 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.  */
362 static 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.  */
372 static 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
383 static 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
407 static 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
419 static inline int
420 __gthread_key_delete (__gthread_key_t key)
421 {
422   /* Not possible.  */
423   return -1;
424 }
425
426 static inline void *
427 __gthread_getspecific (__gthread_key_t key)
428 {
429   void *ptr;
430   if (thr_getspecific (key, &ptr) == 0)
431     return ptr;
432   else
433     return 0;
434 }
435
436 static inline int
437 __gthread_setspecific (__gthread_key_t key, const void *ptr)
438 {
439   return thr_setspecific (key, (void *) ptr);
440 }
441
442 static inline int
443 __gthread_mutex_lock (__gthread_mutex_t *mutex)
444 {
445   if (__gthread_active_p ())
446     return mutex_lock (mutex);
447   else
448     return 0;
449 }
450
451 static inline int
452 __gthread_mutex_trylock (__gthread_mutex_t *mutex)
453 {
454   if (__gthread_active_p ())
455     return mutex_trylock (mutex);
456   else
457     return 0;
458 }
459
460 static inline int
461 __gthread_mutex_unlock (__gthread_mutex_t *mutex)
462 {
463   if (__gthread_active_p ())
464     return mutex_unlock (mutex);
465   else
466     return 0;
467 }
468
469 #endif /* _LIBOBJC */
470
471 #endif /* ! GCC_GTHR_SOLARIS_H */