This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
[rfc] Fix linux_test_for_tracefork for newer kernels
- From: Daniel Jacobowitz <drow at false dot org>
- To: gdb-patches at sources dot redhat dot com
- Date: Fri, 12 Nov 2004 17:59:41 -0500
- Subject: [rfc] Fix linux_test_for_tracefork for newer kernels
This patch makes the run-time test for fork tracing a little more robust.
In particular, it fixes two things:
- If the test failed in an unexpected way, then two stopped processes
could be left around.
- Waitpid can be interrupted by EINTR. Kernel 2.6.10-rc1 has some
changes to wait and signal processing, which cause the SIGCHLD
to be received before wait returns. I don't think there's any
actual bug here, since reissuing the wait works fine.
These changes let my testsuite runs finish without leaving hordes of stopped
processes around. I won't check it in yet, since I haven't tested it on a
system where this runtime check should fail; in the meantime, I'm just
posting it for comments. Hopefully I got it right this time!
--
Daniel Jacobowitz
2004-11-12 Daniel Jacobowitz <dan@debian.org>
* linux-nat.c (my_waitpid): New function.
(linux_test_for_tracefork): Make more robust and verbose.
Index: gdb-6.3/gdb/linux-nat.c
===================================================================
--- gdb-6.3.orig/gdb/linux-nat.c 2004-10-08 16:29:47.000000000 -0400
+++ gdb-6.3/gdb/linux-nat.c 2004-11-12 17:05:30.000000000 -0500
@@ -150,6 +150,21 @@ linux_tracefork_child (void)
exit (0);
}
+/* Wrapper function for waitpid which handles EINTR. */
+
+static int
+my_waitpid (int pid, int *status, int flags)
+{
+ int ret;
+ do
+ {
+ ret = waitpid (pid, status, flags);
+ }
+ while (ret == -1 && errno == EINTR);
+
+ return ret;
+}
+
/* Determine if PTRACE_O_TRACEFORK can be used to follow fork events. We
create a child process, attach to it, use PTRACE_SETOPTIONS to enable
fork tracing, and let it fork. If the process exits, we assume that
@@ -169,7 +184,7 @@ linux_test_for_tracefork (void)
if (child_pid == 0)
linux_tracefork_child ();
- ret = waitpid (child_pid, &status, 0);
+ ret = my_waitpid (child_pid, &status, 0);
if (ret == -1)
perror_with_name ("linux_test_for_tracefork: waitpid");
else if (ret != child_pid)
@@ -182,8 +197,17 @@ linux_test_for_tracefork (void)
ret = ptrace (PTRACE_SETOPTIONS, child_pid, 0, PTRACE_O_TRACEFORK);
if (ret != 0)
{
- ptrace (PTRACE_KILL, child_pid, 0, 0);
- waitpid (child_pid, &status, 0);
+ ret = ptrace (PTRACE_KILL, child_pid, 0, 0);
+ if (ret != 0)
+ {
+ warning ("linux_test_for_tracefork: failed to kill child");
+ return;
+ }
+
+ ret = my_waitpid (child_pid, &status, 0);
+ if (ret != 0)
+ warning ("linux_test_for_tracefork: failed to wait for killed child");
+
return;
}
@@ -192,8 +216,12 @@ linux_test_for_tracefork (void)
PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORKDONE);
linux_supports_tracevforkdone_flag = (ret == 0);
- ptrace (PTRACE_CONT, child_pid, 0, 0);
- ret = waitpid (child_pid, &status, 0);
+ ret = ptrace (PTRACE_CONT, child_pid, 0, 0);
+ if (ret != 0)
+ warning ("linux_test_for_tracefork: failed to resume child");
+
+ ret = my_waitpid (child_pid, &status, 0);
+
if (ret == child_pid && WIFSTOPPED (status)
&& status >> 16 == PTRACE_EVENT_FORK)
{
@@ -204,16 +232,20 @@ linux_test_for_tracefork (void)
int second_status;
linux_supports_tracefork_flag = 1;
- waitpid (second_pid, &second_status, 0);
- ptrace (PTRACE_DETACH, second_pid, 0, 0);
+ my_waitpid (second_pid, &second_status, 0);
+ ret = ptrace (PTRACE_KILL, second_pid, 0, 0);
+ if (ret != 0)
+ warning ("linux_test_for_tracefork: failed to kill second child");
}
}
+ else
+ warning ("linux_test_for_tracefork: unexpected result from waitpid "
+ "(%d, status 0x%x)", ret, status);
- if (WIFSTOPPED (status))
- {
- ptrace (PTRACE_DETACH, child_pid, 0, 0);
- waitpid (child_pid, &status, 0);
- }
+ ret = ptrace (PTRACE_KILL, child_pid, 0, 0);
+ if (ret != 0)
+ warning ("linux_test_for_tracefork: failed to kill child");
+ my_waitpid (child_pid, &status, 0);
}
/* Return non-zero iff we have tracefork functionality available.