summaryrefslogtreecommitdiff
path: root/pthread_stop_world.c
diff options
context:
space:
mode:
Diffstat (limited to 'pthread_stop_world.c')
-rw-r--r--pthread_stop_world.c136
1 files changed, 77 insertions, 59 deletions
diff --git a/pthread_stop_world.c b/pthread_stop_world.c
index 0ef0d221..9302f93f 100644
--- a/pthread_stop_world.c
+++ b/pthread_stop_world.c
@@ -43,6 +43,9 @@ int GC_nacl_thread_used[MAX_NACL_GC_THREADS];
#include <unistd.h>
#include "atomic_ops.h"
+/* It's safe to call original pthread_sigmask() here. */
+#undef pthread_sigmask
+
#ifdef DEBUG_THREADS
# ifndef NSIG
# if defined(MAXSIG)
@@ -56,19 +59,17 @@ int GC_nacl_thread_used[MAX_NACL_GC_THREADS];
# endif
# endif /* NSIG */
- /* It's safe to call original pthread_sigmask() here. */
-# undef pthread_sigmask
-
void GC_print_sig_mask(void)
{
sigset_t blocked;
int i;
if (pthread_sigmask(SIG_BLOCK, NULL, &blocked) != 0)
- ABORT("pthread_sigmask");
+ ABORT("pthread_sigmask failed");
GC_printf("Blocked: ");
for (i = 1; i < NSIG; i++) {
- if (sigismember(&blocked, i)) { GC_printf("%d ", i); }
+ if (sigismember(&blocked, i))
+ GC_printf("%d ", i);
}
GC_printf("\n");
}
@@ -128,7 +129,8 @@ STATIC volatile AO_t GC_world_is_stopped = FALSE;
*/
#ifndef SIG_THR_RESTART
-# if defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS) || defined(GC_NETBSD_THREADS)
+# if defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS) \
+ || defined(GC_NETBSD_THREADS)
# ifdef _SIGRTMIN
# define SIG_THR_RESTART _SIGRTMIN + 5
# else
@@ -139,6 +141,20 @@ STATIC volatile AO_t GC_world_is_stopped = FALSE;
# endif
#endif
+#ifdef GC_EXPLICIT_SIGNALS_UNBLOCK
+ /* Some targets (eg., Solaris) might require this to be called when */
+ /* doing thread registering from the thread destructor. */
+ GC_INNER void GC_unblock_gc_signals(void)
+ {
+ sigset_t set;
+ sigemptyset(&set);
+ sigaddset(&set, SIG_SUSPEND);
+ sigaddset(&set, SIG_THR_RESTART);
+ if (pthread_sigmask(SIG_UNBLOCK, &set, NULL) != 0)
+ ABORT("pthread_sigmask failed");
+ }
+#endif /* GC_EXPLICIT_SIGNALS_UNBLOCK */
+
STATIC sem_t GC_suspend_ack_sem;
#ifdef GC_NETBSD_THREADS
@@ -176,15 +192,13 @@ STATIC void GC_suspend_handler_inner(ptr_t sig_arg, void *context);
/*ARGSUSED*/
STATIC void GC_suspend_handler_inner(ptr_t sig_arg, void *context)
{
- int sig = (int)(word)sig_arg;
- int dummy;
- pthread_t my_thread = pthread_self();
+ pthread_t self = pthread_self();
GC_thread me;
IF_CANCEL(int cancel_state;)
-
AO_t my_stop_count = AO_load(&GC_stop_count);
- if (sig != SIG_SUSPEND) ABORT("Bad signal in suspend_handler");
+ if ((signed_word)sig_arg != SIG_SUSPEND)
+ ABORT("Bad signal in suspend_handler");
DISABLE_CANCEL(cancel_state);
/* pthread_setcancelstate is not defined to be async-signal-safe. */
@@ -196,10 +210,10 @@ STATIC void GC_suspend_handler_inner(ptr_t sig_arg, void *context)
/* cancellation point is inherently a problem, unless there is */
/* some way to disable cancellation in the handler. */
# ifdef DEBUG_THREADS
- GC_printf("Suspending 0x%x\n", (unsigned)my_thread);
+ GC_log_printf("Suspending 0x%x\n", (unsigned)self);
# endif
- me = GC_lookup_thread(my_thread);
+ me = GC_lookup_thread(self);
/* The lookup here is safe, since I'm doing this on behalf */
/* of a thread which holds the allocation lock in order */
/* to stop the world. Thus concurrent modification of the */
@@ -207,7 +221,7 @@ STATIC void GC_suspend_handler_inner(ptr_t sig_arg, void *context)
if (me -> stop_info.last_stop_count == my_stop_count) {
/* Duplicate signal. OK if we are retrying. */
if (!GC_retry_signals) {
- WARN("Duplicate suspend signal in thread %p\n", pthread_self());
+ WARN("Duplicate suspend signal in thread %p\n", self);
}
RESTORE_CANCEL(cancel_state);
return;
@@ -215,7 +229,7 @@ STATIC void GC_suspend_handler_inner(ptr_t sig_arg, void *context)
# ifdef SPARC
me -> stop_info.stack_ptr = GC_save_regs_in_stack();
# else
- me -> stop_info.stack_ptr = (ptr_t)(&dummy);
+ me -> stop_info.stack_ptr = (ptr_t)(&me);
# endif
# ifdef IA64
me -> backing_store_ptr = GC_save_regs_in_stack();
@@ -250,7 +264,7 @@ STATIC void GC_suspend_handler_inner(ptr_t sig_arg, void *context)
/* unlikely to be efficient. */
# ifdef DEBUG_THREADS
- GC_printf("Continuing 0x%x\n", (unsigned)my_thread);
+ GC_log_printf("Continuing 0x%x\n", (unsigned)self);
# endif
RESTORE_CANCEL(cancel_state);
}
@@ -272,7 +286,8 @@ STATIC void GC_restart_handler(int sig)
*/
# ifdef DEBUG_THREADS
- GC_printf("In GC_restart_handler for 0x%x\n", (unsigned)pthread_self());
+ GC_log_printf("In GC_restart_handler for 0x%x\n",
+ (unsigned)pthread_self());
# endif
}
@@ -294,18 +309,18 @@ GC_INNER void GC_push_all_stacks(void)
ptr_t lo, hi;
/* On IA64, we also need to scan the register backing store. */
IF_IA64(ptr_t bs_lo; ptr_t bs_hi;)
- pthread_t me = pthread_self();
+ pthread_t self = pthread_self();
word total_size = 0;
if (!GC_thr_initialized) GC_thr_init();
# ifdef DEBUG_THREADS
- GC_printf("Pushing stacks from thread 0x%x\n", (unsigned) me);
+ GC_log_printf("Pushing stacks from thread 0x%x\n", (unsigned)self);
# endif
for (i = 0; i < THREAD_TABLE_SZ; i++) {
for (p = GC_threads[i]; p != 0; p = p -> next) {
if (p -> flags & FINISHED) continue;
++nthreads;
- if (THREAD_EQUAL(p -> id, me)) {
+ if (THREAD_EQUAL(p -> id, self)) {
GC_ASSERT(!p->thread_blocked);
# ifdef SPARC
lo = (ptr_t)GC_save_regs_in_stack();
@@ -327,8 +342,8 @@ GC_INNER void GC_push_all_stacks(void)
IF_IA64(bs_lo = BACKING_STORE_BASE;)
}
# ifdef DEBUG_THREADS
- GC_printf("Stack for thread 0x%x = [%p,%p)\n",
- (unsigned)(p -> id), lo, hi);
+ GC_log_printf("Stack for thread 0x%x = [%p,%p)\n",
+ (unsigned)(p -> id), lo, hi);
# endif
if (0 == lo) ABORT("GC_push_all_stacks: sp not set!");
GC_push_all_stack_sections(lo, hi, p -> traced_stack_sect);
@@ -345,23 +360,23 @@ GC_INNER void GC_push_all_stacks(void)
# endif
# ifdef IA64
# ifdef DEBUG_THREADS
- GC_printf("Reg stack for thread 0x%x = [%p,%p)\n",
- (unsigned)p -> id, bs_lo, bs_hi);
+ GC_log_printf("Reg stack for thread 0x%x = [%p,%p)\n",
+ (unsigned)p -> id, bs_lo, bs_hi);
# endif
- /* FIXME: This (if p->id==me) may add an unbounded number of */
- /* entries, and hence overflow the mark stack, which is bad. */
+ /* FIXME: This (if p->id==self) may add an unbounded number of */
+ /* entries, and hence overflow the mark stack, which is bad. */
GC_push_all_register_sections(bs_lo, bs_hi,
- THREAD_EQUAL(p -> id, me),
+ THREAD_EQUAL(p -> id, self),
p -> traced_stack_sect);
total_size += bs_hi - bs_lo; /* bs_lo <= bs_hi */
# endif
}
}
if (GC_print_stats == VERBOSE) {
- GC_log_printf("Pushed %d thread stacks\n", (int)nthreads);
+ GC_log_printf("Pushed %d thread stacks\n", (int)nthreads);
}
if (!found_me && !GC_in_thread_creation)
- ABORT("Collecting from unknown thread.");
+ ABORT("Collecting from unknown thread");
GC_total_stacksize = total_size;
}
@@ -373,6 +388,8 @@ GC_INNER void GC_push_all_stacks(void)
#endif
#ifdef PLATFORM_ANDROID
+ extern int tkill(pid_t tid, int sig); /* from sys/linux-unistd.h */
+
static int android_thread_kill(pid_t tid, int sig)
{
int ret;
@@ -401,15 +418,15 @@ STATIC int GC_suspend_all(void)
# ifndef GC_OPENBSD_THREADS
int result;
# endif
- pthread_t my_thread = pthread_self();
+ pthread_t self = pthread_self();
# ifdef DEBUG_THREADS
- GC_stopping_thread = my_thread;
+ GC_stopping_thread = self;
GC_stopping_pid = getpid();
# endif
for (i = 0; i < THREAD_TABLE_SZ; i++) {
for (p = GC_threads[i]; p != 0; p = p -> next) {
- if (!THREAD_EQUAL(p -> id, my_thread)) {
+ if (!THREAD_EQUAL(p -> id, self)) {
if (p -> flags & FINISHED) continue;
if (p -> thread_blocked) /* Will wait */ continue;
# ifndef GC_OPENBSD_THREADS
@@ -417,8 +434,8 @@ STATIC int GC_suspend_all(void)
n_live_threads++;
# endif
# ifdef DEBUG_THREADS
- GC_printf("Sending suspend signal to 0x%x\n",
- (unsigned)(p -> id));
+ GC_log_printf("Sending suspend signal to 0x%x\n",
+ (unsigned)(p -> id));
# endif
# ifdef GC_OPENBSD_THREADS
@@ -457,8 +474,8 @@ STATIC int GC_suspend_all(void)
# define NACL_PARK_WAIT_NANOSECONDS (100 * 1000)
# endif
# ifdef DEBUG_THREADS
- GC_printf("pthread_stop_world: num_threads %d\n",
- GC_nacl_num_gc_threads - 1);
+ GC_log_printf("pthread_stop_world: num_threads %d\n",
+ GC_nacl_num_gc_threads - 1);
# endif
GC_nacl_thread_parker = pthread_self();
GC_nacl_park_threads_now = 1;
@@ -488,8 +505,8 @@ STATIC int GC_suspend_all(void)
ts.tv_sec = 0;
ts.tv_nsec = NACL_PARK_WAIT_NANOSECONDS;
# ifdef DEBUG_THREADS
- GC_printf("Sleep waiting for %d threads to park...\n",
- GC_nacl_num_gc_threads - num_threads_parked - 1);
+ GC_log_printf("Sleep waiting for %d threads to park...\n",
+ GC_nacl_num_gc_threads - num_threads_parked - 1);
# endif
/* This requires _POSIX_TIMERS feature. */
nanosleep(&ts, 0);
@@ -507,7 +524,7 @@ GC_INNER void GC_stop_world(void)
# endif
GC_ASSERT(I_HOLD_LOCK());
# ifdef DEBUG_THREADS
- GC_printf("Stopping the world from 0x%x\n", (unsigned)pthread_self());
+ GC_log_printf("Stopping the world from 0x%x\n", (unsigned)pthread_self());
# endif
/* Make sure all free list construction has stopped before we start. */
@@ -543,8 +560,7 @@ GC_INNER void GC_stop_world(void)
int newly_sent = GC_suspend_all();
if (GC_print_stats) {
- GC_log_printf("Resent %d signals after timeout\n",
- newly_sent);
+ GC_log_printf("Resent %d signals after timeout\n", newly_sent);
}
sem_getvalue(&GC_suspend_ack_sem, &ack_count);
if (newly_sent < n_live_threads - ack_count) {
@@ -577,7 +593,7 @@ GC_INNER void GC_stop_world(void)
GC_release_mark_lock();
# endif
# ifdef DEBUG_THREADS
- GC_printf("World stopped from 0x%x\n", (unsigned)pthread_self());
+ GC_log_printf("World stopped from 0x%x\n", (unsigned)pthread_self());
GC_stopping_thread = 0;
# endif
}
@@ -712,7 +728,7 @@ GC_INNER void GC_stop_world(void)
GC_INNER void GC_start_world(void)
{
# ifndef NACL
- pthread_t my_thread = pthread_self();
+ pthread_t self = pthread_self();
register int i;
register GC_thread p;
# ifndef GC_OPENBSD_THREADS
@@ -724,7 +740,7 @@ GC_INNER void GC_start_world(void)
# endif
# ifdef DEBUG_THREADS
- GC_printf("World starting\n");
+ GC_log_printf("World starting\n");
# endif
# ifndef GC_OPENBSD_THREADS
@@ -732,15 +748,15 @@ GC_INNER void GC_start_world(void)
# endif
for (i = 0; i < THREAD_TABLE_SZ; i++) {
for (p = GC_threads[i]; p != 0; p = p -> next) {
- if (!THREAD_EQUAL(p -> id, my_thread)) {
+ if (!THREAD_EQUAL(p -> id, self)) {
if (p -> flags & FINISHED) continue;
if (p -> thread_blocked) continue;
# ifndef GC_OPENBSD_THREADS
n_live_threads++;
# endif
# ifdef DEBUG_THREADS
- GC_printf("Sending restart signal to 0x%x\n",
- (unsigned)(p -> id));
+ GC_log_printf("Sending restart signal to 0x%x\n",
+ (unsigned)(p -> id));
# endif
# ifdef GC_OPENBSD_THREADS
@@ -767,20 +783,22 @@ GC_INNER void GC_start_world(void)
}
}
# ifdef GC_NETBSD_THREADS_WORKAROUND
- for (i = 0; i < n_live_threads; i++)
- while (0 != (code = sem_wait(&GC_restart_ack_sem)))
- if (errno != EINTR) {
- if (GC_print_stats)
- GC_printf("sem_wait() returned %d\n", code);
- ABORT("sem_wait() for restart handler failed");
- }
+ for (i = 0; i < n_live_threads; i++) {
+ while (0 != (code = sem_wait(&GC_restart_ack_sem))) {
+ if (errno != EINTR) {
+ if (GC_print_stats)
+ GC_log_printf("sem_wait() returned %d\n", code);
+ ABORT("sem_wait() for restart handler failed");
+ }
+ }
+ }
# endif
# ifdef DEBUG_THREADS
- GC_printf("World started\n");
+ GC_log_printf("World started\n");
# endif
# else /* NACL */
# ifdef DEBUG_THREADS
- GC_printf("World starting...\n");
+ GC_log_printf("World starting...\n");
# endif
GC_nacl_park_threads_now = 0;
# endif
@@ -791,10 +809,10 @@ GC_INNER void GC_stop_init(void)
# if !defined(GC_OPENBSD_THREADS) && !defined(NACL)
struct sigaction act;
- if (sem_init(&GC_suspend_ack_sem, 0, 0) != 0)
+ if (sem_init(&GC_suspend_ack_sem, GC_SEM_INIT_PSHARED, 0) != 0)
ABORT("sem_init failed");
# ifdef GC_NETBSD_THREADS_WORKAROUND
- if (sem_init(&GC_restart_ack_sem, 0, 0) != 0)
+ if (sem_init(&GC_restart_ack_sem, GC_SEM_INIT_PSHARED, 0) != 0)
ABORT("sem_init failed");
# endif
@@ -840,7 +858,7 @@ GC_INNER void GC_stop_init(void)
GC_retry_signals = FALSE;
}
if (GC_print_stats && GC_retry_signals) {
- GC_log_printf("Will retry suspend signal if necessary.\n");
+ GC_log_printf("Will retry suspend signal if necessary\n");
}
# endif /* !GC_OPENBSD_THREADS && !NACL */
}