summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornjn <njn@a5019735-40e9-0310-863c-91ae7b9d1cf9>2005-03-26 20:08:06 +0000
committernjn <njn@a5019735-40e9-0310-863c-91ae7b9d1cf9>2005-03-26 20:08:06 +0000
commit03f1e58116abbf9aef5090b34e5bcf39f455ec04 (patch)
tree3a6a1a0364f29d744f048887435e0e043249214a
parent4c4d57b1aa7926222572cb3da483b5bc2a94bd0d (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.h6
-rw-r--r--coregrind/linux/core_os.h1
-rw-r--r--coregrind/linux/syscalls.c43
-rw-r--r--coregrind/vg_syscalls.c78
-rw-r--r--coregrind/x86-linux/syscalls.c8
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