OSDN Git Service

Import Boehm GC version 6.6.
[pf3gnuchains/gcc-fork.git] / boehm-gc / pthread_stop_world.c
1 #include "private/pthread_support.h"
2
3 #if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \
4      && !defined(GC_WIN32_THREADS) && !defined(GC_DARWIN_THREADS)
5
6 #include <signal.h>
7 #include <semaphore.h>
8 #include <errno.h>
9 #include <unistd.h>
10 #include <sys/time.h>
11 #ifndef HPUX
12 # include <sys/select.h>
13   /* Doesn't exist on HP/UX 11.11. */
14 #endif
15
16 #if DEBUG_THREADS
17
18 #ifndef NSIG
19 # if defined(MAXSIG)
20 #  define NSIG (MAXSIG+1)
21 # elif defined(_NSIG)
22 #  define NSIG _NSIG
23 # elif defined(__SIGRTMAX)
24 #  define NSIG (__SIGRTMAX+1)
25 # else
26   --> please fix it
27 # endif
28 #endif
29
30 void GC_print_sig_mask()
31 {
32     sigset_t blocked;
33     int i;
34
35     if (pthread_sigmask(SIG_BLOCK, NULL, &blocked) != 0)
36         ABORT("pthread_sigmask");
37     GC_printf0("Blocked: ");
38     for (i = 1; i < NSIG; i++) {
39         if (sigismember(&blocked, i)) { GC_printf1("%ld ",(long) i); }
40     }
41     GC_printf0("\n");
42 }
43
44 #endif
45
46 /* Remove the signals that we want to allow in thread stopping  */
47 /* handler from a set.                                          */
48 void GC_remove_allowed_signals(sigset_t *set)
49 {
50 #   ifdef NO_SIGNALS
51       if (sigdelset(set, SIGINT) != 0
52           || sigdelset(set, SIGQUIT) != 0
53           || sigdelset(set, SIGABRT) != 0
54           || sigdelset(set, SIGTERM) != 0) {
55         ABORT("sigdelset() failed");
56       }
57 #   endif
58
59 #   ifdef MPROTECT_VDB
60       /* Handlers write to the thread structure, which is in the heap,  */
61       /* and hence can trigger a protection fault.                      */
62       if (sigdelset(set, SIGSEGV) != 0
63 #         ifdef SIGBUS
64             || sigdelset(set, SIGBUS) != 0
65 #         endif
66           ) {
67         ABORT("sigdelset() failed");
68       }
69 #   endif
70 }
71
72 static sigset_t suspend_handler_mask;
73
74 volatile sig_atomic_t GC_stop_count;
75                         /* Incremented at the beginning of GC_stop_world. */
76
77 volatile sig_atomic_t GC_world_is_stopped = FALSE;
78                         /* FALSE ==> it is safe for threads to restart, i.e. */
79                         /* they will see another suspend signal before they  */
80                         /* are expected to stop (unless they have voluntarily */
81                         /* stopped).                                         */
82
83 void GC_brief_async_signal_safe_sleep()
84 {
85     struct timeval tv;
86     tv.tv_sec = 0;
87     tv.tv_usec = 1000 * TIME_LIMIT / 2;
88     select(0, 0, 0, 0, &tv);
89 }
90
91 #ifdef GC_OSF1_THREADS
92   GC_bool GC_retry_signals = TRUE;
93 #else
94   GC_bool GC_retry_signals = FALSE;
95 #endif
96
97 /*
98  * We use signals to stop threads during GC.
99  * 
100  * Suspended threads wait in signal handler for SIG_THR_RESTART.
101  * That's more portable than semaphores or condition variables.
102  * (We do use sem_post from a signal handler, but that should be portable.)
103  *
104  * The thread suspension signal SIG_SUSPEND is now defined in gc_priv.h.
105  * Note that we can't just stop a thread; we need it to save its stack
106  * pointer(s) and acknowledge.
107  */
108
109 #ifndef SIG_THR_RESTART
110 #  if defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS)
111 #    ifdef _SIGRTMIN
112 #      define SIG_THR_RESTART _SIGRTMIN + 5
113 #    else
114 #      define SIG_THR_RESTART SIGRTMIN + 5
115 #    endif
116 #  else
117 #   define SIG_THR_RESTART SIGXCPU
118 #  endif
119 #endif
120
121 sem_t GC_suspend_ack_sem;
122
123 void GC_suspend_handler_inner(ptr_t sig_arg);
124
125 #if defined(IA64) || defined(HP_PA)
126 extern void GC_with_callee_saves_pushed();
127
128 void GC_suspend_handler(int sig)
129 {
130   int old_errno = errno;
131   GC_with_callee_saves_pushed(GC_suspend_handler_inner, (ptr_t)(word)sig);
132   errno = old_errno;
133 }
134
135 #else
136 /* We believe that in all other cases the full context is already       */
137 /* in the signal handler frame.                                         */
138 void GC_suspend_handler(int sig)
139 {
140   int old_errno = errno;
141   GC_suspend_handler_inner((ptr_t)(word)sig);
142   errno = old_errno;
143 }
144 #endif
145
146 void GC_suspend_handler_inner(ptr_t sig_arg)
147 {
148     int sig = (int)(word)sig_arg;
149     int dummy;
150     pthread_t my_thread = pthread_self();
151     GC_thread me;
152 #   ifdef PARALLEL_MARK
153         word my_mark_no = GC_mark_no;
154         /* Marker can't proceed until we acknowledge.  Thus this is     */
155         /* guaranteed to be the mark_no correspending to our            */
156         /* suspension, i.e. the marker can't have incremented it yet.   */
157 #   endif
158     word my_stop_count = GC_stop_count;
159
160     if (sig != SIG_SUSPEND) ABORT("Bad signal in suspend_handler");
161
162 #if DEBUG_THREADS
163     GC_printf1("Suspending 0x%lx\n", my_thread);
164 #endif
165
166     me = GC_lookup_thread(my_thread);
167     /* The lookup here is safe, since I'm doing this on behalf  */
168     /* of a thread which holds the allocation lock in order     */
169     /* to stop the world.  Thus concurrent modification of the  */
170     /* data structure is impossible.                            */
171     if (me -> stop_info.last_stop_count == my_stop_count) {
172         /* Duplicate signal.  OK if we are retrying.    */
173         if (!GC_retry_signals) {
174             WARN("Duplicate suspend signal in thread %lx\n",
175                  pthread_self());
176         }
177         return;
178     }
179 #   ifdef SPARC
180         me -> stop_info.stack_ptr = (ptr_t)GC_save_regs_in_stack();
181 #   else
182         me -> stop_info.stack_ptr = (ptr_t)(&dummy);
183 #   endif
184 #   ifdef IA64
185         me -> backing_store_ptr = (ptr_t)GC_save_regs_in_stack();
186 #   endif
187
188     /* Tell the thread that wants to stop the world that this   */
189     /* thread has been stopped.  Note that sem_post() is        */
190     /* the only async-signal-safe primitive in LinuxThreads.    */
191     sem_post(&GC_suspend_ack_sem);
192     me -> stop_info.last_stop_count = my_stop_count;
193
194     /* Wait until that thread tells us to restart by sending    */
195     /* this thread a SIG_THR_RESTART signal.                    */
196     /* SIG_THR_RESTART should be masked at this point.  Thus there      */
197     /* is no race.                                              */
198     /* We do not continue until we receive a SIG_THR_RESTART,   */
199     /* but we do not take that as authoritative.  (We may be    */
200     /* accidentally restarted by one of the user signals we     */
201     /* don't block.)  After we receive the signal, we use a     */
202     /* primitive and expensive mechanism to wait until it's     */
203     /* really safe to proceed.  Under normal circumstances,     */
204     /* this code should not be executed.                        */
205     sigsuspend(&suspend_handler_mask);        /* Wait for signal */
206     while (GC_world_is_stopped && GC_stop_count == my_stop_count) {
207         GC_brief_async_signal_safe_sleep();
208 #       if DEBUG_THREADS
209           GC_err_printf0("Sleeping in signal handler");
210 #       endif
211     }
212     /* If the RESTART signal gets lost, we can still lose.  That should be  */
213     /* less likely than losing the SUSPEND signal, since we don't do much   */
214     /* between the sem_post and sigsuspend.                                 */
215     /* We'd need more handshaking to work around that.                      */
216     /* Simply dropping the sigsuspend call should be safe, but is unlikely  */
217     /* to be efficient.                                                     */
218
219 #if DEBUG_THREADS
220     GC_printf1("Continuing 0x%lx\n", my_thread);
221 #endif
222 }
223
224 void GC_restart_handler(int sig)
225 {
226     pthread_t my_thread = pthread_self();
227
228     if (sig != SIG_THR_RESTART) ABORT("Bad signal in suspend_handler");
229
230     /*
231     ** Note: even if we don't do anything useful here,
232     ** it would still be necessary to have a signal handler,
233     ** rather than ignoring the signals, otherwise
234     ** the signals will not be delivered at all, and
235     ** will thus not interrupt the sigsuspend() above.
236     */
237
238 #if DEBUG_THREADS
239     GC_printf1("In GC_restart_handler for 0x%lx\n", pthread_self());
240 #endif
241 }
242
243 # ifdef IA64
244 #   define IF_IA64(x) x
245 # else
246 #   define IF_IA64(x)
247 # endif
248 /* We hold allocation lock.  Should do exactly the right thing if the   */
249 /* world is stopped.  Should not fail if it isn't.                      */
250 void GC_push_all_stacks()
251 {
252     GC_bool found_me = FALSE;
253     int i;
254     GC_thread p;
255     ptr_t lo, hi;
256     /* On IA64, we also need to scan the register backing store. */
257     IF_IA64(ptr_t bs_lo; ptr_t bs_hi;)
258     pthread_t me = pthread_self();
259     
260     if (!GC_thr_initialized) GC_thr_init();
261     #if DEBUG_THREADS
262         GC_printf1("Pushing stacks from thread 0x%lx\n", (unsigned long) me);
263     #endif
264     for (i = 0; i < THREAD_TABLE_SZ; i++) {
265       for (p = GC_threads[i]; p != 0; p = p -> next) {
266         if (p -> flags & FINISHED) continue;
267         if (pthread_equal(p -> id, me)) {
268 #           ifdef SPARC
269                 lo = (ptr_t)GC_save_regs_in_stack();
270 #           else
271                 lo = GC_approx_sp();
272 #           endif
273             found_me = TRUE;
274             IF_IA64(bs_hi = (ptr_t)GC_save_regs_in_stack();)
275         } else {
276             lo = p -> stop_info.stack_ptr;
277             IF_IA64(bs_hi = p -> backing_store_ptr;)
278         }
279         if ((p -> flags & MAIN_THREAD) == 0) {
280             hi = p -> stack_end;
281             IF_IA64(bs_lo = p -> backing_store_end);
282         } else {
283             /* The original stack. */
284             hi = GC_stackbottom;
285             IF_IA64(bs_lo = BACKING_STORE_BASE;)
286         }
287         #if DEBUG_THREADS
288             GC_printf3("Stack for thread 0x%lx = [%lx,%lx)\n",
289                 (unsigned long) p -> id,
290                 (unsigned long) lo, (unsigned long) hi);
291         #endif
292         if (0 == lo) ABORT("GC_push_all_stacks: sp not set!\n");
293 #       ifdef STACK_GROWS_UP
294           /* We got them backwards! */
295           GC_push_all_stack(hi, lo);
296 #       else
297           GC_push_all_stack(lo, hi);
298 #       endif
299 #       ifdef IA64
300 #         if DEBUG_THREADS
301             GC_printf3("Reg stack for thread 0x%lx = [%lx,%lx)\n",
302                 (unsigned long) p -> id,
303                 (unsigned long) bs_lo, (unsigned long) bs_hi);
304 #         endif
305           if (pthread_equal(p -> id, me)) {
306             GC_push_all_eager(bs_lo, bs_hi);
307           } else {
308             GC_push_all_stack(bs_lo, bs_hi);
309           }
310 #       endif
311       }
312     }
313     if (!found_me && !GC_in_thread_creation)
314       ABORT("Collecting from unknown thread.");
315 }
316
317 /* There seems to be a very rare thread stopping problem.  To help us  */
318 /* debug that, we save the ids of the stopping thread. */
319 pthread_t GC_stopping_thread;
320 int GC_stopping_pid;
321
322 /* We hold the allocation lock.  Suspend all threads that might */
323 /* still be running.  Return the number of suspend signals that */
324 /* were sent. */
325 int GC_suspend_all()
326 {
327     int n_live_threads = 0;
328     int i;
329     GC_thread p;
330     int result;
331     pthread_t my_thread = pthread_self();
332     
333     GC_stopping_thread = my_thread;    /* debugging only.      */
334     GC_stopping_pid = getpid();                /* debugging only.      */
335     for (i = 0; i < THREAD_TABLE_SZ; i++) {
336       for (p = GC_threads[i]; p != 0; p = p -> next) {
337         if (p -> id != my_thread) {
338             if (p -> flags & FINISHED) continue;
339             if (p -> stop_info.last_stop_count == GC_stop_count) continue;
340             if (p -> thread_blocked) /* Will wait */ continue;
341             n_live_threads++;
342             #if DEBUG_THREADS
343               GC_printf1("Sending suspend signal to 0x%lx\n", p -> id);
344             #endif
345         
346         result = pthread_kill(p -> id, SIG_SUSPEND);
347             switch(result) {
348                 case ESRCH:
349                     /* Not really there anymore.  Possible? */
350                     n_live_threads--;
351                     break;
352                 case 0:
353                     break;
354                 default:
355                     ABORT("pthread_kill failed");
356             }
357         }
358       }
359     }
360     return n_live_threads;
361 }
362
363 /* Caller holds allocation lock.        */
364 void GC_stop_world()
365 {
366     int i;
367     int n_live_threads;
368     int code;
369
370     #if DEBUG_THREADS
371     GC_printf1("Stopping the world from 0x%lx\n", pthread_self());
372     #endif
373        
374     /* Make sure all free list construction has stopped before we start. */
375     /* No new construction can start, since free list construction is   */
376     /* required to acquire and release the GC lock before it starts,    */
377     /* and we have the lock.                                            */
378 #   ifdef PARALLEL_MARK
379       GC_acquire_mark_lock();
380       GC_ASSERT(GC_fl_builder_count == 0);
381       /* We should have previously waited for it to become zero. */
382 #   endif /* PARALLEL_MARK */
383     ++GC_stop_count;
384     GC_world_is_stopped = TRUE;
385     n_live_threads = GC_suspend_all();
386
387       if (GC_retry_signals) {
388           unsigned long wait_usecs = 0;  /* Total wait since retry.     */
389 #         define WAIT_UNIT 3000
390 #         define RETRY_INTERVAL 100000
391           for (;;) {
392               int ack_count;
393
394               sem_getvalue(&GC_suspend_ack_sem, &ack_count);
395               if (ack_count == n_live_threads) break;
396               if (wait_usecs > RETRY_INTERVAL) {
397                   int newly_sent = GC_suspend_all();
398
399 #                 ifdef CONDPRINT
400                     if (GC_print_stats) {
401                       GC_printf1("Resent %ld signals after timeout\n",
402                                  newly_sent);
403                     }
404 #                 endif
405                   sem_getvalue(&GC_suspend_ack_sem, &ack_count);
406                   if (newly_sent < n_live_threads - ack_count) {
407                       WARN("Lost some threads during GC_stop_world?!\n",0);
408                       n_live_threads = ack_count + newly_sent;
409                   }
410                   wait_usecs = 0;
411               }
412               usleep(WAIT_UNIT);
413               wait_usecs += WAIT_UNIT;
414           }
415       }
416     for (i = 0; i < n_live_threads; i++) {
417           while (0 != (code = sem_wait(&GC_suspend_ack_sem))) {
418               if (errno != EINTR) {
419                  GC_err_printf1("Sem_wait returned %ld\n", (unsigned long)code);
420                  ABORT("sem_wait for handler failed");
421               }
422           }
423     }
424 #   ifdef PARALLEL_MARK
425       GC_release_mark_lock();
426 #   endif
427     #if DEBUG_THREADS
428       GC_printf1("World stopped from 0x%lx\n", pthread_self());
429     #endif
430     GC_stopping_thread = 0;  /* debugging only */
431 }
432
433 /* Caller holds allocation lock, and has held it continuously since     */
434 /* the world stopped.                                                   */
435 void GC_start_world()
436 {
437     pthread_t my_thread = pthread_self();
438     register int i;
439     register GC_thread p;
440     register int n_live_threads = 0;
441     register int result;
442
443 #   if DEBUG_THREADS
444       GC_printf0("World starting\n");
445 #   endif
446
447     GC_world_is_stopped = FALSE;
448     for (i = 0; i < THREAD_TABLE_SZ; i++) {
449       for (p = GC_threads[i]; p != 0; p = p -> next) {
450         if (p -> id != my_thread) {
451             if (p -> flags & FINISHED) continue;
452             if (p -> thread_blocked) continue;
453             n_live_threads++;
454             #if DEBUG_THREADS
455               GC_printf1("Sending restart signal to 0x%lx\n", p -> id);
456             #endif
457             result = pthread_kill(p -> id, SIG_THR_RESTART);
458             switch(result) {
459                 case ESRCH:
460                     /* Not really there anymore.  Possible? */
461                     n_live_threads--;
462                     break;
463                 case 0:
464                     break;
465                 default:
466                     ABORT("pthread_kill failed");
467             }
468         }
469       }
470     }
471     #if DEBUG_THREADS
472       GC_printf0("World started\n");
473     #endif
474 }
475
476 void GC_stop_init() {
477     struct sigaction act;
478     
479     if (sem_init(&GC_suspend_ack_sem, 0, 0) != 0)
480         ABORT("sem_init failed");
481
482     act.sa_flags = SA_RESTART;
483     if (sigfillset(&act.sa_mask) != 0) {
484         ABORT("sigfillset() failed");
485     }
486     GC_remove_allowed_signals(&act.sa_mask);
487     /* SIG_THR_RESTART is set in the resulting mask.            */
488     /* It is unmasked by the handler when necessary.            */
489     act.sa_handler = GC_suspend_handler;
490     if (sigaction(SIG_SUSPEND, &act, NULL) != 0) {
491         ABORT("Cannot set SIG_SUSPEND handler");
492     }
493
494     act.sa_handler = GC_restart_handler;
495     if (sigaction(SIG_THR_RESTART, &act, NULL) != 0) {
496         ABORT("Cannot set SIG_THR_RESTART handler");
497     }
498
499     /* Inititialize suspend_handler_mask. It excludes SIG_THR_RESTART. */
500       if (sigfillset(&suspend_handler_mask) != 0) ABORT("sigfillset() failed");
501       GC_remove_allowed_signals(&suspend_handler_mask);
502       if (sigdelset(&suspend_handler_mask, SIG_THR_RESTART) != 0)
503           ABORT("sigdelset() failed");
504
505     /* Check for GC_RETRY_SIGNALS.      */
506       if (0 != GETENV("GC_RETRY_SIGNALS")) {
507           GC_retry_signals = TRUE;
508       }
509       if (0 != GETENV("GC_NO_RETRY_SIGNALS")) {
510           GC_retry_signals = FALSE;
511       }
512 #     ifdef CONDPRINT
513           if (GC_print_stats && GC_retry_signals) {
514               GC_printf0("Will retry suspend signal if necessary.\n");
515           }
516 #     endif
517 }
518
519 #endif