chiark / gitweb /
Prohibit lists where single values expected.
[secnet.git] / hackypar.c
1 /* Hacky parallelism; Ian Jackson */
2
3 #define _GNU_SOURCE
4
5 #include "secnet.h"
6 #include "util.h"
7 #include "hackypar.h"
8
9 #ifdef HACKY_PARALLEL
10
11 #include <stdio.h>
12 #include <unistd.h>
13 #include <errno.h>
14 #include <string.h>
15 #include <signal.h>
16 #include <assert.h>
17 #include <sys/wait.h>
18
19 #define HASHSIZE 16
20 #define CACHESIZE 16
21
22 typedef enum { hp_idle, hp_compute, hp_deferring, hp_fail } HPState;
23
24 static HPState state;
25 static pid_t child;
26
27 static void checkchild(void) {
28   int r, status;
29   
30   if (!child) return;
31
32   r= waitpid(child,&status,WNOHANG); if (!r) return;
33   if (r==-1) {
34     Message(M_ERR,"hacky_par: waitpid: %s\n",strerror(errno));
35     return;
36   }
37   child= 0;
38   
39   if (WIFSIGNALED(status)) {
40     Message(M_ERR,"hacky_par: signaled! %s\n",strsignal(WTERMSIG(status)));
41   } else if (!WIFEXITED(status)) {
42     Message(M_ERR,"hacky_par: unexpected status! %d\n", r);
43   }
44 }
45
46 static HPState start(void) {
47   assert(!child);
48
49   child= fork();
50   if (child == -1) {
51     Message(M_ERR,"hacky_par: fork failed: %s\n",strerror(errno));
52     return hp_fail;
53   }
54
55   if (!child) { /* we are the child */
56     return hp_compute;
57   }
58
59   Message(M_INFO,"hacky_par: started, punting\n");
60   return hp_deferring;
61 }
62
63 int hacky_par_start_failnow(void) {
64   state= hp_idle;
65   checkchild();
66   if (child) {
67     state= hp_deferring;
68     Message(M_INFO,"hacky_par: busy, punting\n");
69     return 1;
70   }
71   return 0;
72 }
73
74 int hacky_par_mid_failnow(void) {
75   state= start();
76   return state != hp_compute;
77 }
78
79 bool_t (*packy_par_gen)(struct site *st);
80
81 void hacky_par_end(int *ok,
82                    int32_t retries, int32_t timeout,
83                    bool_t (*send_msg)(struct site *st), struct site *st) {
84   int i;
85   
86   switch (state) {
87   case hp_deferring:
88     assert(!*ok);
89     *ok= 1;
90     return;
91   case hp_fail:
92     assert(!*ok);
93     return;
94   case hp_idle:
95     return;
96   case hp_compute:
97     if (!ok) {
98       Message(M_ERR,"hacky_par: compute failed\n");
99       _exit(2);
100     }
101     Message(M_INFO,"hacky_par: got result, sending\n");
102     for (i=1; i<retries; i++) {
103         sleep((timeout + 999)/1000);
104         if (!send_msg(st)) {
105             Message(M_ERR,"hacky_par: retry failed\n");
106             _exit(1);
107         }
108     }
109     _exit(0);
110   }
111 }
112
113 #else /*!HACKY_PARALLEL*/
114
115 int hacky_par_start_failnow(void) { return 0; }
116 int hacky_par_mid_failnow(void) { return 0; }
117 void hacky_par_end(int *ok,
118                    int32_t retries, int32_t timeout,
119                    bool_t (*send_msg)(struct site *st), struct site *st) { }
120
121 #endif /*HACKY_PARALLEL...else*/