Avoid gdb.base/fork-running-state.exp lingering processes
authorPedro Alves <palves@redhat.com>
Thu, 14 Jun 2018 16:47:03 +0000 (17:47 +0100)
committerPedro Alves <palves@redhat.com>
Thu, 14 Jun 2018 16:47:03 +0000 (17:47 +0100)
Currently, the gdb.base/fork-running-state.exp testcase leaves a few
processes lingering until a 3 minutes alarm kills them:

 pedro    28308     1  0 13:55 ?        00:00:00 /home/pedro/gdb/binutils-gdb/build/gdb/testsuite/outputs/gdb.base/fork-running-state/fork-running-state
 pedro    28340     1  0 13:55 ?        00:00:00 /home/pedro/gdb/binutils-gdb/build/gdb/testsuite/outputs/gdb.base/fork-running-state/fork-running-state
 pedro    28372     1  0 13:55 ?        00:00:00 /home/pedro/gdb/binutils-gdb/build/gdb/testsuite/outputs/gdb.base/fork-running-state/fork-running-state
 pedro    28400     1  0 13:55 ?        00:00:00 /home/pedro/gdb/binutils-gdb/build/gdb/testsuite/outputs/gdb.base/fork-running-state/fork-running-state
 pedro    28431     1  0 13:55 ?        00:00:00 /home/pedro/gdb/binutils-gdb/build/gdb/testsuite/outputs/gdb.base/fork-running-state/fork-running-state
 pedro    28463     1  0 13:55 ?        00:00:00 /home/pedro/gdb/binutils-gdb/build/gdb/testsuite/outputs/gdb.base/fork-running-state/fork-running-state

Those processes used to kill themselves, but that was changed by
commit f50d8a2eaea0 ("Fix gdb.base/fork-running-state.exp race").

This commit restores the self-killing, but only in the cases gdb won't
try killing the processes, thus avoiding the old race.

(The restored code in fork_parent isn't exactly the same as it was.
In this version, we're exiting immediately when 'wait' returns
success, while in the old version we'd loop again and end up in the
perror call.  The output from that perror call is not expected by the
"kill inferior" tests, and would result in a test FAIL.)

gdb/testsuite/ChangeLog:
2018-06-14  Pedro Alves  <palves@redhat.com>

* gdb.base/fork-running-state.c: Include <errno.h>.
(exit_if_relative_exits): New.
(fork_child): If 'exit_if_relative_exits' is true, exit if the parent
exits.
(fork_parent): If 'exit_if_relative_exits' is true, exit if the
child exits.

gdb/testsuite/ChangeLog
gdb/testsuite/gdb.base/fork-running-state.c
gdb/testsuite/gdb.base/fork-running-state.exp

index 1c98bbd031f8aa2122c959fab336f3ed97854df3..6d1f5f7af5c6d14824ca38eedbdecb4739bfcd30 100644 (file)
@@ -1,3 +1,12 @@
+2018-06-14  Pedro Alves  <palves@redhat.com>
+
+       * gdb.base/fork-running-state.c: Include <errno.h>.
+       (exit_if_relative_exits): New.
+       (fork_child): If 'exit_if_relative_exits' is true, exit if the parent
+       exits.
+       (fork_parent): If 'exit_if_relative_exits' is true, exit if the
+       child exits.
+
 2018-06-14  Tom de Vries  <tdevries@suse.de>
 
        PR cli/22573
index 65ca942ea028e1081552f23ba1cc12f584355703..0037cb5a5e19d13af6760bca5d2d2f3d722e0543 100644 (file)
 #include <stdio.h>
 #include <sys/types.h>
 #include <sys/wait.h>
+#include <errno.h>
 
 int save_parent;
 
+/* Variable set by GDB.  If true, then a fork child (or parent) exits
+   if its parent (or child) exits.  Otherwise the process waits
+   forever until either GDB or the alarm kills it.  */
+volatile int exit_if_relative_exits = 0;
+
 /* The fork child.  Just runs forever.  */
 
 static int
@@ -31,7 +37,20 @@ fork_child (void)
   alarm (180);
 
   while (1)
-    pause ();
+    {
+      if (exit_if_relative_exits)
+       {
+         sleep (1);
+
+         /* Exit if GDB kills the parent.  */
+         if (getppid () != save_parent)
+           break;
+         if (kill (getppid (), 0) != 0)
+           break;
+       }
+      else
+       pause ();
+    }
 
   return 0;
 }
@@ -45,7 +64,23 @@ fork_parent (void)
   alarm (180);
 
   while (1)
-    pause ();
+    {
+      if (exit_if_relative_exits)
+       {
+         int res = wait (NULL);
+         if (res == -1 && errno == EINTR)
+           continue;
+         else if (res == -1)
+           {
+             perror ("wait");
+             return 1;
+           }
+         else
+           return 0;
+       }
+      else
+       pause ();
+    }
 
   return 0;
 }
index 27ed8a43e935e9195beaa79b2fd0cec7cc8e6f18..c15bc53f7a06bfeb83340c632c8d78ee982852bc 100644 (file)
@@ -70,6 +70,13 @@ proc do_test { detach_on_fork follow_fork non_stop schedule_multiple } {
        gdb_test_no_output "set schedule-multiple $schedule_multiple"
     }
 
+    # If we're detaching from the parent (or child), then tell it to
+    # exit itself when its child (or parent) exits.  If we stay
+    # attached, we take care of killing it.
+    if {$detach_on_fork == "on"} {
+       gdb_test "print exit_if_relative_exits = 1" " = 1"
+    }
+
     set test "continue &"
     gdb_test_multiple $test $test {
        -re "$gdb_prompt " {