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