67
72
static sigset_t suspend_handler_mask;
69
word GC_stop_count; /* Incremented at the beginning of GC_stop_world. */
74
volatile sig_atomic_t GC_stop_count;
75
/* Incremented at the beginning of GC_stop_world. */
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 */
83
void GC_brief_async_signal_safe_sleep()
87
tv.tv_usec = 1000 * TIME_LIMIT / 2;
88
select(0, 0, 0, 0, &tv);
71
91
#ifdef GC_OSF1_THREADS
72
92
GC_bool GC_retry_signals = TRUE;
101
121
sem_t GC_suspend_ack_sem;
123
#ifdef GC_NETBSD_THREADS
124
# define GC_NETBSD_THREADS_WORKAROUND
125
/* It seems to be necessary to wait until threads have restarted. */
126
/* But it is unclear why that is the case. */
127
sem_t GC_restart_ack_sem;
103
130
void GC_suspend_handler_inner(ptr_t sig_arg);
105
132
#if defined(IA64) || defined(HP_PA)
175
202
/* this thread a SIG_THR_RESTART signal. */
176
203
/* SIG_THR_RESTART should be masked at this point. Thus there */
177
204
/* is no race. */
179
me->stop_info.signal = 0;
180
sigsuspend(&suspend_handler_mask); /* Wait for signal */
181
} while (me->stop_info.signal != SIG_THR_RESTART);
205
/* We do not continue until we receive a SIG_THR_RESTART, */
206
/* but we do not take that as authoritative. (We may be */
207
/* accidentally restarted by one of the user signals we */
208
/* don't block.) After we receive the signal, we use a */
209
/* primitive and expensive mechanism to wait until it's */
210
/* really safe to proceed. Under normal circumstances, */
211
/* this code should not be executed. */
212
sigsuspend(&suspend_handler_mask); /* Wait for signal */
213
while (GC_world_is_stopped && GC_stop_count == my_stop_count) {
214
GC_brief_async_signal_safe_sleep();
216
GC_err_printf0("Sleeping in signal handler");
182
219
/* If the RESTART signal gets lost, we can still lose. That should be */
183
220
/* less likely than losing the SUSPEND signal, since we don't do much */
184
221
/* between the sem_post and sigsuspend. */
185
/* We'd need more handshaking to work around that, since we don't want */
186
/* to accidentally leave a RESTART signal pending, thus causing us to */
187
/* continue prematurely in a future round. */
222
/* We'd need more handshaking to work around that. */
223
/* Simply dropping the sigsuspend call should be safe, but is unlikely */
224
/* to be efficient. */
189
226
#if DEBUG_THREADS
190
227
GC_printf1("Continuing 0x%lx\n", my_thread);
194
231
void GC_restart_handler(int sig)
196
233
pthread_t my_thread = pthread_self();
199
235
if (sig != SIG_THR_RESTART) ABORT("Bad signal in suspend_handler");
201
/* Let the GC_suspend_handler() know that we got a SIG_THR_RESTART. */
202
/* The lookup here is safe, since I'm doing this on behalf */
203
/* of a thread which holds the allocation lock in order */
204
/* to stop the world. Thus concurrent modification of the */
205
/* data structure is impossible. */
206
me = GC_lookup_thread(my_thread);
207
me->stop_info.signal = SIG_THR_RESTART;
237
#ifdef GC_NETBSD_THREADS_WORKAROUND
238
sem_post(&GC_restart_ack_sem);
210
** Note: even if we didn't do anything useful here,
242
** Note: even if we don't do anything useful here,
211
243
** it would still be necessary to have a signal handler,
212
244
** rather than ignoring the signals, otherwise
213
245
** the signals will not be delivered at all, and
282
314
(unsigned long) bs_lo, (unsigned long) bs_hi);
284
316
if (pthread_equal(p -> id, me)) {
317
/* FIXME: This may add an unbounded number of entries, */
318
/* and hence overflow the mark stack, which is bad. */
285
319
GC_push_all_eager(bs_lo, bs_hi);
287
321
GC_push_all_stack(bs_lo, bs_hi);
417
452
register GC_thread p;
418
453
register int n_live_threads = 0;
419
454
register int result;
455
#ifdef GC_NETBSD_THREADS_WORKAROUND
421
459
# if DEBUG_THREADS
422
460
GC_printf0("World starting\n");
463
GC_world_is_stopped = FALSE;
425
464
for (i = 0; i < THREAD_TABLE_SZ; i++) {
426
465
for (p = GC_threads[i]; p != 0; p = p -> next) {
427
466
if (p -> id != my_thread) {
431
470
#if DEBUG_THREADS
432
471
GC_printf1("Sending restart signal to 0x%lx\n", p -> id);
435
result = pthread_kill(p -> id, SIG_THR_RESTART);
473
result = pthread_kill(p -> id, SIG_THR_RESTART);
438
476
/* Not really there anymore. Possible? */
487
#ifdef GC_NETBSD_THREADS_WORKAROUND
488
for (i = 0; i < n_live_threads; i++)
489
while (0 != (code = sem_wait(&GC_restart_ack_sem)))
490
if (errno != EINTR) {
491
GC_err_printf1("sem_wait() returned %ld\n", (unsigned long)code);
492
ABORT("sem_wait() for restart handler failed");
449
495
#if DEBUG_THREADS
450
496
GC_printf0("World started\n");
457
503
if (sem_init(&GC_suspend_ack_sem, 0, 0) != 0)
458
504
ABORT("sem_init failed");
505
#ifdef GC_NETBSD_THREADS_WORKAROUND
506
if (sem_init(&GC_restart_ack_sem, 0, 0) != 0)
507
ABORT("sem_init failed");
460
510
act.sa_flags = SA_RESTART;
461
511
if (sigfillset(&act.sa_mask) != 0) {