Adding a copy of memcached to the tree.
[awesomized/libmemcached] / memcached / timedrun.c
diff --git a/memcached/timedrun.c b/memcached/timedrun.c
new file mode 100644 (file)
index 0000000..6d7afb3
--- /dev/null
@@ -0,0 +1,102 @@
+#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;
+                if (caught == SIGALRM) {
+                   fprintf(stderr, "Timeout.. killing the process\n");
+                }
+                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(char **argv)
+{
+    int rv = EX_SOFTWARE;
+    pid_t pid = fork();
+
+    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(argv+2);
+}