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 */
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
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);
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)
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) );
}
}
-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);
}
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
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
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
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