diff --git a/coregrind/core.h b/coregrind/core.h index 0c7d2cec4..40ba16175 100644 --- a/coregrind/core.h +++ b/coregrind/core.h @@ -345,7 +345,10 @@ extern VgSchedReturnCode VG_(scheduler) ( ThreadId tid ); // Do everything which needs doing before the process finally ends, // like printing reports, etc -extern void VG_(shutdown_actions)(ThreadId tid); +extern void VG_(shutdown_actions_NORETURN) ( + ThreadId tid, + VgSchedReturnCode tids_schedretcode + ); extern void VG_(scheduler_init) ( void ); @@ -524,12 +527,6 @@ extern Int VG_(clexecfd); Char* VG_(build_child_VALGRINDCLO) ( Char* exename ); Char* VG_(build_child_exename) ( void ); -/* The master thread the one which will be responsible for mopping - everything up at exit. Normally it is tid 1, since that's the - first thread created, but it may be something else after a - fork(). */ -extern ThreadId VG_(master_tid); - /* Called when some unhandleable client behaviour is detected. Prints a msg and aborts. */ extern void VG_(unimplemented) ( Char* msg ) @@ -608,21 +605,23 @@ extern void /*MOD*/ ThreadArchState* arch ); // OS/Platform-specific thread clear (after thread exit) -extern void VGA_(os_state_clear)(ThreadState *); +extern void VGO_(os_state_clear)(ThreadState *); // OS/Platform-specific thread init (at scheduler init time) -extern void VGA_(os_state_init)(ThreadState *); +extern void VGO_(os_state_init)(ThreadState *); -// Run a thread from beginning to end. Does not return if tid == VG_(master_tid). -void VGA_(thread_wrapper)(Word /*ThreadId*/ tid); +// Run a thread from beginning to end. +extern VgSchedReturnCode VGO_(thread_wrapper)(Word /*ThreadId*/ tid); -// Like VGA_(thread_wrapper), but it allocates a stack before calling -// to VGA_(thread_wrapper) on that stack, as if it had been set up by -// clone() -void VGA_(main_thread_wrapper)(ThreadId tid) __attribute__ ((__noreturn__)); +// Call here to exit the entire Valgrind system. +extern void VGO_(terminate_NORETURN)(ThreadId tid, VgSchedReturnCode src); + +// Allocates a stack for the first thread, then runs it, +// as if the thread had been set up by clone() +extern void VGP_(main_thread_wrapper_NORETURN)(ThreadId tid); // Return how many bytes of a thread's Valgrind stack are unused -SSizeT VGA_(stack_unused)(ThreadId tid); +extern SSizeT VGA_(stack_unused)(ThreadId tid); // wait until all other threads are dead extern void VGA_(reap_threads)(ThreadId self); diff --git a/coregrind/linux/core_os.c b/coregrind/linux/core_os.c index ef87b5974..5247db38a 100644 --- a/coregrind/linux/core_os.c +++ b/coregrind/linux/core_os.c @@ -29,26 +29,37 @@ */ #include "core.h" +#include "pub_core_debuglog.h" #include "pub_core_options.h" #include "pub_core_tooliface.h" -void VGA_(os_state_clear)(ThreadState *tst) +void VGO_(os_state_clear)(ThreadState *tst) { tst->os_state.lwpid = 0; tst->os_state.threadgroup = 0; } -void VGA_(os_state_init)(ThreadState *tst) +void VGO_(os_state_init)(ThreadState *tst) { tst->os_state.valgrind_stack_base = 0; tst->os_state.valgrind_stack_szB = 0; - VGA_(os_state_clear)(tst); + VGO_(os_state_clear)(tst); } -static void terminate(ThreadId tid, VgSchedReturnCode src) +static Bool i_am_the_only_thread ( void ) { - vg_assert(tid == VG_(master_tid)); + Int c = VG_(count_living_threads)(); + vg_assert(c >= 1); /* stay sane */ + return c == 1; +} + + +void VGO_(terminate_NORETURN)(ThreadId tid, VgSchedReturnCode src) +{ + VG_(debugLog)(1, "core_os", + "VGO_(terminate_NORETURN)(tid=%lld)\n", (ULong)tid); + vg_assert(VG_(count_living_threads)() == 0); //-------------------------------------------------------------- @@ -56,15 +67,15 @@ static void terminate(ThreadId tid, VgSchedReturnCode src) //-------------------------------------------------------------- switch (src) { case VgSrc_ExitSyscall: /* the normal way out */ - VG_(exit)( VG_(threads)[VG_(master_tid)].os_state.exitcode ); + VG_(exit)( VG_(threads)[tid].os_state.exitcode ); /* NOT ALIVE HERE! */ VG_(core_panic)("entered the afterlife in main() -- ExitSyscall"); break; /* what the hell :) */ case VgSrc_FatalSig: /* We were killed by a fatal signal, so replicate the effect */ - vg_assert(VG_(threads)[VG_(master_tid)].os_state.fatalsig != 0); - VG_(kill_self)(VG_(threads)[VG_(master_tid)].os_state.fatalsig); + vg_assert(VG_(threads)[tid].os_state.fatalsig != 0); + VG_(kill_self)(VG_(threads)[tid].os_state.fatalsig); VG_(core_panic)("main(): signal was supposed to be fatal"); break; @@ -73,9 +84,16 @@ static void terminate(ThreadId tid, VgSchedReturnCode src) } } -/* Run a thread from beginning to end. Does not return. */ -void VGA_(thread_wrapper)(Word /*ThreadId*/ tidW) + +/* Run a thread from beginning to end and return the thread's + scheduler-return-code. */ + +VgSchedReturnCode VGO_(thread_wrapper)(Word /*ThreadId*/ tidW) { + VG_(debugLog)(1, "core_os", + "VGO_(thread_wrapper)(tid=%lld): entry\n", + (ULong)tidW); + VgSchedReturnCode ret; ThreadId tid = (ThreadId)tidW; ThreadState* tst = VG_(get_ThreadState)(tid); @@ -103,79 +121,24 @@ void VGA_(thread_wrapper)(Word /*ThreadId*/ tidW) vg_assert(tst->status == VgTs_Runnable); vg_assert(VG_(is_running_thread)(tid)); - - if (tid == VG_(master_tid)) { - VG_(shutdown_actions)(tid); - terminate(tid, ret); - } + + VG_(debugLog)(1, "core_os", + "VGO_(thread_wrapper)(tid=%lld): done\n", + (ULong)tidW); + + /* Return to caller, still holding the lock. */ + return ret; } -/* 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; -} - -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. - */ -static void 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)); -} +/* Wait until all other threads disappear. */ void VGA_(reap_threads)(ThreadId self) { - vg_assert(self == VG_(master_tid)); - wait_for_threadstate(alldead, NULL); + while (!i_am_the_only_thread()) { + /* Let other thread(s) run */ + VG_(vg_yield)(); + } + vg_assert(i_am_the_only_thread()); } /* The we need to know the address of it so it can be diff --git a/coregrind/m_syscalls/syscalls-x86-linux.c b/coregrind/m_syscalls/syscalls-x86-linux.c index c046978be..f5dc57d1e 100644 --- a/coregrind/m_syscalls/syscalls-x86-linux.c +++ b/coregrind/m_syscalls/syscalls-x86-linux.c @@ -35,6 +35,7 @@ #include "core.h" #include "ume.h" /* for jmp_with_stack */ +#include "pub_core_debuglog.h" #include "pub_core_aspacemgr.h" #include "pub_core_sigframe.h" #include "pub_core_syscalls.h" @@ -244,64 +245,116 @@ SSizeT VGA_(stack_unused)(ThreadId tid) return ((Addr)p) - tst->os_state.valgrind_stack_base; } -/* - Allocate a stack for the main thread, and call VGA_(thread_wrapper) - on that stack. - */ -void VGA_(main_thread_wrapper)(ThreadId tid) + +/* Run a thread all the way to the end, then do appropriate exit actions + (this is the last-one-out-turn-off-the-lights bit). +*/ +static void run_a_thread_NORETURN ( Word tidW ) { + ThreadId tid = (ThreadId)tidW; + + VG_(debugLog)(1, "syscalls-x86-linux", + "run_a_thread_NORETURN(tid=%lld): " + "VGO_(thread_wrapper) called\n", + (ULong)tidW); + + /* Run the thread all the way through. */ + VgSchedReturnCode src = VGO_(thread_wrapper)(tid); + + VG_(debugLog)(1, "syscalls-x86-linux", + "run_a_thread_NORETURN(tid=%lld): " + "VGO_(thread_wrapper) done\n", + (ULong)tidW); + + Int c = VG_(count_living_threads)(); + vg_assert(c >= 1); /* stay sane */ + + if (c == 1) { + + VG_(debugLog)(1, "syscalls-x86-linux", + "run_a_thread_NORETURN(tid=%lld): " + "last one standing\n", + (ULong)tidW); + + /* We are the last one standing. Keep hold of the lock and + carry on to show final tool results, then exit the entire system. */ + VG_(shutdown_actions_NORETURN)(tid, src); + + } else { + + VG_(debugLog)(1, "syscalls-x86-linux", + "run_a_thread_NORETURN(tid=%lld): " + "not last one standing\n", + (ULong)tidW); + + /* OK, thread is dead, but others still exist. Just exit. */ + ThreadState *tst = VG_(get_ThreadState)(tid); + + /* This releases the run lock */ + VG_(exit_thread)(tid); + vg_assert(tst->status == VgTs_Zombie); + + /* We have to use this sequence to terminate the thread to + prevent a subtle race. If VG_(exit_thread)() had left the + ThreadState as Empty, then it could have been reallocated, + reusing the stack while we're doing these last cleanups. + Instead, VG_(exit_thread) leaves it as Zombie to prevent + reallocation. We need to make sure we don't touch the stack + between marking it Empty and exiting. Hence the + assembler. */ + asm volatile ( + "movl %1, %0\n" /* set tst->status = VgTs_Empty */ + "movl %2, %%eax\n" /* set %eax = __NR_exit */ + "movl %3, %%ebx\n" /* set %ebx = tst->os_state.exitcode */ + "int $0x80\n" /* exit(tst->os_state.exitcode) */ + : "=m" (tst->status) + : "n" (VgTs_Empty), "n" (__NR_exit), "m" (tst->os_state.exitcode)); + + VG_(core_panic)("Thread exit failed?\n"); + } + + /*NOTREACHED*/ + vg_assert(0); +} + + +/* + Allocate a stack for the main thread, and run it all the way to the + end. +*/ +void VGP_(main_thread_wrapper_NORETURN)(ThreadId tid) +{ + VG_(debugLog)(1, "syscalls-x86-linux", + "entering VGP_(main_thread_wrapper_NORETURN)\n"); + UWord* esp = allocstack(tid); - vg_assert(tid == VG_(master_tid)); + /* shouldn't be any other threads around yet */ + vg_assert( VG_(count_living_threads)() == 1 ); call_on_new_stack_0_1( - (Addr)esp, /* stack */ - 0, /*bogus return address*/ - VGA_(thread_wrapper), /* fn to call */ - (Word)tid /* arg to give it */ + (Addr)esp, /* stack */ + 0, /*bogus return address*/ + run_a_thread_NORETURN, /* fn to call */ + (Word)tid /* arg to give it */ ); /*NOTREACHED*/ vg_assert(0); } -static Int start_thread(void *arg) + +static Int start_thread_NORETURN ( void* arg ) { - ThreadState *tst = (ThreadState *)arg; - ThreadId tid = tst->tid; + ThreadState* tst = (ThreadState*)arg; + ThreadId tid = tst->tid; - VGA_(thread_wrapper)(tid); - - /* OK, thread is dead; this releases the run lock */ - VG_(exit_thread)(tid); - - vg_assert(tst->status == VgTs_Zombie); - - /* 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); - - /* We have to use this sequence to terminate the thread to prevent - a subtle race. If VG_(exit_thread)() had left the ThreadState - as Empty, then it could have been reallocated, reusing the stack - while we're doing these last cleanups. Instead, - VG_(exit_thread) leaves it as Zombie to prevent reallocation. - We need to make sure we don't touch the stack between marking it - Empty and exiting. Hence the assembler. */ - asm volatile ( - "movl %1, %0\n" /* set tst->status = VgTs_Empty */ - "movl %2, %%eax\n" /* set %eax = __NR_exit */ - "movl %3, %%ebx\n" /* set %ebx = tst->os_state.exitcode */ - "int $0x80\n" /* exit(tst->os_state.exitcode) */ - : "=m" (tst->status) - : "n" (VgTs_Empty), "n" (__NR_exit), "m" (tst->os_state.exitcode)); - - VG_(core_panic)("Thread exit failed?\n"); + run_a_thread_NORETURN ( (Word)tid ); + /*NOTREACHED*/ + vg_assert(0); } + /* --------------------------------------------------------------------- clone() handling ------------------------------------------------------------------ */ @@ -404,7 +457,7 @@ static Int do_clone(ThreadId ptid, VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, &savedmask); /* Create the new thread */ - ret = VG_(clone)(start_thread, stack, flags, &VG_(threads)[ctid], + ret = VG_(clone)(start_thread_NORETURN, stack, flags, &VG_(threads)[ctid], child_tidptr, parent_tidptr, NULL); VG_(sigprocmask)(VKI_SIG_SETMASK, &savedmask, NULL); @@ -1470,7 +1523,7 @@ const struct SyscallTableEntry VGA_(syscall_table)[] = { GENX_(__NR_chroot, sys_chroot), // 61 // (__NR_ustat, sys_ustat) // 62 SVr4 -- deprecated GENXY(__NR_dup2, sys_dup2), // 63 - GENXY(__NR_getppid, sys_getppid), // 64 + GENX_(__NR_getppid, sys_getppid), // 64 GENX_(__NR_getpgrp, sys_getpgrp), // 65 GENX_(__NR_setsid, sys_setsid), // 66 diff --git a/coregrind/m_syscalls/syscalls.c b/coregrind/m_syscalls/syscalls.c index e65aaab4b..ce917a9be 100644 --- a/coregrind/m_syscalls/syscalls.c +++ b/coregrind/m_syscalls/syscalls.c @@ -2345,27 +2345,17 @@ PRE(sys_execve, Special) /* Resistance is futile. Nuke all other threads. POSIX mandates this. (Really, nuke them all, since the new process will make its own new thread.) */ - VG_(master_tid) = tid; /* become the master */ VG_(nuke_all_threads_except)( tid, VgSrc_ExitSyscall ); VGA_(reap_threads)(tid); - if (0) { - /* Shut down cleanly and report final state - XXX Is this reasonable? */ - tst->exitreason = VgSrc_ExitSyscall; - VG_(shutdown_actions)(tid); - } - - { - // Remove the valgrind-specific stuff from the environment so the - // child doesn't get vg_inject.so, vgpreload.so, etc. This is - // done unconditionally, since if we are tracing the child, - // stage1/2 will set up the appropriate client environment. - Char** envp = (Char**)ARG3; - - if (envp != NULL) { - VG_(env_remove_valgrind_env_stuff)( envp ); - } + { // Remove the valgrind-specific stuff from the environment so the + // child doesn't get vg_inject.so, vgpreload.so, etc. This is + // done unconditionally, since if we are tracing the child, + // stage1/2 will set up the appropriate client environment. + Char** envp = (Char**)ARG3; + if (envp != NULL) { + VG_(env_remove_valgrind_env_stuff)( envp ); + } } if (VG_(clo_trace_children)) { @@ -2952,16 +2942,6 @@ PRE(sys_getppid, 0) PRE_REG_READ0(long, "getppid"); } -POST(sys_getppid) -{ - /* If the master thread has already exited, and it is this thread's - parent, then force getppid to return 1 (init) rather than the - real ppid, so that it thinks its parent has exited. */ - if (VG_(threads)[VG_(master_tid)].os_state.lwpid == RES && - VG_(is_exiting)(VG_(master_tid))) - RES = 1; -} - static void common_post_getrlimit(ThreadId tid, UWord a1, UWord a2) { POST_MEM_WRITE( a2, sizeof(struct vki_rlimit) ); @@ -6068,15 +6048,6 @@ static void sanitize_client_sigmask(ThreadId tid, vki_sigset_t *mask) VG_(sigdelset)(mask, VKI_SIGSTOP); VG_(sigdelset)(mask, VKI_SIGVGKILL); /* never 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); } void VG_(client_syscall) ( ThreadId tid ) diff --git a/coregrind/vg_main.c b/coregrind/vg_main.c index f181423cb..f026ed67a 100644 --- a/coregrind/vg_main.c +++ b/coregrind/vg_main.c @@ -137,12 +137,6 @@ const Char *VG_(libdir) = VG_LIBDIR; static Int vg_argc; static Char **vg_argv; -/* The master thread the one which will be responsible for mopping - everything up at exit. Normally it is tid 1, since that's the - first thread created, but it may be something else after a - fork(). */ -ThreadId VG_(master_tid) = VG_INVALID_THREADID; - /* Application-visible file descriptor limits */ Int VG_(fd_soft_limit) = -1; Int VG_(fd_hard_limit) = -1; @@ -2817,24 +2811,29 @@ int main(int argc, char **argv, char **envp) //-------------------------------------------------------------- VGP_POPCC(VgpStartup); - vg_assert(VG_(master_tid) == 1); - if (VG_(clo_xml)) { VG_(message)(Vg_UserMsg, "RUNNING"); VG_(message)(Vg_UserMsg, ""); } VG_(debugLog)(1, "main", "Running thread 1\n"); - VGA_(main_thread_wrapper)(1); + /* As a result of the following call, the last thread standing + eventually winds up running VG_(shutdown_actions_NORETURN) just + below. */ + VGP_(main_thread_wrapper_NORETURN)(1); - abort(); + /*NOTREACHED*/ + vg_assert(0); } /* Do everything which needs doing when the last thread exits */ -void VG_(shutdown_actions)(ThreadId tid) +void VG_(shutdown_actions_NORETURN) ( ThreadId tid, + VgSchedReturnCode tids_schedretcode ) { - vg_assert(tid == VG_(master_tid)); + VG_(debugLog)(1, "main", "entering VG_(shutdown_actions_NORETURN)\n"); + + vg_assert( VG_(count_living_threads)() == 1 ); vg_assert(VG_(is_running_thread)(tid)); // Wait for all other threads to exit. @@ -2896,6 +2895,12 @@ void VG_(shutdown_actions)(ThreadId tid) /* Print Vex storage stats */ if (0) LibVEX_ShowAllocStats(); + + /* Ok, finally exit in the os-specific way. In short, if the + (last) thread exited by calling sys_exit, do likewise; if the + (last) thread stopped due to a fatal signal, terminate the + entire system with that same fatal signal. */ + VGO_(terminate_NORETURN)( tid, tids_schedretcode ); } /*--------------------------------------------------------------------*/ diff --git a/coregrind/vg_scheduler.c b/coregrind/vg_scheduler.c index 50b3c2d0c..4ddf9d3fc 100644 --- a/coregrind/vg_scheduler.c +++ b/coregrind/vg_scheduler.c @@ -439,10 +439,6 @@ static void block_signals(ThreadId tid) 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); } @@ -566,7 +562,7 @@ void mostly_clear_thread_record ( ThreadId tid ) VG_(sigemptyset)(&VG_(threads)[tid].sig_mask); VG_(sigemptyset)(&VG_(threads)[tid].tmp_sig_mask); - VGA_(os_state_clear)(&VG_(threads)[tid]); + VGO_(os_state_clear)(&VG_(threads)[tid]); /* start with no altstack */ VG_(threads)[tid].altstack.ss_sp = (void *)0xdeadbeef; @@ -600,8 +596,6 @@ static void sched_fork_cleanup(ThreadId me) ThreadId tid; vg_assert(running_tid == me); - VG_(master_tid) = me; - VG_(threads)[me].os_state.lwpid = VG_(gettid)(); VG_(threads)[me].os_state.threadgroup = VG_(getpid)(); @@ -635,7 +629,7 @@ void VG_(scheduler_init) ( void ) for (i = 0 /* NB; not 1 */; i < VG_N_THREADS; i++) { VG_(threads)[i].sig_queue = NULL; - VGA_(os_state_init)(&VG_(threads)[i]); + VGO_(os_state_init)(&VG_(threads)[i]); mostly_clear_thread_record(i); VG_(threads)[i].status = VgTs_Empty; @@ -645,8 +639,6 @@ void VG_(scheduler_init) ( void ) tid_main = VG_(alloc_ThreadState)(); - VG_(master_tid) = tid_main; - /* Initial thread's stack is the original process stack */ VG_(threads)[tid_main].client_stack_highest_word = VG_(clstk_end) - sizeof(UWord); diff --git a/coregrind/vg_signals.c b/coregrind/vg_signals.c index 24f816fcd..326de2470 100644 --- a/coregrind/vg_signals.c +++ b/coregrind/vg_signals.c @@ -303,8 +303,6 @@ void calculate_SKSS_from_SCSS ( SKSS* dst ) // cases in the switch, so we handle them in the 'default' case. if (sig == VKI_SIGVGKILL) skss_handler = sigvgkill_handler; - else if (sig == VKI_SIGVGCHLD) - skss_handler = VKI_SIG_IGN; /* we only poll for it */ else { if (scss_handler == VKI_SIG_IGN) skss_handler = VKI_SIG_IGN; @@ -1358,7 +1356,8 @@ static void default_action(const vki_siginfo_t *info, ThreadId tid) #endif /* stash fatal signal in main thread */ - VG_(threads)[VG_(master_tid)].os_state.fatalsig = sigNo; + // what's this for? + //VG_(threads)[VG_(master_tid)].os_state.fatalsig = sigNo; /* everyone dies */ VG_(nuke_all_threads_except)(tid, VgSrc_FatalSig); @@ -1884,8 +1883,10 @@ void sync_signalhandler ( Int sigNo, vki_siginfo_t *info, struct vki_ucontext *u if (0) VG_(kill_self)(sigNo); /* generate a core dump */ - if (tid == 0) /* could happen after everyone has exited */ - tid = VG_(master_tid); + //if (tid == 0) /* could happen after everyone has exited */ + // tid = VG_(master_tid); + vg_assert(tid != 0); + tst = VG_(get_ThreadState)(tid); VG_(get_StackTrace2)(ips, VG_(clo_backtrace_size), VGP_UCONTEXT_INSTR_PTR(uc), @@ -1967,8 +1968,6 @@ void VG_(poll_signals)(ThreadId tid) for(i = 0; i < _VKI_NSIG_WORDS; i++) pollset.sig[i] = ~tst->sig_mask.sig[i]; - VG_(sigdelset)(&pollset, VKI_SIGVGCHLD); /* already dealt with */ - //VG_(printf)("tid %d pollset=%08x%08x\n", tid, pollset.sig[1], pollset.sig[0]); block_all_host_signals(&saved_mask); // protect signal queue @@ -2063,18 +2062,17 @@ void VG_(sigstartup_actions) ( void ) VG_(message)(Vg_DebugMsg, "Max kernel-supported signal is %d", VG_(max_signal)); /* Our private internal signals are treated as ignored */ - scss.scss_per_sig[VKI_SIGVGCHLD].scss_handler = VKI_SIG_IGN; - scss.scss_per_sig[VKI_SIGVGCHLD].scss_flags = VKI_SA_SIGINFO; - VG_(sigfillset)(&scss.scss_per_sig[VKI_SIGVGCHLD].scss_mask); - scss.scss_per_sig[VKI_SIGVGKILL].scss_handler = VKI_SIG_IGN; scss.scss_per_sig[VKI_SIGVGKILL].scss_flags = VKI_SA_SIGINFO; VG_(sigfillset)(&scss.scss_per_sig[VKI_SIGVGKILL].scss_mask); /* Copy the process' signal mask into the root thread. */ - vg_assert(VG_(threads)[VG_(master_tid)].status == VgTs_Init); - VG_(threads)[VG_(master_tid)].sig_mask = saved_procmask; - VG_(threads)[VG_(master_tid)].tmp_sig_mask = saved_procmask; + vg_assert(VG_(threads)[1].status == VgTs_Init); + for (i = 2; i < VG_N_THREADS; i++) + vg_assert(VG_(threads)[i].status == VgTs_Empty); + + VG_(threads)[1].sig_mask = saved_procmask; + VG_(threads)[1].tmp_sig_mask = saved_procmask; /* Calculate SKSS and apply it. This also sets the initial kernel mask we need to run with. */ diff --git a/include/vki-linux.h b/include/vki-linux.h index d23c75f34..30b695cad 100644 --- a/include/vki-linux.h +++ b/include/vki-linux.h @@ -351,8 +351,7 @@ struct vki_sched_param { /* Use high signals because native pthreads wants to use low */ #define VKI_SIGVGKILL (VG_(max_signal)-0) // [[internal: kill]] -#define VKI_SIGVGCHLD (VG_(max_signal)-1) // [[internal: thread death]] -#define VKI_SIGVGRTUSERMAX (VG_(max_signal)-2) // [[internal: last user-usable RT signal]] +#define VKI_SIGVGRTUSERMAX (VG_(max_signal)-1) // [[internal: last user-usable RT signal]] //---------------------------------------------------------------------- // From linux-2.6.8.1/include/asm-generic/siginfo.h