From: Nicholas Nethercote Date: Sat, 26 Mar 2005 20:08:06 +0000 (+0000) Subject: The two patches attached resolve the exit-hang (of OOo) bug for me. The first X-Git-Tag: svn/VALGRIND_3_0_0~869 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=d5717b3e8ceec92cbd81663e83e0aa2cdb971f29;p=thirdparty%2Fvalgrind.git The two patches attached resolve the exit-hang (of OOo) bug for me. The first fixes getppid(), and the second fixes the next bug which is revealed once getppid() does what LinuxThreads wants; LinuxThreads uses SIGKILL to kill off stray threads, but if we send naked SIGKILLs to Valgrind threads, they'll die without cleaning up or informing anyone of their death, which means that they're waited on forever. ADAPTED FROM CVS HEAD git-svn-id: svn://svn.valgrind.org/valgrind/trunk@3449 --- diff --git a/coregrind/core.h b/coregrind/core.h index 3b47f0fd85..8108a12dba 100644 --- a/coregrind/core.h +++ b/coregrind/core.h @@ -1134,6 +1134,10 @@ Bool VG_(valid_client_addr)(Addr start, SizeT size, ThreadId tid, Bool VG_(fd_allowed)(Int fd, const Char *syscallname, ThreadId tid, Bool soft); void VG_(record_fd_open)(ThreadId tid, Int fd, char *pathname); + +// Used when killing threads -- we must not kill a thread if it's the thread +// that would do Valgrind's final cleanup and output. +Bool VG_(do_sigkill)(Int pid, Int tgid); // Flags describing syscall wrappers #define Special (1 << 0) /* handled specially */ @@ -1413,8 +1417,6 @@ GEN_SYSCALL_WRAPPER(sys_mq_timedsend); // * P? GEN_SYSCALL_WRAPPER(sys_mq_timedreceive); // * P? GEN_SYSCALL_WRAPPER(sys_mq_notify); // * P? GEN_SYSCALL_WRAPPER(sys_mq_getsetattr); // * P? -GEN_SYSCALL_WRAPPER(sys_tkill); // * L -GEN_SYSCALL_WRAPPER(sys_tgkill); // * L GEN_SYSCALL_WRAPPER(sys_gettid); // * L? #undef GEN_SYSCALL_WRAPPER diff --git a/coregrind/linux/core_os.h b/coregrind/linux/core_os.h index ce44d4486f..da159a2fa0 100644 --- a/coregrind/linux/core_os.h +++ b/coregrind/linux/core_os.h @@ -82,6 +82,7 @@ VGO_LINUX_SYSCALL_WRAPPER(sys_epoll_create); VGO_LINUX_SYSCALL_WRAPPER(sys_epoll_ctl); VGO_LINUX_SYSCALL_WRAPPER(sys_epoll_wait); +VGO_LINUX_SYSCALL_WRAPPER(sys_tkill); VGO_LINUX_SYSCALL_WRAPPER(sys_tgkill); VGO_LINUX_SYSCALL_WRAPPER(sys_io_setup); diff --git a/coregrind/linux/syscalls.c b/coregrind/linux/syscalls.c index 3d0d9ce9e6..4f340b8453 100644 --- a/coregrind/linux/syscalls.c +++ b/coregrind/linux/syscalls.c @@ -503,13 +503,52 @@ POST(sys_epoll_wait) POST_MEM_WRITE( ARG2, sizeof(struct epoll_event)*RES ) ; } -PRE(sys_tgkill, 0) +PRE(sys_tkill, Special) +{ + /* int tkill(pid_t tid, int sig); */ + PRINT("sys_tkill ( %d, %d )", ARG1,ARG2); + PRE_REG_READ2(long, "tkill", int, tid, int, sig); + if (!VG_(client_signal_OK)(ARG2)) { + SET_RESULT( -VKI_EINVAL ); + return; + } + + /* If we're sending SIGKILL, check to see if the target is one of + our threads and handle it specially. */ + if (ARG2 == VKI_SIGKILL && VG_(do_sigkill)(ARG1, -1)) + SET_RESULT(0); + else + SET_RESULT(VG_(do_syscall2)(SYSNO, ARG1, ARG2)); + + if (VG_(clo_trace_signals)) + VG_(message)(Vg_DebugMsg, "tkill: sent signal %d to pid %d", + ARG2, ARG1); + // Check to see if this kill gave us a pending signal + VG_(poll_signals)(tid); +} + +PRE(sys_tgkill, Special) { /* int tgkill(pid_t tgid, pid_t tid, int sig); */ PRINT("sys_tgkill ( %d, %d, %d )", ARG1,ARG2,ARG3); PRE_REG_READ3(long, "tgkill", int, tgid, int, tid, int, sig); - if (!VG_(client_signal_OK)(ARG3)) + if (!VG_(client_signal_OK)(ARG3)) { SET_RESULT( -VKI_EINVAL ); + return; + } + + /* If we're sending SIGKILL, check to see if the target is one of + our threads and handle it specially. */ + if (ARG3 == VKI_SIGKILL && VG_(do_sigkill)(ARG2, ARG1)) + SET_RESULT(0); + else + SET_RESULT(VG_(do_syscall3)(SYSNO, ARG1, ARG2, ARG3)); + + if (VG_(clo_trace_signals)) + VG_(message)(Vg_DebugMsg, "tgkill: sent signal %d to pid %d/%d", + ARG3, ARG1, ARG2); + // Check to see if this kill gave us a pending signal + VG_(poll_signals)(tid); } POST(sys_tgkill) diff --git a/coregrind/vg_syscalls.c b/coregrind/vg_syscalls.c index 46c2d90d3a..45d3eb60ea 100644 --- a/coregrind/vg_syscalls.c +++ b/coregrind/vg_syscalls.c @@ -2946,6 +2946,16 @@ 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) ); @@ -4319,20 +4329,76 @@ POST(sys_ioctl) } } -PRE(sys_kill, 0) +/* + If we're sending a SIGKILL to one of our own threads, then simulate + it rather than really sending the signal, so that the target thread + gets a chance to clean up. Returns True if we did the killing (or + no killing is necessary), and False if the caller should use the + normal kill syscall. + + "pid" is any pid argument which can be passed to kill; group kills + (< -1, 0), and owner kills (-1) are ignored, on the grounds that + they'll most likely hit all the threads and we won't need to worry + about cleanup. In truth, we can't fully emulate these multicast + kills. + + "tgid" is a thread group id. If it is not -1, then the target + thread must be in that thread group. + */ +Bool VG_(do_sigkill)(Int pid, Int tgid) +{ + ThreadState *tst; + ThreadId tid; + + if (pid <= 0) + return False; + + tid = VG_(get_lwp_tid)(pid); + if (tid == VG_INVALID_THREADID) + return False; /* none of our threads */ + + tst = VG_(get_ThreadState)(tid); + if (tst == NULL || tst->status == VgTs_Empty) + return False; /* hm, shouldn't happen */ + + if (tgid != -1 && tst->os_state.threadgroup != tgid) + return False; /* not the right thread group */ + + /* Check to see that the target isn't already exiting. */ + if (!VG_(is_exiting)(tid)) { + if (VG_(clo_trace_signals)) + VG_(message)(Vg_DebugMsg, "Thread %d being killed with SIGKILL", tst->tid); + + tst->exitreason = VgSrc_FatalSig; + tst->os_state.fatalsig = VKI_SIGKILL; + + if (!VG_(is_running_thread)(tid)) + VG_(kill_thread)(tid); + } + + return True; +} + +PRE(sys_kill, Special) { /* int kill(pid_t pid, int sig); */ PRINT("sys_kill ( %d, %d )", ARG1,ARG2); PRE_REG_READ2(long, "kill", int, pid, int, sig); - if (!VG_(client_signal_OK)(ARG2)) + if (!VG_(client_signal_OK)(ARG2)) { SET_RESULT( -VKI_EINVAL ); -} + return; + } + + /* If we're sending SIGKILL, check to see if the target is one of + our threads and handle it specially. */ + if (ARG2 == VKI_SIGKILL && VG_(do_sigkill)(ARG1, -1)) + SET_RESULT(0); + else + SET_RESULT(VG_(do_syscall2)(SYSNO, ARG1, ARG2)); -POST(sys_kill) -{ if (VG_(clo_trace_signals)) VG_(message)(Vg_DebugMsg, "kill: sent signal %d to pid %d", - ARG2, ARG1); + ARG2, ARG1); // Check to see if this kill gave us a pending signal VG_(poll_signals)(tid); } diff --git a/coregrind/x86-linux/syscalls.c b/coregrind/x86-linux/syscalls.c index b4f7fc8182..ce4f72846c 100644 --- a/coregrind/x86-linux/syscalls.c +++ b/coregrind/x86-linux/syscalls.c @@ -1017,7 +1017,7 @@ const struct SyscallTableEntry VGA_(syscall_table)[] = { GENX_(__NR_ftime, sys_ni_syscall), // 35 GENX_(__NR_sync, sys_sync), // 36 - GENXY(__NR_kill, sys_kill), // 37 + GENX_(__NR_kill, sys_kill), // 37 GENX_(__NR_rename, sys_rename), // 38 GENX_(__NR_mkdir, sys_mkdir), // 39 @@ -1049,7 +1049,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 - GENX_(__NR_getppid, sys_getppid), // 64 + GENXY(__NR_getppid, sys_getppid), // 64 GENX_(__NR_getpgrp, sys_getpgrp), // 65 GENX_(__NR_setsid, sys_setsid), // 66 @@ -1261,7 +1261,7 @@ const struct SyscallTableEntry VGA_(syscall_table)[] = { GENX_(__NR_removexattr, sys_removexattr), // 235 GENX_(__NR_lremovexattr, sys_lremovexattr), // 236 GENX_(__NR_fremovexattr, sys_fremovexattr), // 237 - // (__NR_tkill, sys_tkill), // 238 */Linux + LINX_(__NR_tkill, sys_tkill), // 238 */Linux LINXY(__NR_sendfile64, sys_sendfile64), // 239 LINXY(__NR_futex, sys_futex), // 240 @@ -1300,7 +1300,7 @@ const struct SyscallTableEntry VGA_(syscall_table)[] = { GENXY(__NR_statfs64, sys_statfs64), // 268 GENXY(__NR_fstatfs64, sys_fstatfs64), // 269 - LINXY(__NR_tgkill, sys_tgkill), // 270 */Linux + LINX_(__NR_tgkill, sys_tgkill), // 270 */Linux GENX_(__NR_utimes, sys_utimes), // 271 // (__NR_fadvise64_64, sys_fadvise64_64), // 272 */(Linux?) GENX_(__NR_vserver, sys_ni_syscall), // 273