Andrew Black wrote:
Greetings all.
Attached is a patch that aims to resolve an old issue with the exec
utility on UNIX. The problem observed is that when a kill signal is
sent to the exec utility, the child processes aren't killed. This patch
has been tested on Linux IA-32 and HPUX-11.23 on IA-64 (chosen due to
previous issues with signals).
Looks good to me. Unless Farid objects go ahead and commit it.
Thanks
Martin
--Andrew Black
Changelog:
* exec.cpp (alarm_timeout) [!_WIN32]: Update documentation.
(kill_signal) [!WIN32]: Add file local variable to track signal used to
kill process.
(handle_term_signal) [!_WIN32]: Add new callback function...
(wait_for_child) [!_WIN32]: ... Used here for SIGHUP, SIGINT, SIGQUIT,
and SIGTERM signals (via sigaction). Handlers are cleared if
kill_signal is set and the signal contained within is raise()ed.
------------------------------------------------------------------------
Index: util/exec.cpp
===================================================================
--- util/exec.cpp (revision 483585)
+++ util/exec.cpp (working copy)
@@ -64,10 +64,19 @@
Value is 1 when alarm has been triggered and hasn't been handled
@see handle_alrm
+ @see handle_term_signal
*/
static int alarm_timeout;
/**
+ Record of fatal signal recieved. Used to raise() the signal again after
+ child process has been killed.
+
+ @see handle_term_signal
+*/
+static int kill_signal;
+
+/**
Utility macro to generate a signal number/name pair.
@parm val 'short' signal name (no leading SIG) to generate pair for.
@@ -360,6 +369,22 @@
alarm_timeout = 1;
}
+/**
+ Callback used to gracefully terminate the utility if signaled to do so
+ while running a target
+
+ @param signo the signal recieved (should be in {SIGHUP, SIGINT, SIGQUIT,
+ SIGTERM})
+ @see alarm_timeout
+
+*/
+static void
+handle_term_signal (int signo)
+{
+ kill_signal = signo;
+ alarm_timeout = 1;
+}
+
typedef void (*alarm_handler)(int);
#ifdef __cplusplus
@@ -428,6 +453,19 @@
sigaction (SIGALRM, &act, 0);
+ /* Set handlers for SIGHUP, SIGINT, SIGQUIT, SIGTERM so we can kill the
+ child process prior to dieing.
+ */
+ kill_signal = 0;
+
+ phandler = handle_term_signal;
+ memcpy (&act.sa_handler, &phandler, sizeof act.sa_handler);
+
+ sigaction (SIGHUP, &act, 0);
+ sigaction (SIGINT, &act, 0);
+ sigaction (SIGQUIT, &act, 0);
+ sigaction (SIGTERM, &act, 0);
+
if (timeout > 0)
alarm (timeout);
@@ -558,6 +596,20 @@
++siginx;
sleep (1);
}
+
+ /* Check if we were signaled to quit. */
+ if (kill_signal) {
+ /* Reset the handlers to normal */
+ act.sa_handler = SIG_DFL;
+ sigaction (SIGHUP, &act, 0);
+ sigaction (SIGINT, &act, 0);
+ sigaction (SIGQUIT, &act, 0);
+ sigaction (SIGTERM, &act, 0);
+
+ if (0 > raise (kill_signal))
+ terminate (1, "raise(%s) failed: %s\n",
+ get_signame (kill_signal), strerror (errno));
+ }
}
/**