timeout: support cascaded timeouts
authorPádraig Brady <P@draigBrady.com>
Fri, 8 Jul 2011 12:31:05 +0000 (13:31 +0100)
committerPádraig Brady <P@draigBrady.com>
Fri, 8 Jul 2011 12:54:08 +0000 (13:54 +0100)
* src/timeout.c (cleanup): Send signals directly to the child
in case it has started its own process group (like a cascaded
timeout command would for example).
* test/misc/timeout-group: Add a test case.
* NEWS: Mention the fix.

NEWS
src/timeout.c
tests/misc/timeout-group

diff --git a/NEWS b/NEWS
index a4b11ed..62262bd 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -14,6 +14,9 @@ GNU coreutils NEWS                                    -*- outline -*-
   split --number l/... no longer creates extraneous files in certain cases.
   [bug introduced in coreutils-8.8]
 
+  timeout now sends signals to commands that create their own process group.
+  [bug introduced in coreutils-7.0]
+
 ** Changes in behavior
 
   chmod, chown and chgrp now output the original attributes in messages,
index 8f0980b..ab54ed6 100644 (file)
@@ -104,8 +104,6 @@ cleanup (int sig)
     }
   if (monitored_pid)
     {
-      int where = foreground ? monitored_pid : 0;
-
       if (sigs_to_ignore[sig])
         {
           sigs_to_ignore[sig] = 0;
@@ -119,9 +117,20 @@ cleanup (int sig)
           kill_after = 0; /* Don't let later signals reset kill alarm.  */
         }
 
-      send_sig (where, sig);
+      /* Send the signal directly to the monitored child,
+         in case it has itself become group leader,
+         or is not running in a separate group.  */
+      send_sig (monitored_pid, sig);
+      /* The normal case is the job has remained in our
+         newly created process group, so send to all processes in that.  */
+      if (!foreground)
+        send_sig (0, sig);
       if (sig != SIGKILL && sig != SIGCONT)
-        send_sig (where, SIGCONT);
+        {
+          send_sig (monitored_pid, SIGCONT);
+          if (!foreground)
+            send_sig (0, SIGCONT);
+        }
     }
   else /* we're the child or the child is not exec'd yet.  */
     _exit (128 + sig);
index 0c3caa0..fedd53a 100755 (executable)
@@ -34,13 +34,13 @@ cat > timeout.cmd <<\EOF
 #!/bin/sh
 trap 'touch int.received; exit' INT
 touch timeout.running
-sleep 10
+sleep $1
 EOF
 chmod a+x timeout.cmd
 
 cat > group.sh <<\EOF
 #!/bin/sh
-timeout --foreground 5 ./timeout.cmd&
+timeout --foreground 5 ./timeout.cmd 10&
 wait
 EOF
 chmod a+x group.sh
@@ -55,4 +55,21 @@ env kill -INT -- -$!
 wait
 test -e int.received || fail=1
 
+rm -f int.received timeout.running
+
+
+# Ensure cascaded timeouts work
+# or more generally, ensure we timeout
+# commands that create their own group
+# This didn't work before 8.13.
+
+# Note the first timeout must send a signal that
+# the second is handling for it to be propagated to the command.
+# SIGINT, SIGTERM, SIGALRM etc. are implicit.
+timeout -sALRM 2 timeout -sINT 10 ./timeout.cmd 5&
+until test -e timeout.running; do sleep .1; done
+kill -ALRM $!
+wait
+test -e int.received || fail=1
+
 Exit $fail