1
1
#include "private/pthread_support.h"
3
#if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \
4
&& !defined(GC_WIN32_THREADS) && !defined(GC_DARWIN_THREADS)
3
#if defined(GC_PTHREADS) && !defined(GC_WIN32_THREADS) && \
4
!defined(GC_DARWIN_THREADS)
7
7
#include <semaphore.h>
12
# include <sys/select.h>
13
/* Doesn't exist on HP/UX 11.11. */
10
#include "atomic_ops.h"
35
31
if (pthread_sigmask(SIG_BLOCK, NULL, &blocked) != 0)
36
32
ABORT("pthread_sigmask");
37
GC_printf0("Blocked: ");
33
GC_printf("Blocked: ");
38
34
for (i = 1; i < NSIG; i++) {
39
if (sigismember(&blocked, i)) { GC_printf1("%ld ",(long) i); }
35
if (sigismember(&blocked, i)) { GC_printf("%d ", i); }
47
43
/* handler from a set. */
48
44
void GC_remove_allowed_signals(sigset_t *set)
51
if (sigdelset(set, SIGINT) != 0
46
if (sigdelset(set, SIGINT) != 0
52
47
|| sigdelset(set, SIGQUIT) != 0
53
48
|| sigdelset(set, SIGABRT) != 0
54
49
|| sigdelset(set, SIGTERM) != 0) {
55
50
ABORT("sigdelset() failed");
59
53
# ifdef MPROTECT_VDB
60
54
/* Handlers write to the thread structure, which is in the heap, */
72
66
static sigset_t suspend_handler_mask;
74
volatile sig_atomic_t GC_stop_count;
68
volatile AO_t GC_stop_count;
75
69
/* Incremented at the beginning of GC_stop_world. */
77
volatile sig_atomic_t GC_world_is_stopped = FALSE;
71
volatile AO_t GC_world_is_stopped = FALSE;
78
72
/* FALSE ==> it is safe for threads to restart, i.e. */
79
73
/* they will see another suspend signal before they */
80
74
/* 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);
91
77
#ifdef GC_OSF1_THREADS
92
78
GC_bool GC_retry_signals = TRUE;
127
113
sem_t GC_restart_ack_sem;
130
void GC_suspend_handler_inner(ptr_t sig_arg);
116
void GC_suspend_handler_inner(ptr_t sig_arg, void *context);
132
118
#if defined(IA64) || defined(HP_PA) || defined(M68K)
133
extern void GC_with_callee_saves_pushed();
120
void GC_suspend_handler(int sig, siginfo_t *info, void *context)
135
122
void GC_suspend_handler(int sig)
137
125
int old_errno = errno;
138
126
GC_with_callee_saves_pushed(GC_suspend_handler_inner, (ptr_t)(word)sig);
139
127
errno = old_errno;
143
130
/* We believe that in all other cases the full context is already */
144
131
/* in the signal handler frame. */
133
void GC_suspend_handler(int sig, siginfo_t *info, void *context)
145
135
void GC_suspend_handler(int sig)
147
138
int old_errno = errno;
148
GC_suspend_handler_inner((ptr_t)(word)sig);
142
GC_suspend_handler_inner((ptr_t)(word)sig, context);
149
143
errno = old_errno;
153
void GC_suspend_handler_inner(ptr_t sig_arg)
147
void GC_suspend_handler_inner(ptr_t sig_arg, void *context)
155
149
int sig = (int)(word)sig_arg;
162
156
/* guaranteed to be the mark_no correspending to our */
163
157
/* suspension, i.e. the marker can't have incremented it yet. */
165
word my_stop_count = GC_stop_count;
159
AO_t my_stop_count = AO_load(&GC_stop_count);
167
161
if (sig != SIG_SUSPEND) ABORT("Bad signal in suspend_handler");
170
GC_printf1("Suspending 0x%lx\n", my_thread);
164
GC_printf("Suspending 0x%x\n", (unsigned)my_thread);
173
167
me = GC_lookup_thread(my_thread);
174
168
/* The lookup here is safe, since I'm doing this on behalf */
187
me -> stop_info.stack_ptr = (ptr_t)GC_save_regs_in_stack();
181
me -> stop_info.stack_ptr = GC_save_regs_in_stack();
189
183
me -> stop_info.stack_ptr = (ptr_t)(&dummy);
192
me -> backing_store_ptr = (ptr_t)GC_save_regs_in_stack();
186
me -> backing_store_ptr = GC_save_regs_in_stack();
195
189
/* Tell the thread that wants to stop the world that this */
209
203
/* primitive and expensive mechanism to wait until it's */
210
204
/* really safe to proceed. Under normal circumstances, */
211
205
/* 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");
207
sigsuspend (&suspend_handler_mask);
208
} while (AO_load_acquire(&GC_world_is_stopped)
209
&& AO_load(&GC_stop_count) == my_stop_count);
219
210
/* If the RESTART signal gets lost, we can still lose. That should be */
220
211
/* less likely than losing the SUSPEND signal, since we don't do much */
221
212
/* between the sem_post and sigsuspend. */
223
214
/* Simply dropping the sigsuspend call should be safe, but is unlikely */
224
215
/* to be efficient. */
227
GC_printf1("Continuing 0x%lx\n", my_thread);
218
GC_printf("Continuing 0x%x\n", (unsigned)my_thread);
231
222
void GC_restart_handler(int sig)
233
224
pthread_t my_thread = pthread_self();
235
227
if (sig != SIG_THR_RESTART) ABORT("Bad signal in suspend_handler");
237
#ifdef GC_NETBSD_THREADS_WORKAROUND
238
sem_post(&GC_restart_ack_sem);
229
# ifdef GC_NETBSD_THREADS_WORKAROUND
230
sem_post(&GC_restart_ack_sem);
242
234
** Note: even if we don't do anything useful here,
269
262
pthread_t me = pthread_self();
271
264
if (!GC_thr_initialized) GC_thr_init();
273
GC_printf1("Pushing stacks from thread 0x%lx\n", (unsigned long) me);
266
GC_printf("Pushing stacks from thread 0x%x\n", (unsigned) me);
275
268
for (i = 0; i < THREAD_TABLE_SZ; i++) {
276
269
for (p = GC_threads[i]; p != 0; p = p -> next) {
277
270
if (p -> flags & FINISHED) continue;
278
if (pthread_equal(p -> id, me)) {
272
if (THREAD_EQUAL(p -> id, me)) {
280
274
lo = (ptr_t)GC_save_regs_in_stack();
295
289
hi = GC_stackbottom;
296
290
IF_IA64(bs_lo = BACKING_STORE_BASE;)
299
GC_printf3("Stack for thread 0x%lx = [%lx,%lx)\n",
300
(unsigned long) p -> id,
301
(unsigned long) lo, (unsigned long) hi);
293
GC_printf("Stack for thread 0x%x = [%p,%p)\n",
294
(unsigned)(p -> id), lo, hi);
303
296
if (0 == lo) ABORT("GC_push_all_stacks: sp not set!\n");
304
297
# ifdef STACK_GROWS_UP
305
298
/* We got them backwards! */
311
304
# if DEBUG_THREADS
312
GC_printf3("Reg stack for thread 0x%lx = [%lx,%lx)\n",
313
(unsigned long) p -> id,
314
(unsigned long) bs_lo, (unsigned long) bs_hi);
305
GC_printf("Reg stack for thread 0x%x = [%lx,%lx)\n",
306
(unsigned)p -> id, bs_lo, bs_hi);
316
if (pthread_equal(p -> id, me)) {
308
if (THREAD_EQUAL(p -> id, me)) {
317
309
/* FIXME: This may add an unbounded number of entries, */
318
310
/* and hence overflow the mark stack, which is bad. */
319
311
GC_push_all_eager(bs_lo, bs_hi);
318
if (GC_print_stats == VERBOSE) {
319
GC_log_printf("Pushed %d thread stacks\n", nthreads);
326
321
if (!found_me && !GC_in_thread_creation)
327
322
ABORT("Collecting from unknown thread.");
347
342
GC_stopping_pid = getpid(); /* debugging only. */
348
343
for (i = 0; i < THREAD_TABLE_SZ; i++) {
349
344
for (p = GC_threads[i]; p != 0; p = p -> next) {
350
if (p -> id != my_thread) {
345
if (!THREAD_EQUAL(p -> id, my_thread)) {
351
346
if (p -> flags & FINISHED) continue;
352
347
if (p -> stop_info.last_stop_count == GC_stop_count) continue;
353
348
if (p -> thread_blocked) /* Will wait */ continue;
354
349
n_live_threads++;
356
GC_printf1("Sending suspend signal to 0x%lx\n", p -> id);
351
GC_printf("Sending suspend signal to 0x%x\n",
352
(unsigned)(p -> id));
359
result = pthread_kill(p -> id, SIG_SUSPEND);
355
result = pthread_kill(p -> id, SIG_SUSPEND);
362
358
/* Not really there anymore. Possible? */
373
369
return n_live_threads;
376
/* Caller holds allocation lock. */
377
372
void GC_stop_world()
380
375
int n_live_threads;
384
GC_printf1("Stopping the world from 0x%lx\n", pthread_self());
378
GC_ASSERT(I_HOLD_LOCK());
380
GC_printf("Stopping the world from 0x%x\n", (unsigned)pthread_self());
387
383
/* Make sure all free list construction has stopped before we start. */
388
384
/* No new construction can start, since free list construction is */
393
389
GC_ASSERT(GC_fl_builder_count == 0);
394
390
/* We should have previously waited for it to become zero. */
395
391
# endif /* PARALLEL_MARK */
397
GC_world_is_stopped = TRUE;
392
AO_store(&GC_stop_count, GC_stop_count+1);
393
/* Only concurrent reads are possible. */
394
AO_store_release(&GC_world_is_stopped, TRUE);
398
395
n_live_threads = GC_suspend_all();
400
397
if (GC_retry_signals) {
409
406
if (wait_usecs > RETRY_INTERVAL) {
410
407
int newly_sent = GC_suspend_all();
413
if (GC_print_stats) {
414
GC_printf1("Resent %ld signals after timeout\n",
409
if (GC_print_stats) {
410
GC_log_printf("Resent %d signals after timeout\n",
418
413
sem_getvalue(&GC_suspend_ack_sem, &ack_count);
419
414
if (newly_sent < n_live_threads - ack_count) {
420
415
WARN("Lost some threads during GC_stop_world?!\n",0);
429
424
for (i = 0; i < n_live_threads; i++) {
430
while (0 != (code = sem_wait(&GC_suspend_ack_sem))) {
431
if (errno != EINTR) {
432
GC_err_printf1("Sem_wait returned %ld\n", (unsigned long)code);
433
ABORT("sem_wait for handler failed");
426
if (0 != (code = sem_wait(&GC_suspend_ack_sem))) {
427
/* On Linux, sem_wait is documented to always return zero.*/
428
/* But the documentation appears to be incorrect. */
429
if (errno == EINTR) {
430
/* Seems to happen with some versions of gdb. */
433
ABORT("sem_wait for handler failed");
437
436
# ifdef PARALLEL_MARK
438
437
GC_release_mark_lock();
440
439
#if DEBUG_THREADS
441
GC_printf1("World stopped from 0x%lx\n", pthread_self());
440
GC_printf("World stopped from 0x%x\n", (unsigned)pthread_self());
443
442
GC_stopping_thread = 0; /* debugging only */
452
451
register GC_thread p;
453
452
register int n_live_threads = 0;
454
453
register int result;
455
#ifdef GC_NETBSD_THREADS_WORKAROUND
454
# ifdef GC_NETBSD_THREADS_WORKAROUND
459
458
# if DEBUG_THREADS
460
GC_printf0("World starting\n");
459
GC_printf("World starting\n");
463
GC_world_is_stopped = FALSE;
462
AO_store(&GC_world_is_stopped, FALSE);
464
463
for (i = 0; i < THREAD_TABLE_SZ; i++) {
465
464
for (p = GC_threads[i]; p != 0; p = p -> next) {
466
if (p -> id != my_thread) {
465
if (!THREAD_EQUAL(p -> id, my_thread)) {
467
466
if (p -> flags & FINISHED) continue;
468
467
if (p -> thread_blocked) continue;
469
468
n_live_threads++;
470
469
#if DEBUG_THREADS
471
GC_printf1("Sending restart signal to 0x%lx\n", p -> id);
470
GC_printf("Sending restart signal to 0x%x\n",
471
(unsigned)(p -> id));
473
474
result = pthread_kill(p -> id, SIG_THR_RESTART);
487
#ifdef GC_NETBSD_THREADS_WORKAROUND
488
for (i = 0; i < n_live_threads; i++)
488
# ifdef GC_NETBSD_THREADS_WORKAROUND
489
for (i = 0; i < n_live_threads; i++)
489
490
while (0 != (code = sem_wait(&GC_restart_ack_sem)))
490
491
if (errno != EINTR) {
491
GC_err_printf1("sem_wait() returned %ld\n", (unsigned long)code);
492
GC_err_printf("sem_wait() returned %d\n",
492
494
ABORT("sem_wait() for restart handler failed");
496
GC_printf0("World started\n");
498
GC_printf("World started\n");
500
502
void GC_stop_init() {
503
505
if (sem_init(&GC_suspend_ack_sem, 0, 0) != 0)
504
506
ABORT("sem_init failed");
505
#ifdef GC_NETBSD_THREADS_WORKAROUND
506
if (sem_init(&GC_restart_ack_sem, 0, 0) != 0)
507
# ifdef GC_NETBSD_THREADS_WORKAROUND
508
if (sem_init(&GC_restart_ack_sem, 0, 0) != 0)
507
509
ABORT("sem_init failed");
510
act.sa_flags = SA_RESTART;
512
act.sa_flags = SA_RESTART
511
517
if (sigfillset(&act.sa_mask) != 0) {
512
518
ABORT("sigfillset() failed");
514
520
GC_remove_allowed_signals(&act.sa_mask);
515
521
/* SIG_THR_RESTART is set in the resulting mask. */
516
522
/* It is unmasked by the handler when necessary. */
524
act.sa_sigaction = GC_suspend_handler;
517
526
act.sa_handler = GC_suspend_handler;
518
528
if (sigaction(SIG_SUSPEND, &act, NULL) != 0) {
519
529
ABORT("Cannot set SIG_SUSPEND handler");
533
act.sa_flags &= ~ SA_SIGINFO;
522
535
act.sa_handler = GC_restart_handler;
523
536
if (sigaction(SIG_THR_RESTART, &act, NULL) != 0) {
524
537
ABORT("Cannot set SIG_THR_RESTART handler");
537
550
if (0 != GETENV("GC_NO_RETRY_SIGNALS")) {
538
551
GC_retry_signals = FALSE;
541
if (GC_print_stats && GC_retry_signals) {
542
GC_printf0("Will retry suspend signal if necessary.\n");
553
if (GC_print_stats && GC_retry_signals) {
554
GC_log_printf("Will retry suspend signal if necessary.\n");