diff options
author | njn <njn@a5019735-40e9-0310-863c-91ae7b9d1cf9> | 2005-03-26 20:08:06 +0000 |
---|---|---|
committer | njn <njn@a5019735-40e9-0310-863c-91ae7b9d1cf9> | 2005-03-26 20:08:06 +0000 |
commit | 03f1e58116abbf9aef5090b34e5bcf39f455ec04 (patch) | |
tree | 3a6a1a0364f29d744f048887435e0e043249214a | |
parent | 4c4d57b1aa7926222572cb3da483b5bc2a94bd0d (diff) |
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 a5019735-40e9-0310-863c-91ae7b9d1cf9
-rw-r--r-- | coregrind/core.h | 6 | ||||
-rw-r--r-- | coregrind/linux/core_os.h | 1 | ||||
-rw-r--r-- | coregrind/linux/syscalls.c | 43 | ||||
-rw-r--r-- | coregrind/vg_syscalls.c | 78 | ||||
-rw-r--r-- | coregrind/x86-linux/syscalls.c | 8 |
5 files changed, 122 insertions, 14 deletions
diff --git a/coregrind/core.h b/coregrind/core.h index 3b47f0fd..8108a12d 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 ce44d448..da159a2f 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 3d0d9ce9..4f340b84 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 46c2d90d..45d3eb60 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 b4f7fc81..ce4f7284 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 |