From: Tom Hughes Date: Sat, 16 Oct 2004 10:59:49 +0000 (+0000) Subject: When signal routing is in use (because we are running on an older kernel X-Git-Tag: svn/VALGRIND_3_0_0~1521 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=76126d1e2b6871b81d4ef5d01cfb1ab385e3b4ad;p=thirdparty%2Fvalgrind.git When signal routing is in use (because we are running on an older kernel that doesn't route signals to the correct threads properly) the siginfo data was not being propagated to any signal handlers installed by the client program. This is because the main thread routes the signal to the proxy LWP by using the tkill system call but that then appears in the proxy as a user initiated signal and the original siginfo data is lost. This patch adds a small queue of siginfo data for pending sigals to each thread's state so that when the proxy LWP passes the signal back to the main thread the relevant siginfo data can be recovered and passed on to any signal handlers. Thix fixes bug 91325. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@2773 --- diff --git a/coregrind/core.h b/coregrind/core.h index 197fe887d4..afc316177a 100644 --- a/coregrind/core.h +++ b/coregrind/core.h @@ -176,6 +176,9 @@ /* Max number of callers for context in a suppression. */ #define VG_N_SUPP_CALLERS 4 +/* Numer of entries in each thread's signal queue. */ +#define VG_N_SIGNALQUEUE 8 + /* Useful macros */ /* a - alignment - must be a power of 2 */ #define ROUNDDN(p, a) ((Addr)(p) & ~((a)-1)) @@ -812,6 +815,15 @@ typedef */ vki_ksigset_t eff_sig_mask; + /* Signal queue. This is used when the kernel doesn't route + signals properly in order to remember the signal information + while we are routing the signal. It is a circular queue with + insertions performed at the head and removals at the tail. + */ + vki_ksiginfo_t sigqueue[VG_N_SIGNALQUEUE]; + Int sigqueue_head; + Int sigqueue_tail; + /* Stacks. When a thread slot is freed, we don't deallocate its stack; we just leave it lying around for the next use of the slot. If the next use of the slot requires a larger stack, diff --git a/coregrind/vg_proxylwp.c b/coregrind/vg_proxylwp.c index 8856444116..de25bc1697 100644 --- a/coregrind/vg_proxylwp.c +++ b/coregrind/vg_proxylwp.c @@ -1153,7 +1153,26 @@ static void sys_wait_results(Bool block, ThreadId tid, enum RequestType reqtype, break; case PX_Signal: - if (VG_(clo_trace_signals) || VG_(clo_trace_syscalls)) + if (VG_(do_signal_routing) && + res.u.siginfo.si_code == VKI_SI_USER && + res.u.siginfo._sifields._kill._pid == VG_(getpid)()) { + Int ptr = tst->sigqueue_tail; + + while (tst->sigqueue[ptr].si_signo != res.u.siginfo.si_signo) { + vg_assert(ptr != tst->sigqueue_head); + ptr = (ptr + 1) % VG_N_SIGNALQUEUE; + } + + res.u.siginfo = tst->sigqueue[ptr]; + tst->sigqueue[ptr].si_signo = 0; + + while (tst->sigqueue_tail != tst->sigqueue_head && + tst->sigqueue[tst->sigqueue_tail].si_signo == 0) { + tst->sigqueue_tail = (tst->sigqueue_tail + 1) % VG_N_SIGNALQUEUE; + } + } + + if (VG_(clo_trace_signals) || VG_(clo_trace_syscalls)) VG_(message)(Vg_DebugMsg, "sys_wait_results: got PX_Signal for TID %d, signal %d", res.tid, res.u.siginfo.si_signo); diff --git a/coregrind/vg_scheduler.c b/coregrind/vg_scheduler.c index 7de3f220fc..1252f7df5a 100644 --- a/coregrind/vg_scheduler.c +++ b/coregrind/vg_scheduler.c @@ -372,6 +372,8 @@ void mostly_clear_thread_record ( ThreadId tid ) VG_(threads)[tid].custack_used = 0; VG_(ksigemptyset)(&VG_(threads)[tid].sig_mask); VG_(ksigfillset)(&VG_(threads)[tid].eff_sig_mask); + VG_(threads)[tid].sigqueue_head = 0; + VG_(threads)[tid].sigqueue_tail = 0; VG_(threads)[tid].specifics_ptr = NULL; VG_(threads)[tid].syscallno = -1; diff --git a/coregrind/vg_signals.c b/coregrind/vg_signals.c index 4d46e48f16..57c146810e 100644 --- a/coregrind/vg_signals.c +++ b/coregrind/vg_signals.c @@ -1918,6 +1918,7 @@ void VG_(route_signals)(void) static const struct vki_timespec zero = { 0, 0 }; static ThreadId start_tid = 1; /* tid to start scanning from */ vki_ksigset_t set; + vki_ksiginfo_t siset[VKI_KNSIG]; vki_ksiginfo_t si; Int sigNo; @@ -1933,8 +1934,10 @@ void VG_(route_signals)(void) VG_(block_all_host_signals) ( &set ); /* grab any pending signals and add them to the pending signal set */ - while(VG_(ksigtimedwait)(&set, &si, &zero) > 0) + while(VG_(ksigtimedwait)(&set, &si, &zero) > 0) { VG_(ksigaddset)(&proc_pending, si.si_signo); + siset[si.si_signo] = si; + } /* transfer signals from the process pending set to a particular thread which has it unblocked */ @@ -1969,9 +1972,13 @@ void VG_(route_signals)(void) /* found one - deliver it and be done */ if (target != -1) { + ThreadState *tst = &VG_(threads)[target]; if (VG_(clo_trace_signals)) VG_(message)(Vg_DebugMsg, "Routing signal %d to tid %d", sigNo, tid); + tst->sigqueue[tst->sigqueue_head] = siset[sigNo]; + tst->sigqueue_head = (tst->sigqueue_head + 1) % VG_N_SIGNALQUEUE; + vg_assert(tst->sigqueue_head != tst->sigqueue_tail); VG_(proxy_sendsig)(target, sigNo); VG_(ksigdelset)(&proc_pending, sigNo); }