xref: /openbsd-src/gnu/gcc/gcc/gthr-solaris.h (revision 404b540a9034ac75a6199ad1a32d1bbc7a0d4210)
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 
6 This file is part of GCC.
7 
8 GCC is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 2, or (at your option) any later
11 version.
12 
13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16 for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING.  If not, write to the Free
20 Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
21 02110-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 
48 typedef thread_key_t __gthread_key_t;
49 typedef struct {
50   mutex_t mutex;
51   int once;
52 } __gthread_once_t;
53 typedef mutex_t __gthread_mutex_t;
54 
55 typedef 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)
__gthrw(thr_getspecific)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 
105 static 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 
114 static 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 */
125 static thread_key_t _objc_thread_storage;
126 
127 /* Thread local storage for a single thread */
128 static void *thread_local_storage = NULL;
129 
130 /* Backend initialization functions */
131 
132 /* Initialize the threads subsystem.  */
133 static inline int
__gthread_objc_init_thread_system(void)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.  */
145 static inline int
__gthread_objc_close_thread_system(void)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.  */
157 static inline objc_thread_t
__gthread_objc_thread_detach(void (* func)(void *),void * arg)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.  */
177 static inline int
__gthread_objc_thread_set_priority(int priority)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.  */
207 static inline int
__gthread_objc_thread_get_priority(void)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.  */
229 static inline void
__gthread_objc_thread_yield(void)230 __gthread_objc_thread_yield (void)
231 {
232   if (__gthread_active_p ())
233     __gthrw_(thr_yield) ();
234 }
235 
236 /* Terminate the current thread.  */
237 static inline int
__gthread_objc_thread_exit(void)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.  */
249 static inline objc_thread_t
__gthread_objc_thread_id(void)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.  */
259 static inline int
__gthread_objc_thread_set_data(void * value)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.  */
277 static inline void *
__gthread_objc_thread_get_data(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.  */
296 static inline int
__gthread_objc_mutex_allocate(objc_mutex_t mutex)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.  */
307 static inline int
__gthread_objc_mutex_deallocate(objc_mutex_t mutex)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.  */
317 static inline int
__gthread_objc_mutex_lock(objc_mutex_t mutex)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.  */
328 static inline int
__gthread_objc_mutex_trylock(objc_mutex_t mutex)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 */
339 static inline int
__gthread_objc_mutex_unlock(objc_mutex_t mutex)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.  */
352 static inline int
__gthread_objc_condition_allocate(objc_condition_t condition)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.  */
363 static inline int
__gthread_objc_condition_deallocate(objc_condition_t condition)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 */
373 static inline int
__gthread_objc_condition_wait(objc_condition_t condition,objc_mutex_t mutex)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.  */
384 static inline int
__gthread_objc_condition_broadcast(objc_condition_t condition)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.  */
394 static inline int
__gthread_objc_condition_signal(objc_condition_t condition)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 
405 static inline int
__gthread_once(__gthread_once_t * once,void (* func)(void))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 
429 static inline int
__gthread_key_create(__gthread_key_t * key,void (* dtor)(void *))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 
441 static inline int
__gthread_key_delete(__gthread_key_t UNUSED (key))442 __gthread_key_delete (__gthread_key_t UNUSED (key))
443 {
444   /* Not possible.  */
445   return -1;
446 }
447 
448 static inline void *
__gthread_getspecific(__gthread_key_t key)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 
458 static inline int
__gthread_setspecific(__gthread_key_t key,const void * ptr)459 __gthread_setspecific (__gthread_key_t key, const void *ptr)
460 {
461   return __gthrw_(thr_setspecific) (key, (void *) ptr);
462 }
463 
464 static inline int
__gthread_mutex_lock(__gthread_mutex_t * mutex)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 
473 static inline int
__gthread_mutex_trylock(__gthread_mutex_t * mutex)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 
482 static inline int
__gthread_mutex_unlock(__gthread_mutex_t * mutex)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 
491 static inline int
__gthread_recursive_mutex_init_function(__gthread_recursive_mutex_t * mutex)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 
499 static inline int
__gthread_recursive_mutex_lock(__gthread_recursive_mutex_t * mutex)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 
517 static inline int
__gthread_recursive_mutex_trylock(__gthread_recursive_mutex_t * mutex)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 
536 static inline int
__gthread_recursive_mutex_unlock(__gthread_recursive_mutex_t * mutex)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