summaryrefslogtreecommitdiff
path: root/timedrun.c
diff options
context:
space:
mode:
authorDustin Sallings <dustin@spy.net>2009-08-14 23:06:06 -0700
committerDustin Sallings <dustin@spy.net>2009-08-14 23:06:06 -0700
commitfba0a8919dd24c9dafa9459e4b046a58649392e0 (patch)
tree56aeef44b414d3d43a526e8bf648795bd11d3381 /timedrun.c
parent50d7188502f635d41ca07bb1f7b666f7b54171f0 (diff)
downloadmemcached-fba0a8919dd24c9dafa9459e4b046a58649392e0.tar.gz
Put a time limit on memcached processes started from within tests.
This solves the problem where certain test failures would cause indefinite hangs as child processes refused to ever exit.
Diffstat (limited to 'timedrun.c')
-rw-r--r--timedrun.c101
1 files changed, 101 insertions, 0 deletions
diff --git a/timedrun.c b/timedrun.c
new file mode 100644
index 0000000..5c93ed7
--- /dev/null
+++ b/timedrun.c
@@ -0,0 +1,101 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <sysexits.h>
+
+#include <assert.h>
+
+static int caught = 0;
+
+static void caught_signal(int which)
+{
+ caught = which;
+}
+
+static int wait_for_process(pid_t pid)
+{
+ int rv = EX_SOFTWARE;
+ int stats = 0;
+ int i = 0;
+ struct sigaction sig_handler;
+
+ sig_handler.sa_handler = caught_signal;
+ sig_handler.sa_flags = 0;
+
+ sigaction(SIGALRM, &sig_handler, NULL);
+ sigaction(SIGHUP, &sig_handler, NULL);
+ sigaction(SIGINT, &sig_handler, NULL);
+ sigaction(SIGTERM, &sig_handler, NULL);
+ sigaction(SIGPIPE, &sig_handler, NULL);
+
+ /* Loop forever waiting for the process to quit */
+ for (i = 0; ;i++) {
+ pid_t p = waitpid(pid, &stats, 0);
+ if (p == pid) {
+ /* child exited. Let's get out of here */
+ rv = WIFEXITED(stats) ?
+ WEXITSTATUS(stats) :
+ (0x80 | WTERMSIG(stats));
+ break;
+ } else {
+ int sig = 0;
+ switch (i) {
+ case 0:
+ /* On the first iteration, pass the signal through */
+ sig = caught > 0 ? caught : SIGTERM;
+ break;
+ case 1:
+ sig = SIGTERM;
+ break;
+ default:
+ sig = SIGKILL;
+ break;
+ }
+ if (kill(pid, sig) < 0) {
+ /* Kill failed. Must have lost the process. :/ */
+ perror("lost child when trying to kill");
+ }
+ /* Wait up to 5 seconds for the pid */
+ alarm(5);
+ }
+ }
+ return rv;
+}
+
+static int spawn_and_wait(int argc, char **argv)
+{
+ int rv = EX_SOFTWARE;
+ pid_t pid = fork();
+
+ assert(argc > 1);
+
+ switch (pid) {
+ case -1:
+ perror("fork");
+ rv = EX_OSERR;
+ break; /* NOTREACHED */
+ case 0:
+ execvp(argv[0], argv);
+ perror("exec");
+ rv = EX_SOFTWARE;
+ break; /* NOTREACHED */
+ default:
+ rv = wait_for_process(pid);
+ }
+ return rv;
+}
+
+int main(int argc, char **argv)
+{
+ int naptime = 0;
+ assert(argc > 2);
+
+ naptime = atoi(argv[1]);
+ assert(naptime > 0 && naptime < 1800);
+
+ alarm(naptime);
+
+ return spawn_and_wait(argc+2, argv+2);
+}