|
From: Jeremy F. <je...@go...> - 2005-01-28 09:08:57
|
CVS commit by fitzhardinge:
Set SIGVGCHLD to SIG_IGN, except for when we actually care about it.
This prevents unwanted signals from building up and clogging our
pores.
M +8 -10 core.h 1.72
M +4 -4 vg_scheduler.c 1.216
M +93 -42 vg_signals.c 1.116
M +2 -4 vg_syscalls.c 1.238
M +10 -29 linux/core_os.c 1.7
M +8 -8 x86-linux/syscall.S 1.4
M +16 -0 x86-linux/syscalls.c 1.19
--- valgrind/coregrind/vg_signals.c #1.115:1.116
@@ -93,10 +93,7 @@ static void vg_sync_signalhandler ( Int
static void vg_async_signalhandler ( Int sigNo, vki_siginfo_t *info, struct vki_ucontext * );
static void sigvgkill_handler ( Int sigNo, vki_siginfo_t *info, struct vki_ucontext * );
-static void sigvgchld_handler ( Int sigNo, vki_siginfo_t *info, struct vki_ucontext * );
static const Char *signame(Int sigNo);
-vki_sigset_t VG_(blocked_mask);
-
/* Maximum usable signal. */
Int VG_(max_signal) = _VKI_NSIG;
@@ -257,5 +254,5 @@ void calculate_SKSS_from_SCSS ( SKSS* ds
skss_handler = sigvgkill_handler;
else if (sig == VKI_SIGVGCHLD)
- skss_handler = sigvgchld_handler;
+ skss_handler = VKI_SIG_IGN; /* we only poll for it */
else {
if (scss_handler == VKI_SIG_IGN)
@@ -477,5 +474,5 @@ Int VG_(do_sys_sigaction) ( Int signo,
/* don't let them use our signals */
- if ( (signo == VKI_SIGVGCHLD || signo == VKI_SIGVGKILL)
+ if ( (signo > VKI_SIGVGRTUSERMAX)
&& new_act
&& !(new_act->ksa_handler == VKI_SIG_DFL || new_act->ksa_handler == VKI_SIG_IGN) )
@@ -565,8 +562,61 @@ void do_sigprocmask_bitops ( Int vki_how
}
+static void sigvgchld_handler(Int sig)
+{
+ VG_(printf)("got a sigvgchld?\n");
+}
+
+/*
+ Wait until some predicate about threadstates is satisfied.
+
+ This uses SIGVGCHLD as a notification that it is now worth
+ re-evaluating the predicate.
+ */
+void VG_(wait_for_threadstate)(Bool (*pred)(void *), void *arg)
+{
+ vki_sigset_t set, saved;
+ struct vki_sigaction sa, old_sa;
+
+ /*
+ SIGVGCHLD is set to be ignored, and is unblocked by default.
+ This means all such signals are simply discarded.
+
+ In this loop, we actually block it, and then poll for it with
+ sigtimedwait.
+ */
+ VG_(sigemptyset)(&set);
+ VG_(sigaddset)(&set, VKI_SIGVGCHLD);
+
+ VG_(set_sleeping)(VG_(master_tid), VgTs_Yielding);
+ VG_(sigprocmask)(VKI_SIG_BLOCK, &set, &saved);
+
+ /* It shouldn't be necessary to set a handler, since the signal is
+ always blocked, but it seems to be necessary to convice the
+ kernel not to just toss the signal... */
+ sa.ksa_handler = sigvgchld_handler;
+ sa.sa_flags = 0;
+ VG_(sigfillset)(&sa.sa_mask);
+ VG_(sigaction)(VKI_SIGVGCHLD, &sa, &old_sa);
+
+ vg_assert(old_sa.ksa_handler == VKI_SIG_IGN);
+
+ while(!(*pred)(arg)) {
+ struct vki_siginfo si;
+ Int ret = VG_(sigtimedwait)(&set, &si, NULL);
+
+ if (ret > 0 && VG_(clo_trace_signals))
+ VG_(message)(Vg_DebugMsg, "Got %d (code=%d) from tid lwp %d",
+ ret, si.si_code, si._sifields._kill._pid);
+ }
+
+ VG_(sigaction)(VKI_SIGVGCHLD, &old_sa, NULL);
+ VG_(sigprocmask)(VKI_SIG_SETMASK, &saved, NULL);
+ VG_(set_running)(VG_(master_tid));
+}
+
/* Add and remove signals from mask so that we end up telling the
kernel the state we actually want rather than what the client
wants. */
-void VG_(sanitize_client_sigmask)(vki_sigset_t *mask)
+void VG_(sanitize_client_sigmask)(ThreadId tid, vki_sigset_t *mask)
{
VG_(sigdelset)(mask, VKI_SIGKILL);
@@ -574,5 +624,13 @@ void VG_(sanitize_client_sigmask)(vki_si
VG_(sigdelset)(mask, VKI_SIGVGKILL); /* never block */
- VG_(sigaddset)(mask, VKI_SIGVGCHLD); /* always block */
+
+ /* SIGVGCHLD is used by threads to indicate their state changes to
+ the master thread. Mostly it doesn't care, so it leaves the
+ signal ignored and unblocked. Everyone else should have it
+ blocked, so there's at most 1 thread with it unblocked. */
+ if (tid == VG_(master_tid))
+ VG_(sigdelset)(mask, VKI_SIGVGCHLD);
+ else
+ VG_(sigaddset)(mask, VKI_SIGVGCHLD);
}
@@ -816,7 +874,7 @@ void VG_(kill_self)(Int sigNo)
VG_(sigaction)(sigNo, &sa, &origsa);
- VG_(sigfillset)(&mask);
- VG_(sigdelset)(&mask, sigNo);
- VG_(sigprocmask)(VKI_SIG_SETMASK, &mask, &origmask);
+ VG_(sigemptyset)(&mask);
+ VG_(sigaddset)(&mask, sigNo);
+ VG_(sigprocmask)(VKI_SIG_UNBLOCK, &mask, &origmask);
VG_(tkill)(VG_(getpid)(), sigNo);
@@ -1808,21 +1866,4 @@ static void sigvgkill_handler(int signo,
}
-/* This handler should never be called */
-static void sigvgchld_handler(int signo, vki_siginfo_t *si, struct vki_ucontext *uc)
-{
- /* Just ignore it - it seems that LinuxThread signals can get
- delivered even if they're blocked... */
- vg_assert(signo == VKI_SIGVGCHLD);
-
- if (VG_(clo_trace_signals)) {
- vki_sigset_t mask;
- VG_(sigprocmask)(0, NULL, &mask);
- VG_(message)(Vg_DebugMsg, "SIGVGCHLD called in tid %d: mask=%08x%08x (blocked=%d)\n",
- VG_(gettid)(), mask.sig[1], mask.sig[0], VG_(sigismember)(&mask, signo));
- }
-
- return;
-}
-
static __attribute((unused))
void pp_vg_ksigaction ( struct vki_sigaction* sa )
@@ -1865,11 +1906,4 @@ void VG_(poll_signals)(ThreadId tid)
vki_sigset_t saved_mask;
- /* First, mop up any pending SIGVGCHLDs; we don't care about
- them here. */
- VG_(sigemptyset)(&pollset);
- VG_(sigaddset)(&pollset, VKI_SIGVGCHLD);
- while(VG_(sigtimedwait)(&pollset, NULL, &zero) == VKI_SIGVGCHLD)
- ;
-
/* look for all the signals this thread isn't blocking */
for(i = 0; i < _VKI_NSIG_WORDS; i++)
@@ -1909,4 +1943,29 @@ void VG_(poll_signals)(ThreadId tid)
}
+/* Set the standard set of blocked signals, used wheneever we're not
+ running a client syscall. */
+void VG_(block_signals)(ThreadId tid)
+{
+ vki_sigset_t mask;
+
+ VG_(sigfillset)(&mask);
+
+ /* Don't block these because they're synchronous */
+ VG_(sigdelset)(&mask, VKI_SIGSEGV);
+ VG_(sigdelset)(&mask, VKI_SIGBUS);
+ VG_(sigdelset)(&mask, VKI_SIGFPE);
+ VG_(sigdelset)(&mask, VKI_SIGILL);
+
+ /* Can't block these anyway */
+ VG_(sigdelset)(&mask, VKI_SIGSTOP);
+ VG_(sigdelset)(&mask, VKI_SIGKILL);
+
+ /* Master doesn't block this */
+ if (tid == VG_(master_tid))
+ VG_(sigdelset)(&mask, VKI_SIGVGCHLD);
+
+ VG_(sigprocmask)(VKI_SIG_SETMASK, &mask, NULL);
+}
+
/* At startup, copy the process' real signal state to the SCSS.
Whilst doing this, block all real signals. Then calculate SKSS and
@@ -1925,12 +1984,4 @@ void VG_(sigstartup_actions) ( void )
VG_(block_all_host_signals)( &saved_procmask );
- VG_(sigfillset)(&VG_(blocked_mask));
- VG_(sigdelset)(&VG_(blocked_mask), VKI_SIGSEGV);
- VG_(sigdelset)(&VG_(blocked_mask), VKI_SIGBUS);
- VG_(sigdelset)(&VG_(blocked_mask), VKI_SIGFPE);
- VG_(sigdelset)(&VG_(blocked_mask), VKI_SIGILL);
- VG_(sigdelset)(&VG_(blocked_mask), VKI_SIGSTOP);
- VG_(sigdelset)(&VG_(blocked_mask), VKI_SIGKILL);
-
/* Copy per-signal settings to SCSS. */
for (i = 1; i <= _VKI_NSIG; i++) {
--- valgrind/coregrind/core.h #1.71:1.72
@@ -839,10 +839,7 @@ extern Bool VG_(my_fault);
------------------------------------------------------------------ */
-/* This is a signal mask with almost everything blocked. The
- exceptions are signals which could be synchronous (SIGILL, SIGBUS,
- SIGSEGV - if we get one of those when they're blocked, then the
- whole process could just die without warning), and the unblockable
- ones (SIGKILL and SIGSTOP). */
-extern vki_sigset_t VG_(blocked_mask);
+/* Set the standard set of blocked signals, used wheneever we're not
+ running a client syscall. */
+extern void VG_(block_signals)(ThreadId tid);
/* Highest signal the kernel will let us use */
@@ -901,5 +898,8 @@ extern void VG_(set_default_handler)(Int
/* Adjust a client's signal mask to match our internal requirements */
-extern void VG_(sanitize_client_sigmask)(vki_sigset_t *mask);
+extern void VG_(sanitize_client_sigmask)(ThreadId tid, vki_sigset_t *mask);
+
+/* Wait until a thread-related predicate is true */
+extern void VG_(wait_for_threadstate)(Bool (*pred)(void *), void *arg);
/* ---------------------------------------------------------------------
@@ -1847,7 +1847,5 @@ extern const Addr vga_sys_before, vga_sy
*/
extern void VGA_(client_syscall)(Int syscallno, arch_thread_t *regs,
- const vki_sigset_t *syscall_mask,
- const vki_sigset_t *restore_mask,
- Int nsigwords);
+ const vki_sigset_t *syscall_mask);
/*
--- valgrind/coregrind/vg_syscalls.c #1.237:1.238
@@ -6034,10 +6034,8 @@ void VG_(client_syscall) ( ThreadId tid
mask = tst->sig_mask;
- VG_(sanitize_client_sigmask)(&mask);
+ VG_(sanitize_client_sigmask)(tid, &mask);
VG_(set_sleeping)(tid, VgTs_WaitSys);
- VGA_(client_syscall)(syscallno, &tst->arch, &mask,
- &VG_(blocked_mask),
- _VKI_NSIG_WORDS * sizeof(UWord));
+ VGA_(client_syscall)(syscallno, &tst->arch, &mask);
/* VGA_(client_syscall) may not return if the syscall was
interrupted by a signal. In that case, flow of control
--- valgrind/coregrind/vg_scheduler.c #1.215:1.216
@@ -538,5 +538,5 @@ UInt run_thread_for_a_while ( ThreadId t
vg_assert(trc == 0);
trc = VG_TRC_FAULT_SIGNAL;
- VG_(sigprocmask)(VKI_SIG_SETMASK, &VG_(blocked_mask), NULL);
+ VG_(block_signals)(tid);
}
@@ -705,5 +705,5 @@ static void handle_syscall(ThreadId tid)
if (jumped) {
- VG_(sigprocmask)(VKI_SIG_SETMASK, &VG_(blocked_mask), NULL);
+ VG_(block_signals)(tid);
VG_(poll_signals)(tid);
}
@@ -726,5 +726,5 @@ VgSchedReturnCode VG_(scheduler) ( Threa
/* set the proper running signal mask */
- VG_(sigprocmask)(VKI_SIG_SETMASK, &VG_(blocked_mask), NULL);
+ VG_(block_signals)(tid);
vg_assert(VG_(is_running_thread)(tid));
@@ -809,5 +809,5 @@ VgSchedReturnCode VG_(scheduler) ( Threa
before (ie, there's no window that unsafe signals could
sneak in). */
- VG_(sigprocmask)(VKI_SIG_SETMASK, &VG_(blocked_mask), NULL);
+ VG_(block_signals)(tid);
break;
--- valgrind/coregrind/linux/core_os.c #1.6:1.7
@@ -79,34 +79,15 @@ void VGA_(terminate)(ThreadId tid, VgSch
/* wait until all other threads are dead */
+static Bool alldead(void *v)
+{
+ /* master_tid must be alive... */
+ Int c = VG_(count_living_threads)();
+ //VG_(printf)("alldead: count=%d\n", c);
+ return c <= 1;
+}
void VGA_(reap_threads)(ThreadId self)
{
- vki_sigset_t mask;
- vki_sigset_t sigchld;
- vki_siginfo_t si;
-
- /* block everything */
- VG_(sigfillset)(&mask);
- VG_(sigprocmask)(VKI_SIG_SETMASK, &mask, NULL);
-
- /* wait for SIGVGCHLD to show up */
- VG_(sigemptyset)(&sigchld);
- VG_(sigaddset)(&sigchld, VKI_SIGVGCHLD);
-
- vg_assert(VG_(threads)[self].status == VgTs_Runnable);
-
- while(VG_(count_living_threads)() > 1) {
- Int sig;
-
- VG_(set_sleeping)(self, VgTs_WaitSys); /* let other threads run a bit */
- sig = VG_(sigtimedwait)(&sigchld, &si, 0);
- VG_(set_running)(self);
-
- if (sig == -VKI_EINTR)
- continue;
-
- vg_assert(sig == VKI_SIGVGCHLD);
- vg_assert(si.si_signo == VKI_SIGVGCHLD);
- }
- vg_assert(VG_(count_living_threads)() == 1);
+ vg_assert(self == VG_(master_tid));
+ VG_(wait_for_threadstate)(alldead, NULL);
}
@@ -142,5 +123,5 @@ void VGA_(final_tidyup)(ThreadId tid)
/* block all blockable signals... */
- VG_(threads)[tid].sig_mask = VG_(blocked_mask);
+ VG_(sigprocmask)(VKI_SIG_BLOCK, NULL, &VG_(threads)[tid].sig_mask);
/* and restore handlers to default */
--- valgrind/coregrind/x86-linux/syscall.S #1.3:1.4
@@ -149,9 +149,9 @@
Prototype:
- Int VGA_(client_syscall)(Int syscallno, // 0
- arch_thread_t *regs, // 4
- const vki_sigset_t *sysmask, // 8
- const vki_sigset_t *postmask, // 12
- Int nsigwords) // 16
+ Int VGA_(_client_syscall)(Int syscallno, // 0
+ arch_thread_t *regs, // 4
+ const vki_sigset_t *sysmask, // 8
+ vki_sigset_t *postmask, // 12
+ Int nsigwords) // 16
*/
@@ -160,6 +160,6 @@
#define VKI_SIG_SETMASK 2
-.globl VGA_(client_syscall)
-VGA_(client_syscall):
+.globl VGA_(_client_syscall)
+VGA_(_client_syscall):
/* save callee-saved regs */
push %esi
@@ -177,5 +177,5 @@
movl $VKI_SIG_SETMASK, %ebx
movl 8+FSZ(%esp), %ecx
- xorl %edx, %edx
+ movl 12+FSZ(%esp), %edx
movl 16+FSZ(%esp), %esi
int $0x80
--- valgrind/coregrind/x86-linux/syscalls.c #1.18:1.19
@@ -148,4 +148,16 @@ void VGA_(interrupted_syscall)(ThreadId
}
+extern void VGA_(_client_syscall)(Int syscallno, arch_thread_t *regs,
+ const vki_sigset_t *syscall_mask,
+ const vki_sigset_t *restore_mask,
+ Int nsigwords);
+
+void VGA_(client_syscall)(Int syscallno, arch_thread_t *regs,
+ const vki_sigset_t *syscall_mask)
+{
+ vki_sigset_t saved;
+ VGA_(_client_syscall)(syscallno, regs, syscall_mask, &saved, _VKI_NSIG_WORDS * sizeof(UWord));
+}
+
/*
@@ -234,4 +246,8 @@ static Int start_thread(void *arg)
/* Poke the reaper */
+ if (VG_(clo_trace_signals))
+ VG_(message)(Vg_DebugMsg, "Sending SIGVGCHLD to master tid=%d lwp=%d",
+ VG_(master_tid), VG_(threads)[VG_(master_tid)].os_state.lwpid);
+
VG_(tkill)(VG_(threads)[VG_(master_tid)].os_state.lwpid, VKI_SIGVGCHLD);
|