chiark / gitweb /
Import release 0.1.16
[secnet.git] / hackypar.c
diff --git a/hackypar.c b/hackypar.c
new file mode 100644 (file)
index 0000000..ebab051
--- /dev/null
@@ -0,0 +1,121 @@
+/* Hacky parallelism; Ian Jackson */
+
+#define _GNU_SOURCE
+
+#include "secnet.h"
+#include "util.h"
+#include "hackypar.h"
+
+#ifdef HACKY_PARALLEL
+
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+#include <assert.h>
+#include <sys/wait.h>
+
+#define HASHSIZE 16
+#define CACHESIZE 16
+
+typedef enum { hp_idle, hp_compute, hp_deferring, hp_fail } HPState;
+
+static HPState state;
+static pid_t child;
+
+static void checkchild(void) {
+  int r, status;
+  
+  if (!child) return;
+
+  r= waitpid(child,&status,WNOHANG); if (!r) return;
+  if (r==-1) {
+    Message(M_ERR,"hacky_par: waitpid: %s\n",strerror(errno));
+    return;
+  }
+  child= 0;
+  
+  if (WIFSIGNALED(status)) {
+    Message(M_ERR,"hacky_par: signaled! %s\n",strsignal(WTERMSIG(status)));
+  } else if (!WIFEXITED(status)) {
+    Message(M_ERR,"hacky_par: unexpected status! %d\n", r);
+  }
+}
+
+static HPState start(void) {
+  assert(!child);
+
+  child= fork();
+  if (child == -1) {
+    Message(M_ERR,"hacky_par: fork failed: %s\n",strerror(errno));
+    return hp_fail;
+  }
+
+  if (!child) { /* we are the child */
+    return hp_compute;
+  }
+
+  Message(M_INFO,"hacky_par: started, punting\n");
+  return hp_deferring;
+}
+
+int hacky_par_start_failnow(void) {
+  state= hp_idle;
+  checkchild();
+  if (child) {
+    state= hp_deferring;
+    Message(M_INFO,"hacky_par: busy, punting\n");
+    return 1;
+  }
+  return 0;
+}
+
+int hacky_par_mid_failnow(void) {
+  state= start();
+  return state != hp_compute;
+}
+
+bool_t (*packy_par_gen)(struct site *st);
+
+void hacky_par_end(int *ok,
+                  uint32_t retries, uint32_t timeout,
+                  bool_t (*send_msg)(struct site *st), struct site *st) {
+  int i;
+  
+  switch (state) {
+  case hp_deferring:
+    assert(!*ok);
+    *ok= 1;
+    return;
+  case hp_fail:
+    assert(!*ok);
+    return;
+  case hp_idle:
+    return;
+  case hp_compute:
+    if (!ok) {
+      Message(M_ERR,"hacky_par: compute failed\n");
+      _exit(2);
+    }
+    Message(M_INFO,"hacky_par: got result, sending\n");
+    for (i=1; i<retries; i++) {
+        sleep((timeout + 999)/1000);
+       if (!send_msg(st)) {
+           Message(M_ERR,"hacky_par: retry failed\n");
+           _exit(1);
+       }
+    }
+    _exit(0);
+  }
+}
+
+#else /*!HACKY_PARALLEL*/
+
+int hacky_par_start_failnow(void) { return 0; }
+int hacky_par_mid_failnow(void) { return 0; }
+void hacky_par_end(int *ok,
+                  uint32_t retries, uint32_t timeout,
+                  bool_t (*send_msg)(struct site *st), struct site *st) { }
+
+#endif /*HACKY_PARALLEL...else*/