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
This commit is contained in:
Nicholas Nethercote 2005-03-26 20:08:06 +00:00
parent 203b7b6638
commit d5717b3e8c
5 changed files with 122 additions and 14 deletions

View File

@ -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

View File

@ -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);

View File

@ -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)

View File

@ -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);
}

View File

@ -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