aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPetr Machata <pmachata@redhat.com>2012-04-11 18:01:44 +0200
committerPetr Machata <pmachata@redhat.com>2012-04-11 18:01:44 +0200
commitffe4cd25089680daf1bd1ec0114d177ec3e0cf95 (patch)
tree68cbebfb7e1de8633af2a305985ccb784d20c770
parentcec06ec8282c538a40bde968ae36fe8356daffaa (diff)
downloadltrace-ffe4cd25089680daf1bd1ec0114d177ec3e0cf95.tar.gz
Handle detach from sleeping or unresponsive processes
-rw-r--r--common.h17
-rw-r--r--handle_event.c7
-rw-r--r--libltrace.c9
-rw-r--r--sysdeps/linux-gnu/events.c6
-rw-r--r--sysdeps/linux-gnu/trace.c15
5 files changed, 46 insertions, 8 deletions
diff --git a/common.h b/common.h
index 2399e29..b6e10f2 100644
--- a/common.h
+++ b/common.h
@@ -347,7 +347,6 @@ extern void continue_after_signal(pid_t pid, int signum);
extern void continue_after_syscall(Process *proc, int sysnum, int ret_p);
extern void continue_after_breakpoint(Process * proc, Breakpoint * sbp);
extern void continue_after_vfork(Process * proc);
-extern void ltrace_exiting(void);
extern long gimme_arg(enum tof type, Process * proc, int arg_num, arg_type_info * info);
extern void save_register_args(enum tof type, Process * proc);
extern int umovestr(Process * proc, void * addr, int len, void * laddr);
@@ -363,6 +362,22 @@ extern int task_kill (pid_t pid, int sig);
* any platform-specific knowledge of why it could be so. */
void trace_fail_warning(pid_t pid);
+/* A pair of functions called to initiate a detachment request when
+ * ltrace is about to exit. Their job is to undo any effects that
+ * tracing had and eventually detach process, perhaps by way of
+ * installing a process handler.
+ *
+ * OS_LTRACE_EXITING_SIGHANDLER is called from a signal handler
+ * context right after the signal was captured. It returns 1 if the
+ * request was handled or 0 if it wasn't.
+ *
+ * If the call to OS_LTRACE_EXITING_SIGHANDLER didn't handle the
+ * request, OS_LTRACE_EXITING is called when the next event is
+ * generated. Therefore it's called in "safe" context, without
+ * re-entrancy concerns, but it's only called after an even is
+ * generated. */
+int os_ltrace_exiting_sighandler(void);
+void os_ltrace_exiting(void);
extern struct ltelf main_lte;
diff --git a/handle_event.c b/handle_event.c
index e3d3d0a..725f50d 100644
--- a/handle_event.c
+++ b/handle_event.c
@@ -49,11 +49,12 @@ call_handler(Process * proc, Event * event)
}
void
-handle_event(Event *event) {
+handle_event(Event *event)
+{
if (exiting == 1) {
- exiting = 2;
debug(1, "ltrace about to exit");
- ltrace_exiting();
+ os_ltrace_exiting();
+ exiting = 2;
}
debug(DEBUG_FUNCTION, "handle_event(pid=%d, type=%d)",
event->proc ? event->proc->pid : -1, event->type);
diff --git a/libltrace.c b/libltrace.c
index 19bfafd..777ad1b 100644
--- a/libltrace.c
+++ b/libltrace.c
@@ -48,9 +48,14 @@ signal_alarm(int sig) {
}
static void
-signal_exit(int sig) {
- exiting = 1;
+signal_exit(int sig)
+{
debug(1, "Received interrupt signal; exiting...");
+ if (exiting != 0)
+ return;
+
+ exiting = 1 + !!os_ltrace_exiting_sighandler();
+
signal(SIGINT, SIG_IGN);
signal(SIGTERM, SIG_IGN);
signal(SIGALRM, signal_alarm);
diff --git a/sysdeps/linux-gnu/events.c b/sysdeps/linux-gnu/events.c
index 021192f..b6c12ef 100644
--- a/sysdeps/linux-gnu/events.c
+++ b/sysdeps/linux-gnu/events.c
@@ -104,6 +104,8 @@ next_qd_event(void)
return each_qd_event(&event_process_not_reenabling, NULL);
}
+int linux_in_waitpid = 0;
+
Event *
next_event(void)
{
@@ -124,7 +126,11 @@ next_event(void)
debug(DEBUG_EVENT, "event: No more traced programs: exiting");
exit(0);
}
+
+ linux_in_waitpid = 1;
pid = waitpid(-1, &status, __WALL);
+ linux_in_waitpid = 0;
+
if (pid == -1) {
if (errno == ECHILD) {
debug(DEBUG_EVENT, "event: No more traced programs: exiting");
diff --git a/sysdeps/linux-gnu/trace.c b/sysdeps/linux-gnu/trace.c
index 82a4154..9ecea1e 100644
--- a/sysdeps/linux-gnu/trace.c
+++ b/sysdeps/linux-gnu/trace.c
@@ -314,8 +314,8 @@ task_stopped(Process * task, void * data)
case ps_invalid:
case ps_tracing_stop:
case ps_zombie:
- case ps_sleeping:
return pcb_cont;
+ case ps_sleeping:
case ps_stop:
case ps_other:
return pcb_stop;
@@ -1005,7 +1005,7 @@ continue_after_syscall(Process * proc, int sysnum, int ret_p)
* detaches.
*/
void
-ltrace_exiting(void)
+os_ltrace_exiting(void)
{
struct opt_p_t * it;
for (it = opt_p; it != NULL; it = it->next) {
@@ -1019,6 +1019,17 @@ ltrace_exiting(void)
}
}
+int
+os_ltrace_exiting_sighandler(void)
+{
+ extern int linux_in_waitpid;
+ if (linux_in_waitpid) {
+ os_ltrace_exiting();
+ return 1;
+ }
+ return 0;
+}
+
size_t
umovebytes(Process *proc, void *addr, void *laddr, size_t len) {