OSDN Git Service

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