* class.c (check_bitfield_decl): New function, split out from
[official-gcc.git] / boehm-gc / linux_threads.c
blob8287dce647b1413250261ef06bbe4479a9446618
1 /*
2 * Copyright (c) 1994 by Xerox Corporation. All rights reserved.
3 * Copyright (c) 1996 by Silicon Graphics. All rights reserved.
4 * Copyright (c) 1998 by Fergus Henderson. All rights reserved.
6 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
7 * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
9 * Permission is hereby granted to use or copy this program
10 * for any purpose, provided the above notices are retained on all copies.
11 * Permission to modify the code and to distribute modified code is granted,
12 * provided the above notices are retained, and a notice that the code was
13 * modified is included with the above copyright notice.
16 * Support code for LinuxThreads, the clone()-based kernel
17 * thread package for Linux which is included in libc6.
19 * This code relies on implementation details of LinuxThreads,
20 * (i.e. properties not guaranteed by the Pthread standard):
22 * - the function GC_linux_thread_top_of_stack(void)
23 * relies on the way LinuxThreads lays out thread stacks
24 * in the address space.
26 * Note that there is a lot of code duplication between linux_threads.c
27 * and irix_threads.c; any changes made here may need to be reflected
28 * there too.
31 /* #define DEBUG_THREADS 1 */
33 /* ANSI C requires that a compilation unit contains something */
34 # include "gc_priv.h"
36 # if defined(LINUX_THREADS)
38 # include <pthread.h>
39 # include <time.h>
40 # include <errno.h>
41 # include <unistd.h>
42 # include <sys/mman.h>
43 # include <sys/time.h>
44 # include <semaphore.h>
46 #undef pthread_create
47 #undef pthread_sigmask
48 #undef pthread_join
50 void GC_thr_init();
52 #if 0
53 void GC_print_sig_mask()
55 sigset_t blocked;
56 int i;
58 if (pthread_sigmask(SIG_BLOCK, NULL, &blocked) != 0)
59 ABORT("pthread_sigmask");
60 GC_printf0("Blocked: ");
61 for (i = 1; i <= MAXSIG; i++) {
62 if (sigismember(&blocked, i)) { GC_printf1("%ld ",(long) i); }
64 GC_printf0("\n");
66 #endif
68 /* We use the allocation lock to protect thread-related data structures. */
70 /* The set of all known threads. We intercept thread creation and */
71 /* joins. We never actually create detached threads. We allocate all */
72 /* new thread stacks ourselves. These allow us to maintain this */
73 /* data structure. */
74 /* Protected by GC_thr_lock. */
75 /* Some of this should be declared volatile, but that's incosnsistent */
76 /* with some library routine declarations. */
77 typedef struct GC_Thread_Rep {
78 struct GC_Thread_Rep * next; /* More recently allocated threads */
79 /* with a given pthread id come */
80 /* first. (All but the first are */
81 /* guaranteed to be dead, but we may */
82 /* not yet have registered the join.) */
83 pthread_t id;
84 word flags;
85 # define FINISHED 1 /* Thread has exited. */
86 # define DETACHED 2 /* Thread is intended to be detached. */
87 # define MAIN_THREAD 4 /* True for the original thread only. */
89 ptr_t stack_end;
90 ptr_t stack_ptr; /* Valid only when stopped. */
91 int signal;
92 void * status; /* The value returned from the thread. */
93 /* Used only to avoid premature */
94 /* reclamation of any data it might */
95 /* reference. */
96 } * GC_thread;
98 GC_thread GC_lookup_thread(pthread_t id);
101 * The only way to suspend threads given the pthread interface is to send
102 * signals. We can't use SIGSTOP directly, because we need to get the
103 * thread to save its stack pointer in the GC thread table before
104 * suspending. So we have to reserve a signal of our own for this.
105 * This means we have to intercept client calls to change the signal mask.
106 * The linuxthreads package already uses SIGUSR1 and SIGUSR2,
107 * so we need to reuse something else. I chose SIGPWR.
108 * (Perhaps SIGUNUSED would be a better choice.)
110 #define SIG_SUSPEND SIGPWR
112 #define SIG_RESTART SIGXCPU
114 sem_t GC_suspend_ack_sem;
117 GC_linux_thread_top_of_stack() relies on implementation details of
118 LinuxThreads, namely that thread stacks are allocated on 2M boundaries
119 and grow to no more than 2M.
120 To make sure that we're using LinuxThreads and not some other thread
121 package, we generate a dummy reference to `pthread_kill_other_threads_np'
122 (was `__pthread_initial_thread_bos' but that disappeared),
123 which is a symbol defined in LinuxThreads, but (hopefully) not in other
124 thread packages.
126 void (*dummy_var_to_force_linux_threads)() = pthread_kill_other_threads_np;
128 #define LINUX_THREADS_STACK_SIZE (2 * 1024 * 1024)
130 static inline ptr_t GC_linux_thread_top_of_stack(void)
132 char *sp = GC_approx_sp();
133 ptr_t tos = (ptr_t) (((unsigned long)sp | (LINUX_THREADS_STACK_SIZE - 1)) + 1);
134 #if DEBUG_THREADS
135 GC_printf1("SP = %lx\n", (unsigned long)sp);
136 GC_printf1("TOS = %lx\n", (unsigned long)tos);
137 #endif
138 return tos;
141 void GC_suspend_handler(int sig)
143 int dummy;
144 pthread_t my_thread = pthread_self();
145 GC_thread me;
146 sigset_t all_sigs;
147 sigset_t old_sigs;
148 int i;
149 sigset_t mask;
151 if (sig != SIG_SUSPEND) ABORT("Bad signal in suspend_handler");
153 #if DEBUG_THREADS
154 GC_printf1("Suspending 0x%x\n", my_thread);
155 #endif
157 me = GC_lookup_thread(my_thread);
158 /* The lookup here is safe, since I'm doing this on behalf */
159 /* of a thread which holds the allocation lock in order */
160 /* to stop the world. Thus concurrent modification of the */
161 /* data structure is impossible. */
162 me -> stack_ptr = (ptr_t)(&dummy);
163 me -> stack_end = GC_linux_thread_top_of_stack();
165 /* Tell the thread that wants to stop the world that this */
166 /* thread has been stopped. Note that sem_post() is */
167 /* the only async-signal-safe primitive in LinuxThreads. */
168 sem_post(&GC_suspend_ack_sem);
170 /* Wait until that thread tells us to restart by sending */
171 /* this thread a SIG_RESTART signal. */
172 /* SIG_RESTART should be masked at this point. Thus there */
173 /* is no race. */
174 if (sigfillset(&mask) != 0) ABORT("sigfillset() failed");
175 if (sigdelset(&mask, SIG_RESTART) != 0) ABORT("sigdelset() failed");
176 do {
177 me->signal = 0;
178 sigsuspend(&mask); /* Wait for signal */
179 } while (me->signal != SIG_RESTART);
181 #if DEBUG_THREADS
182 GC_printf1("Continuing 0x%x\n", my_thread);
183 #endif
186 void GC_restart_handler(int sig)
188 GC_thread me;
190 if (sig != SIG_RESTART) ABORT("Bad signal in suspend_handler");
192 /* Let the GC_suspend_handler() know that we got a SIG_RESTART. */
193 /* The lookup here is safe, since I'm doing this on behalf */
194 /* of a thread which holds the allocation lock in order */
195 /* to stop the world. Thus concurrent modification of the */
196 /* data structure is impossible. */
197 me = GC_lookup_thread(pthread_self());
198 me->signal = SIG_RESTART;
201 ** Note: even if we didn't do anything useful here,
202 ** it would still be necessary to have a signal handler,
203 ** rather than ignoring the signals, otherwise
204 ** the signals will not be delivered at all, and
205 ** will thus not interrupt the sigsuspend() above.
208 #if DEBUG_THREADS
209 GC_printf1("In GC_restart_handler for 0x%x\n", pthread_self());
210 #endif
213 GC_bool GC_thr_initialized = FALSE;
215 # define THREAD_TABLE_SZ 128 /* Must be power of 2 */
216 volatile GC_thread GC_threads[THREAD_TABLE_SZ];
218 /* Add a thread to GC_threads. We assume it wasn't already there. */
219 /* Caller holds allocation lock. */
220 GC_thread GC_new_thread(pthread_t id)
222 int hv = ((word)id) % THREAD_TABLE_SZ;
223 GC_thread result;
224 static struct GC_Thread_Rep first_thread;
225 static GC_bool first_thread_used = FALSE;
227 if (!first_thread_used) {
228 result = &first_thread;
229 first_thread_used = TRUE;
230 /* Dont acquire allocation lock, since we may already hold it. */
231 } else {
232 result = (struct GC_Thread_Rep *)
233 GC_generic_malloc_inner(sizeof(struct GC_Thread_Rep), NORMAL);
235 if (result == 0) return(0);
236 result -> id = id;
237 result -> next = GC_threads[hv];
238 GC_threads[hv] = result;
239 /* result -> flags = 0; */
240 return(result);
243 /* Delete a thread from GC_threads. We assume it is there. */
244 /* (The code intentionally traps if it wasn't.) */
245 /* Caller holds allocation lock. */
246 void GC_delete_thread(pthread_t id)
248 int hv = ((word)id) % THREAD_TABLE_SZ;
249 register GC_thread p = GC_threads[hv];
250 register GC_thread prev = 0;
252 while (!pthread_equal(p -> id, id)) {
253 prev = p;
254 p = p -> next;
256 if (prev == 0) {
257 GC_threads[hv] = p -> next;
258 } else {
259 prev -> next = p -> next;
263 /* If a thread has been joined, but we have not yet */
264 /* been notified, then there may be more than one thread */
265 /* in the table with the same pthread id. */
266 /* This is OK, but we need a way to delete a specific one. */
267 void GC_delete_gc_thread(pthread_t id, GC_thread gc_id)
269 int hv = ((word)id) % THREAD_TABLE_SZ;
270 register GC_thread p = GC_threads[hv];
271 register GC_thread prev = 0;
273 while (p != gc_id) {
274 prev = p;
275 p = p -> next;
277 if (prev == 0) {
278 GC_threads[hv] = p -> next;
279 } else {
280 prev -> next = p -> next;
284 /* Return a GC_thread corresponding to a given thread_t. */
285 /* Returns 0 if it's not there. */
286 /* Caller holds allocation lock or otherwise inhibits */
287 /* updates. */
288 /* If there is more than one thread with the given id we */
289 /* return the most recent one. */
290 GC_thread GC_lookup_thread(pthread_t id)
292 int hv = ((word)id) % THREAD_TABLE_SZ;
293 register GC_thread p = GC_threads[hv];
295 while (p != 0 && !pthread_equal(p -> id, id)) p = p -> next;
296 return(p);
299 /* Caller holds allocation lock. */
300 void GC_stop_world()
302 pthread_t my_thread = pthread_self();
303 register int i;
304 register GC_thread p;
305 register int n_live_threads = 0;
306 register int result;
308 for (i = 0; i < THREAD_TABLE_SZ; i++) {
309 for (p = GC_threads[i]; p != 0; p = p -> next) {
310 if (p -> id != my_thread) {
311 if (p -> flags & FINISHED) continue;
312 n_live_threads++;
313 #if DEBUG_THREADS
314 GC_printf1("Sending suspend signal to 0x%x\n", p -> id);
315 #endif
316 result = pthread_kill(p -> id, SIG_SUSPEND);
317 switch(result) {
318 case ESRCH:
319 /* Not really there anymore. Possible? */
320 n_live_threads--;
321 break;
322 case 0:
323 break;
324 default:
325 ABORT("pthread_kill failed");
330 for (i = 0; i < n_live_threads; i++) {
331 sem_wait(&GC_suspend_ack_sem);
333 #if DEBUG_THREADS
334 GC_printf1("World stopped 0x%x\n", pthread_self());
335 #endif
338 /* Caller holds allocation lock. */
339 void GC_start_world()
341 pthread_t my_thread = pthread_self();
342 register int i;
343 register GC_thread p;
344 register int n_live_threads = 0;
345 register int result;
347 # if DEBUG_THREADS
348 GC_printf0("World starting\n");
349 # endif
351 for (i = 0; i < THREAD_TABLE_SZ; i++) {
352 for (p = GC_threads[i]; p != 0; p = p -> next) {
353 if (p -> id != my_thread) {
354 if (p -> flags & FINISHED) continue;
355 n_live_threads++;
356 #if DEBUG_THREADS
357 GC_printf1("Sending restart signal to 0x%x\n", p -> id);
358 #endif
359 result = pthread_kill(p -> id, SIG_RESTART);
360 switch(result) {
361 case ESRCH:
362 /* Not really there anymore. Possible? */
363 n_live_threads--;
364 break;
365 case 0:
366 break;
367 default:
368 ABORT("pthread_kill failed");
373 #if DEBUG_THREADS
374 GC_printf0("World started\n");
375 #endif
378 /* We hold allocation lock. We assume the world is stopped. */
379 void GC_push_all_stacks()
381 register int i;
382 register GC_thread p;
383 register ptr_t sp = GC_approx_sp();
384 register ptr_t lo, hi;
385 pthread_t me = pthread_self();
387 if (!GC_thr_initialized) GC_thr_init();
388 #if DEBUG_THREADS
389 GC_printf1("Pushing stacks from thread 0x%lx\n", (unsigned long) me);
390 #endif
391 for (i = 0; i < THREAD_TABLE_SZ; i++) {
392 for (p = GC_threads[i]; p != 0; p = p -> next) {
393 if (p -> flags & FINISHED) continue;
394 if (pthread_equal(p -> id, me)) {
395 lo = GC_approx_sp();
396 } else {
397 lo = p -> stack_ptr;
399 if ((p -> flags & MAIN_THREAD) == 0) {
400 if (pthread_equal(p -> id, me)) {
401 hi = GC_linux_thread_top_of_stack();
402 } else {
403 hi = p -> stack_end;
405 } else {
406 /* The original stack. */
407 hi = GC_stackbottom;
409 #if DEBUG_THREADS
410 GC_printf3("Stack for thread 0x%lx = [%lx,%lx)\n",
411 (unsigned long) p -> id,
412 (unsigned long) lo, (unsigned long) hi);
413 #endif
414 GC_push_all_stack(lo, hi);
420 /* We hold the allocation lock. */
421 void GC_thr_init()
423 GC_thread t;
424 struct sigaction act;
426 if (GC_thr_initialized) return;
427 GC_thr_initialized = TRUE;
429 if (sem_init(&GC_suspend_ack_sem, 0, 0) != 0)
430 ABORT("sem_init failed");
432 act.sa_flags = SA_RESTART;
433 if (sigfillset(&act.sa_mask) != 0) {
434 ABORT("sigfillset() failed");
436 /* SIG_RESTART is unmasked by the handler when necessary. */
437 act.sa_handler = GC_suspend_handler;
438 if (sigaction(SIG_SUSPEND, &act, NULL) != 0) {
439 ABORT("Cannot set SIG_SUSPEND handler");
442 act.sa_handler = GC_restart_handler;
443 if (sigaction(SIG_RESTART, &act, NULL) != 0) {
444 ABORT("Cannot set SIG_SUSPEND handler");
447 /* Add the initial thread, so we can stop it. */
448 t = GC_new_thread(pthread_self());
449 t -> stack_ptr = 0;
450 t -> flags = DETACHED | MAIN_THREAD;
453 int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
455 sigset_t fudged_set;
457 if (set != NULL && (how == SIG_BLOCK || how == SIG_SETMASK)) {
458 fudged_set = *set;
459 sigdelset(&fudged_set, SIG_SUSPEND);
460 set = &fudged_set;
462 return(pthread_sigmask(how, set, oset));
465 struct start_info {
466 void *(*start_routine)(void *);
467 void *arg;
468 word flags;
469 sem_t registered; /* 1 ==> in our thread table, but */
470 /* parent hasn't yet noticed. */
474 void GC_thread_exit_proc(void *arg)
476 GC_thread me;
477 struct start_info * si = arg;
479 LOCK();
480 me = GC_lookup_thread(pthread_self());
481 if (me -> flags & DETACHED) {
482 GC_delete_thread(pthread_self());
483 } else {
484 me -> flags |= FINISHED;
486 UNLOCK();
489 int GC_pthread_join(pthread_t thread, void **retval)
491 int result;
492 GC_thread thread_gc_id;
494 LOCK();
495 thread_gc_id = GC_lookup_thread(thread);
496 /* This is guaranteed to be the intended one, since the thread id */
497 /* cant have been recycled by pthreads. */
498 UNLOCK();
499 result = pthread_join(thread, retval);
500 LOCK();
501 /* Here the pthread thread id may have been recycled. */
502 GC_delete_gc_thread(thread, thread_gc_id);
503 UNLOCK();
504 return result;
507 void * GC_start_routine(void * arg)
509 struct start_info * si = arg;
510 void * result;
511 GC_thread me;
512 pthread_t my_pthread;
513 void *(*start)(void *);
514 void *start_arg;
516 my_pthread = pthread_self();
517 LOCK();
518 me = GC_new_thread(my_pthread);
519 me -> flags = si -> flags;
520 me -> stack_ptr = 0;
521 me -> stack_end = 0;
522 UNLOCK();
523 start = si -> start_routine;
524 start_arg = si -> arg;
525 sem_post(&(si -> registered));
526 pthread_cleanup_push(GC_thread_exit_proc, si);
527 # ifdef DEBUG_THREADS
528 GC_printf1("Starting thread 0x%lx\n", pthread_self());
529 GC_printf1("pid = %ld\n", (long) getpid());
530 GC_printf1("sp = 0x%lx\n", (long) &arg);
531 GC_printf1("start_routine = 0x%lx\n", start);
532 # endif
533 result = (*start)(start_arg);
534 #if DEBUG_THREADS
535 GC_printf1("Finishing thread 0x%x\n", pthread_self());
536 #endif
537 me -> status = result;
538 me -> flags |= FINISHED;
539 pthread_cleanup_pop(1);
540 /* Cleanup acquires lock, ensuring that we can't exit */
541 /* while a collection that thinks we're alive is trying to stop */
542 /* us. */
543 return(result);
547 GC_pthread_create(pthread_t *new_thread,
548 const pthread_attr_t *attr,
549 void *(*start_routine)(void *), void *arg)
551 int result;
552 GC_thread t;
553 pthread_t my_new_thread;
554 void * stack;
555 size_t stacksize;
556 pthread_attr_t new_attr;
557 int detachstate;
558 word my_flags = 0;
559 struct start_info * si = GC_malloc(sizeof(struct start_info));
560 /* This is otherwise saved only in an area mmapped by the thread */
561 /* library, which isn't visible to the collector. */
563 if (0 == si) return(ENOMEM);
564 sem_init(&(si -> registered), 0, 0);
565 si -> start_routine = start_routine;
566 si -> arg = arg;
567 LOCK();
568 if (!GC_thr_initialized) GC_thr_init();
569 if (NULL == attr) {
570 stack = 0;
571 (void) pthread_attr_init(&new_attr);
572 } else {
573 new_attr = *attr;
575 pthread_attr_getdetachstate(&new_attr, &detachstate);
576 if (PTHREAD_CREATE_DETACHED == detachstate) my_flags |= DETACHED;
577 si -> flags = my_flags;
578 UNLOCK();
579 result = pthread_create(new_thread, &new_attr, GC_start_routine, si);
580 /* Wait until child has been added to the thread table. */
581 /* This also ensures that we hold onto si until the child is done */
582 /* with it. Thus it doesn't matter whether it is otherwise */
583 /* visible to the collector. */
584 if (0 != sem_wait(&(si -> registered))) ABORT("sem_wait failed");
585 sem_destroy(&(si -> registered));
586 /* pthread_attr_destroy(&new_attr); */
587 /* pthread_attr_destroy(&new_attr); */
588 return(result);
591 GC_bool GC_collecting = 0;
592 /* A hint that we're in the collector and */
593 /* holding the allocation lock for an */
594 /* extended period. */
596 /* Reasonably fast spin locks. Basically the same implementation */
597 /* as STL alloc.h. This isn't really the right way to do this. */
598 /* but until the POSIX scheduling mess gets straightened out ... */
600 volatile unsigned int GC_allocate_lock = 0;
603 void GC_lock()
605 # define low_spin_max 30 /* spin cycles if we suspect uniprocessor */
606 # define high_spin_max 1000 /* spin cycles for multiprocessor */
607 static unsigned spin_max = low_spin_max;
608 unsigned my_spin_max;
609 static unsigned last_spins = 0;
610 unsigned my_last_spins;
611 volatile unsigned junk;
612 # define PAUSE junk *= junk; junk *= junk; junk *= junk; junk *= junk
613 int i;
615 if (!GC_test_and_set(&GC_allocate_lock)) {
616 return;
618 junk = 0;
619 my_spin_max = spin_max;
620 my_last_spins = last_spins;
621 for (i = 0; i < my_spin_max; i++) {
622 if (GC_collecting) goto yield;
623 if (i < my_last_spins/2 || GC_allocate_lock) {
624 PAUSE;
625 continue;
627 if (!GC_test_and_set(&GC_allocate_lock)) {
629 * got it!
630 * Spinning worked. Thus we're probably not being scheduled
631 * against the other process with which we were contending.
632 * Thus it makes sense to spin longer the next time.
634 last_spins = i;
635 spin_max = high_spin_max;
636 return;
639 /* We are probably being scheduled against the other process. Sleep. */
640 spin_max = low_spin_max;
641 yield:
642 for (i = 0;; ++i) {
643 if (!GC_test_and_set(&GC_allocate_lock)) {
644 return;
646 # define SLEEP_THRESHOLD 12
647 /* nanosleep(<= 2ms) just spins under Linux. We */
648 /* want to be careful to avoid that behavior. */
649 if (i < SLEEP_THRESHOLD) {
650 sched_yield();
651 } else {
652 struct timespec ts;
654 if (i > 26) i = 26;
655 /* Don't wait for more than about 60msecs, even */
656 /* under extreme contention. */
657 ts.tv_sec = 0;
658 ts.tv_nsec = 1 << i;
659 nanosleep(&ts, 0);
664 # endif /* LINUX_THREADS */