timeout: handle implicitly created threads
authorPádraig Brady <P@draigBrady.com>
Wed, 21 Sep 2011 14:22:52 +0000 (15:22 +0100)
committerPádraig Brady <P@draigBrady.com>
Thu, 22 Sep 2011 11:01:05 +0000 (12:01 +0100)
On some systems like glibc on GNU/kFreeBSD, a thread is
implicitly created when timer_settime() is used.
This breaks our scheme to ignore signals we've
sent ourselves.

* src/timeout.c (send_sig): Change the scheme used to
ignore signals we've sent ourselves, to a more robust
but perhaps limited scheme of ignoring all signals of
a certain type after we've sent that signal to the job.
* NEWS: Mention the change in behavior.

NEWS
src/timeout.c

diff --git a/NEWS b/NEWS
index 5d3ca40..140e6fa 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -12,6 +12,12 @@ GNU coreutils NEWS                                    -*- outline -*-
   more than PATH_MAX / 3 components.  Also affected due to their use
   of canonicalize_* functions: df, stat, readlink.
 
+** Changes in behavior
+
+  timeout now only processes the first signal received from the set
+  it is handling (SIGTERM, SIGINT, ...).  This is to support systems that
+  implicitly create threads for some timer functions (like GNU/kFreeBSD).
+
 
 * Noteworthy changes in release 8.13 (2011-09-08) [stable]
 
index d734e4e..59b937e 100644 (file)
@@ -77,7 +77,6 @@
 static int timed_out;
 static int term_signal = SIGTERM;  /* same default as kill command.  */
 static int monitored_pid;
-static int sigs_to_ignore[NSIG];   /* so monitor can ignore sigs it resends.  */
 static double kill_after;
 static bool foreground;            /* whether to use another program group.  */
 
@@ -141,12 +140,20 @@ settimeout (double duration)
   alarm (timeint);
 }
 
-/* send sig to group but not ourselves.
- * FIXME: Is there a better way to achieve this?  */
+/* send SIG avoiding the current process.  */
+
 static int
 send_sig (int where, int sig)
 {
-  sigs_to_ignore[sig] = 1;
+  /* If sending to the group, then ignore the signal,
+     so we don't go into a signal loop.  Note that this will ignore any of the
+     signals registered in install_signal_handlers(), that are sent after we
+     propagate the first one, which hopefully won't be an issue.  Note this
+     process can be implicitly multithreaded due to some timer_settime()
+     implementations, therefore a signal sent to the group, can be sent
+     multiple times to this process.  */
+  if (where == 0)
+    signal (sig, SIG_IGN);
   return kill (where, sig);
 }
 
@@ -160,11 +167,6 @@ cleanup (int sig)
     }
   if (monitored_pid)
     {
-      if (sigs_to_ignore[sig])
-        {
-          sigs_to_ignore[sig] = 0;
-          return;
-        }
       if (kill_after)
         {
           /* Start a new timeout after which we'll send SIGKILL.  */