OSDN Git Service

2008-01-15 Sebastian Pop <sebastian.pop@amd.com>
[pf3gnuchains/gcc-fork.git] / gcc / gthr-posix95.h
1 /* Threads compatibility routines for libgcc2 and libobjc.  */
2 /* Compile this one with gcc.  */
3 /* Copyright (C) 2004, 2005, 2007 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, 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301, 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_POSIX_H
30 #define GCC_GTHR_POSIX_H
31
32 /* POSIX threads specific definitions.
33    Easy, since the interface is just one-to-one mapping.  */
34
35 #define __GTHREADS 1
36
37 /* Some implementations of <pthread.h> require this to be defined.  */
38 #ifndef _REENTRANT
39 #define _REENTRANT 1
40 #endif
41
42 #include <pthread.h>
43 #include <unistd.h>
44
45 typedef pthread_key_t __gthread_key_t;
46 typedef pthread_once_t __gthread_once_t;
47 typedef pthread_mutex_t __gthread_mutex_t;
48 typedef pthread_cond_t __gthread_cond_t;
49
50 /* POSIX like conditional variables are supported.  Please look at comments
51    in gthr.h for details. */
52 #define __GTHREAD_HAS_COND      1
53
54 typedef struct {
55   long depth;
56   pthread_t owner;
57   pthread_mutex_t actual;
58 } __gthread_recursive_mutex_t;
59
60 #define __GTHREAD_MUTEX_INIT PTHREAD_MUTEX_INITIALIZER
61 #define __GTHREAD_ONCE_INIT PTHREAD_ONCE_INIT
62 #define __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION __gthread_recursive_mutex_init_function
63 #define __GTHREAD_COND_INIT PTHREAD_COND_INITIALIZER
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(pthread_once)
75 __gthrw(pthread_key_create)
76 __gthrw(pthread_key_delete)
77 __gthrw(pthread_getspecific)
78 __gthrw(pthread_setspecific)
79 __gthrw(pthread_create)
80 __gthrw(pthread_cancel)
81 __gthrw(pthread_self)
82
83 __gthrw(pthread_mutex_lock)
84 __gthrw(pthread_mutex_trylock)
85 __gthrw(pthread_mutex_unlock)
86 __gthrw(pthread_mutexattr_init)
87 __gthrw(pthread_mutexattr_destroy)
88
89 __gthrw(pthread_mutex_init)
90 __gthrw(pthread_cond_broadcast)
91 __gthrw(pthread_cond_wait)
92
93 #if defined(_LIBOBJC) || defined(_LIBOBJC_WEAK)
94 /* Objective-C.  */
95 __gthrw(pthread_cond_destroy)
96 __gthrw(pthread_cond_init)
97 __gthrw(pthread_cond_signal)
98 __gthrw(pthread_exit)
99 __gthrw(pthread_mutex_destroy)
100 #ifdef _POSIX_PRIORITY_SCHEDULING
101 #ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
102 __gthrw(sched_get_priority_max)
103 __gthrw(sched_get_priority_min)
104 #endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
105 #endif /* _POSIX_PRIORITY_SCHEDULING */
106 __gthrw(sched_yield)
107 __gthrw(pthread_attr_destroy)
108 __gthrw(pthread_attr_init)
109 __gthrw(pthread_attr_setdetachstate)
110 #ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
111 __gthrw(pthread_getschedparam)
112 __gthrw(pthread_setschedparam)
113 #endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
114 #endif /* _LIBOBJC || _LIBOBJC_WEAK */
115
116 #if SUPPORTS_WEAK && GTHREAD_USE_WEAK
117
118 /* On Solaris 2.6 up to 9, the libc exposes a POSIX threads interface even if
119    -pthreads is not specified.  The functions are dummies and most return an
120    error value.  However pthread_once returns 0 without invoking the routine
121    it is passed so we cannot pretend that the interface is active if -pthreads
122    is not specified.  On Solaris 2.5.1, the interface is not exposed at all so
123    we need to play the usual game with weak symbols.  On Solaris 10 and up, a
124    working interface is always exposed.  */
125
126 #if defined(__sun) && defined(__svr4__)
127
128 static volatile int __gthread_active = -1;
129
130 static void
131 __gthread_trigger (void)
132 {
133   __gthread_active = 1;
134 }
135
136 static inline int
137 __gthread_active_p (void)
138 {
139   static pthread_mutex_t __gthread_active_mutex = PTHREAD_MUTEX_INITIALIZER;
140   static pthread_once_t __gthread_active_once = PTHREAD_ONCE_INIT;
141
142   /* Avoid reading __gthread_active twice on the main code path.  */
143   int __gthread_active_latest_value = __gthread_active;
144
145   /* This test is not protected to avoid taking a lock on the main code
146      path so every update of __gthread_active in a threaded program must
147      be atomic with regard to the result of the test.  */
148   if (__builtin_expect (__gthread_active_latest_value < 0, 0))
149     {
150       if (__gthrw_(pthread_once))
151         {
152           /* If this really is a threaded program, then we must ensure that
153              __gthread_active has been set to 1 before exiting this block.  */
154           __gthrw_(pthread_mutex_lock) (&__gthread_active_mutex);
155           __gthrw_(pthread_once) (&__gthread_active_once, __gthread_trigger);
156           __gthrw_(pthread_mutex_unlock) (&__gthread_active_mutex);
157         }
158
159       /* Make sure we'll never enter this block again.  */
160       if (__gthread_active < 0)
161         __gthread_active = 0;
162
163       __gthread_active_latest_value = __gthread_active;
164     }
165
166   return __gthread_active_latest_value != 0;
167 }
168
169 #else /* not Solaris */
170
171 static inline int
172 __gthread_active_p (void)
173 {
174   static void *const __gthread_active_ptr 
175     = __extension__ (void *) &__gthrw_(pthread_cancel);
176   return __gthread_active_ptr != 0;
177 }
178
179 #endif /* Solaris */
180
181 #else /* not SUPPORTS_WEAK */
182
183 /* Similar to Solaris, HP-UX 11 for PA-RISC provides stubs for pthread
184    calls in shared flavors of the HP-UX C library.  Most of the stubs
185    have no functionality.  The details are described in the "libc cumulative
186    patch" for each subversion of HP-UX 11.  There are two special interfaces
187    provided for checking whether an application is linked to a pthread
188    library or not.  However, these interfaces aren't available in early
189    libc versions.  We also can't use pthread_once as some libc versions
190    call the init function.  So, we use pthread_create to check whether it
191    is possible to create a thread or not.  The stub implementation returns
192    the error number ENOSYS.  */
193
194 #if defined(__hppa__) && defined(__hpux__)
195
196 #include <errno.h>
197
198 static volatile int __gthread_active = -1;
199
200 static void *
201 __gthread_start (void *arg __attribute__((unused)))
202 {
203   return NULL;
204 }
205
206 static void __gthread_active_init (void) __attribute__((noinline));
207 static void
208 __gthread_active_init (void)
209 {
210   static pthread_mutex_t __gthread_active_mutex = PTHREAD_MUTEX_INITIALIZER;
211   pthread_t t;
212   pthread_attr_t a;
213   int result;
214
215   __gthrw_(pthread_mutex_lock) (&__gthread_active_mutex);
216   if (__gthread_active < 0)
217     {
218       __gthrw_(pthread_attr_init) (&a);
219       __gthrw_(pthread_attr_setdetachstate) (&a, PTHREAD_CREATE_DETACHED);
220       result = __gthrw_(pthread_create) (&t, &a, __gthread_start, NULL);
221       if (result != ENOSYS)
222         __gthread_active = 1;
223       else
224         __gthread_active = 0;
225       __gthrw_(pthread_attr_destroy) (&a);
226     }
227   __gthrw_(pthread_mutex_unlock) (&__gthread_active_mutex);
228 }
229
230 static inline int
231 __gthread_active_p (void)
232 {
233   /* Avoid reading __gthread_active twice on the main code path.  */
234   int __gthread_active_latest_value = __gthread_active;
235
236   /* This test is not protected to avoid taking a lock on the main code
237      path so every update of __gthread_active in a threaded program must
238      be atomic with regard to the result of the test.  */
239   if (__builtin_expect (__gthread_active_latest_value < 0, 0))
240     {
241       __gthread_active_init ();
242       __gthread_active_latest_value = __gthread_active;
243     }
244
245   return __gthread_active_latest_value != 0;
246 }
247
248 #else /* not hppa-hpux */
249
250 static inline int
251 __gthread_active_p (void)
252 {
253   return 1;
254 }
255
256 #endif /* hppa-hpux */
257
258 #endif /* SUPPORTS_WEAK */
259
260 #ifdef _LIBOBJC
261
262 /* This is the config.h file in libobjc/ */
263 #include <config.h>
264
265 #ifdef HAVE_SCHED_H
266 # include <sched.h>
267 #endif
268
269 /* Key structure for maintaining thread specific storage */
270 static pthread_key_t _objc_thread_storage;
271 static pthread_attr_t _objc_thread_attribs;
272
273 /* Thread local storage for a single thread */
274 static void *thread_local_storage = NULL;
275
276 /* Backend initialization functions */
277
278 /* Initialize the threads subsystem.  */
279 static inline int
280 __gthread_objc_init_thread_system (void)
281 {
282   if (__gthread_active_p ())
283     {
284       /* Initialize the thread storage key.  */
285       if (__gthrw_(pthread_key_create) (&_objc_thread_storage, NULL) == 0)
286         {
287           /* The normal default detach state for threads is
288            * PTHREAD_CREATE_JOINABLE which causes threads to not die
289            * when you think they should.  */
290           if (__gthrw_(pthread_attr_init) (&_objc_thread_attribs) == 0
291               && __gthrw_(pthread_attr_setdetachstate) (&_objc_thread_attribs,
292                                               PTHREAD_CREATE_DETACHED) == 0)
293             return 0;
294         }
295     }
296
297   return -1;
298 }
299
300 /* Close the threads subsystem.  */
301 static inline int
302 __gthread_objc_close_thread_system (void)
303 {
304   if (__gthread_active_p ()
305       && __gthrw_(pthread_key_delete) (_objc_thread_storage) == 0
306       && __gthrw_(pthread_attr_destroy) (&_objc_thread_attribs) == 0)
307     return 0;
308
309   return -1;
310 }
311
312 /* Backend thread functions */
313
314 /* Create a new thread of execution.  */
315 static inline objc_thread_t
316 __gthread_objc_thread_detach (void (*func)(void *), void *arg)
317 {
318   objc_thread_t thread_id;
319   pthread_t new_thread_handle;
320
321   if (!__gthread_active_p ())
322     return NULL;
323
324   if (!(__gthrw_(pthread_create) (&new_thread_handle, NULL, (void *) func, arg)))
325     thread_id = (objc_thread_t) new_thread_handle;
326   else
327     thread_id = NULL;
328
329   return thread_id;
330 }
331
332 /* Set the current thread's priority.  */
333 static inline int
334 __gthread_objc_thread_set_priority (int priority)
335 {
336   if (!__gthread_active_p ())
337     return -1;
338   else
339     {
340 #ifdef _POSIX_PRIORITY_SCHEDULING
341 #ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
342       pthread_t thread_id = __gthrw_(pthread_self) ();
343       int policy;
344       struct sched_param params;
345       int priority_min, priority_max;
346
347       if (__gthrw_(pthread_getschedparam) (thread_id, &policy, &params) == 0)
348         {
349           if ((priority_max = __gthrw_(sched_get_priority_max) (policy)) == -1)
350             return -1;
351
352           if ((priority_min = __gthrw_(sched_get_priority_min) (policy)) == -1)
353             return -1;
354
355           if (priority > priority_max)
356             priority = priority_max;
357           else if (priority < priority_min)
358             priority = priority_min;
359           params.sched_priority = priority;
360
361           /*
362            * The solaris 7 and several other man pages incorrectly state that
363            * this should be a pointer to policy but pthread.h is universally
364            * at odds with this.
365            */
366           if (__gthrw_(pthread_setschedparam) (thread_id, policy, &params) == 0)
367             return 0;
368         }
369 #endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
370 #endif /* _POSIX_PRIORITY_SCHEDULING */
371       return -1;
372     }
373 }
374
375 /* Return the current thread's priority.  */
376 static inline int
377 __gthread_objc_thread_get_priority (void)
378 {
379 #ifdef _POSIX_PRIORITY_SCHEDULING
380 #ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
381   if (__gthread_active_p ())
382     {
383       int policy;
384       struct sched_param params;
385
386       if (__gthrw_(pthread_getschedparam) (__gthrw_(pthread_self) (), &policy, &params) == 0)
387         return params.sched_priority;
388       else
389         return -1;
390     }
391   else
392 #endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
393 #endif /* _POSIX_PRIORITY_SCHEDULING */
394     return OBJC_THREAD_INTERACTIVE_PRIORITY;
395 }
396
397 /* Yield our process time to another thread.  */
398 static inline void
399 __gthread_objc_thread_yield (void)
400 {
401   if (__gthread_active_p ())
402     __gthrw_(sched_yield) ();
403 }
404
405 /* Terminate the current thread.  */
406 static inline int
407 __gthread_objc_thread_exit (void)
408 {
409   if (__gthread_active_p ())
410     /* exit the thread */
411     __gthrw_(pthread_exit) (&__objc_thread_exit_status);
412
413   /* Failed if we reached here */
414   return -1;
415 }
416
417 /* Returns an integer value which uniquely describes a thread.  */
418 static inline objc_thread_t
419 __gthread_objc_thread_id (void)
420 {
421   if (__gthread_active_p ())
422     return (objc_thread_t) __gthrw_(pthread_self) ();
423   else
424     return (objc_thread_t) 1;
425 }
426
427 /* Sets the thread's local storage pointer.  */
428 static inline int
429 __gthread_objc_thread_set_data (void *value)
430 {
431   if (__gthread_active_p ())
432     return __gthrw_(pthread_setspecific) (_objc_thread_storage, value);
433   else
434     {
435       thread_local_storage = value;
436       return 0;
437     }
438 }
439
440 /* Returns the thread's local storage pointer.  */
441 static inline void *
442 __gthread_objc_thread_get_data (void)
443 {
444   if (__gthread_active_p ())
445     return __gthrw_(pthread_getspecific) (_objc_thread_storage);
446   else
447     return thread_local_storage;
448 }
449
450 /* Backend mutex functions */
451
452 /* Allocate a mutex.  */
453 static inline int
454 __gthread_objc_mutex_allocate (objc_mutex_t mutex)
455 {
456   if (__gthread_active_p ())
457     {
458       mutex->backend = objc_malloc (sizeof (pthread_mutex_t));
459
460       if (__gthrw_(pthread_mutex_init) ((pthread_mutex_t *) mutex->backend, NULL))
461         {
462           objc_free (mutex->backend);
463           mutex->backend = NULL;
464           return -1;
465         }
466     }
467
468   return 0;
469 }
470
471 /* Deallocate a mutex.  */
472 static inline int
473 __gthread_objc_mutex_deallocate (objc_mutex_t mutex)
474 {
475   if (__gthread_active_p ())
476     {
477       int count;
478
479       /*
480        * Posix Threads specifically require that the thread be unlocked
481        * for __gthrw_(pthread_mutex_destroy) to work.
482        */
483
484       do
485         {
486           count = __gthrw_(pthread_mutex_unlock) ((pthread_mutex_t *) mutex->backend);
487           if (count < 0)
488             return -1;
489         }
490       while (count);
491
492       if (__gthrw_(pthread_mutex_destroy) ((pthread_mutex_t *) mutex->backend))
493         return -1;
494
495       objc_free (mutex->backend);
496       mutex->backend = NULL;
497     }
498   return 0;
499 }
500
501 /* Grab a lock on a mutex.  */
502 static inline int
503 __gthread_objc_mutex_lock (objc_mutex_t mutex)
504 {
505   if (__gthread_active_p ()
506       && __gthrw_(pthread_mutex_lock) ((pthread_mutex_t *) mutex->backend) != 0)
507     {
508       return -1;
509     }
510
511   return 0;
512 }
513
514 /* Try to grab a lock on a mutex.  */
515 static inline int
516 __gthread_objc_mutex_trylock (objc_mutex_t mutex)
517 {
518   if (__gthread_active_p ()
519       && __gthrw_(pthread_mutex_trylock) ((pthread_mutex_t *) mutex->backend) != 0)
520     {
521       return -1;
522     }
523
524   return 0;
525 }
526
527 /* Unlock the mutex */
528 static inline int
529 __gthread_objc_mutex_unlock (objc_mutex_t mutex)
530 {
531   if (__gthread_active_p ()
532       && __gthrw_(pthread_mutex_unlock) ((pthread_mutex_t *) mutex->backend) != 0)
533     {
534       return -1;
535     }
536
537   return 0;
538 }
539
540 /* Backend condition mutex functions */
541
542 /* Allocate a condition.  */
543 static inline int
544 __gthread_objc_condition_allocate (objc_condition_t condition)
545 {
546   if (__gthread_active_p ())
547     {
548       condition->backend = objc_malloc (sizeof (pthread_cond_t));
549
550       if (__gthrw_(pthread_cond_init) ((pthread_cond_t *) condition->backend, NULL))
551         {
552           objc_free (condition->backend);
553           condition->backend = NULL;
554           return -1;
555         }
556     }
557
558   return 0;
559 }
560
561 /* Deallocate a condition.  */
562 static inline int
563 __gthread_objc_condition_deallocate (objc_condition_t condition)
564 {
565   if (__gthread_active_p ())
566     {
567       if (__gthrw_(pthread_cond_destroy) ((pthread_cond_t *) condition->backend))
568         return -1;
569
570       objc_free (condition->backend);
571       condition->backend = NULL;
572     }
573   return 0;
574 }
575
576 /* Wait on the condition */
577 static inline int
578 __gthread_objc_condition_wait (objc_condition_t condition, objc_mutex_t mutex)
579 {
580   if (__gthread_active_p ())
581     return __gthrw_(pthread_cond_wait) ((pthread_cond_t *) condition->backend,
582                               (pthread_mutex_t *) mutex->backend);
583   else
584     return 0;
585 }
586
587 /* Wake up all threads waiting on this condition.  */
588 static inline int
589 __gthread_objc_condition_broadcast (objc_condition_t condition)
590 {
591   if (__gthread_active_p ())
592     return __gthrw_(pthread_cond_broadcast) ((pthread_cond_t *) condition->backend);
593   else
594     return 0;
595 }
596
597 /* Wake up one thread waiting on this condition.  */
598 static inline int
599 __gthread_objc_condition_signal (objc_condition_t condition)
600 {
601   if (__gthread_active_p ())
602     return __gthrw_(pthread_cond_signal) ((pthread_cond_t *) condition->backend);
603   else
604     return 0;
605 }
606
607 #else /* _LIBOBJC */
608
609 static inline int
610 __gthread_once (__gthread_once_t *once, void (*func) (void))
611 {
612   if (__gthread_active_p ())
613     return __gthrw_(pthread_once) (once, func);
614   else
615     return -1;
616 }
617
618 static inline int
619 __gthread_key_create (__gthread_key_t *key, void (*dtor) (void *))
620 {
621   return __gthrw_(pthread_key_create) (key, dtor);
622 }
623
624 static inline int
625 __gthread_key_delete (__gthread_key_t key)
626 {
627   return __gthrw_(pthread_key_delete) (key);
628 }
629
630 static inline void *
631 __gthread_getspecific (__gthread_key_t key)
632 {
633   return __gthrw_(pthread_getspecific) (key);
634 }
635
636 static inline int
637 __gthread_setspecific (__gthread_key_t key, const void *ptr)
638 {
639   return __gthrw_(pthread_setspecific) (key, ptr);
640 }
641
642 static inline int
643 __gthread_mutex_lock (__gthread_mutex_t *mutex)
644 {
645   if (__gthread_active_p ())
646     return __gthrw_(pthread_mutex_lock) (mutex);
647   else
648     return 0;
649 }
650
651 static inline int
652 __gthread_mutex_trylock (__gthread_mutex_t *mutex)
653 {
654   if (__gthread_active_p ())
655     return __gthrw_(pthread_mutex_trylock) (mutex);
656   else
657     return 0;
658 }
659
660 static inline int
661 __gthread_mutex_unlock (__gthread_mutex_t *mutex)
662 {
663   if (__gthread_active_p ())
664     return __gthrw_(pthread_mutex_unlock) (mutex);
665   else
666     return 0;
667 }
668
669 static inline int
670 __gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *mutex)
671 {
672   mutex->depth = 0;
673   mutex->owner = (pthread_t) 0;
674   return __gthrw_(pthread_mutex_init) (&mutex->actual, NULL);
675 }
676
677 static inline int
678 __gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex)
679 {
680   if (__gthread_active_p ())
681     {
682       pthread_t me = __gthrw_(pthread_self) ();
683
684       if (mutex->owner != me)
685         {
686           __gthrw_(pthread_mutex_lock) (&mutex->actual);
687           mutex->owner = me;
688         }
689
690       mutex->depth++;
691     }
692   return 0;
693 }
694
695 static inline int
696 __gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex)
697 {
698   if (__gthread_active_p ())
699     {
700       pthread_t me = __gthrw_(pthread_self) ();
701
702       if (mutex->owner != me)
703         {
704           if (__gthrw_(pthread_mutex_trylock) (&mutex->actual))
705             return 1;
706           mutex->owner = me;
707         }
708
709       mutex->depth++;
710     }
711   return 0;
712 }
713
714 static inline int
715 __gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex)
716 {
717   if (__gthread_active_p ())
718     {
719       if (--mutex->depth == 0)
720         {
721            mutex->owner = (pthread_t) 0;
722            __gthrw_(pthread_mutex_unlock) (&mutex->actual);
723         }
724     }
725   return 0;
726 }
727
728 static inline int
729 __gthread_cond_broadcast (__gthread_cond_t *cond)
730 {
731   return __gthrw_(pthread_cond_broadcast) (cond);
732 }
733
734 static inline int
735 __gthread_cond_wait (__gthread_cond_t *cond, __gthread_mutex_t *mutex)
736 {
737   return __gthrw_(pthread_cond_wait) (cond, mutex);
738 }
739
740 static inline int
741 __gthread_cond_wait_recursive (__gthread_cond_t *cond,
742                                __gthread_recursive_mutex_t *mutex)
743 {
744   return __gthrw_(pthread_cond_wait) (cond, mutex->actual);
745 }
746
747 #endif /* _LIBOBJC */
748
749 #endif /* ! GCC_GTHR_POSIX_H */