chiark / gitweb /
logging: Persistent children include pid in their log messages
[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 {
29     int r, status;
30   
31     if (!child) return;
32
33     r= waitpid(child,&status,WNOHANG); if (!r) return;
34     if (r==-1) {
35         Message(M_ERR,"hacky_par: waitpid: %s\n",strerror(errno));
36         return;
37     }
38     child= 0;
39   
40     if (WIFSIGNALED(status)) {
41         Message(M_ERR,"hacky_par: signaled! %s\n",strsignal(WTERMSIG(status)));
42     } else if (!WIFEXITED(status)) {
43         Message(M_ERR,"hacky_par: unexpected status! %d\n", r);
44     }
45 }
46
47 static HPState start(void)
48 {
49     assert(!child);
50
51     child= fork();
52     if (child == -1) {
53         Message(M_ERR,"hacky_par: fork failed: %s\n",strerror(errno));
54         return hp_fail;
55     }
56
57     if (!child) { /* we are the child */
58         afterfork();
59         return hp_compute;
60     }
61
62     Message(M_INFO,"hacky_par: started, punting\n");
63     return hp_deferring;
64 }
65
66 int hacky_par_start_failnow(void)
67 {
68     state= hp_idle;
69     checkchild();
70     if (child) {
71         state= hp_deferring;
72         Message(M_INFO,"hacky_par: busy, punting\n");
73         return 1;
74     }
75     return 0;
76 }
77
78 int hacky_par_mid_failnow(void)
79 {
80     state= start();
81     return state != hp_compute;
82 }
83
84 bool_t (*packy_par_gen)(struct site *st);
85
86 void hacky_par_end(int *ok,
87                    int32_t retries, int32_t timeout,
88                    bool_t (*send_msg)(struct site *st), struct site *st)
89 {
90     int i;
91   
92     switch (state) {
93     case hp_deferring:
94         assert(!*ok);
95         *ok= 1;
96         return;
97     case hp_fail:
98         assert(!*ok);
99         return;
100     case hp_idle:
101         return;
102     case hp_compute:
103         if (!ok) {
104             Message(M_ERR,"hacky_par: compute failed\n");
105             _exit(2);
106         }
107         Message(M_INFO,"hacky_par: got result, sending\n");
108         for (i=1; i<retries; i++) {
109             sleep((timeout + 999)/1000);
110             if (!send_msg(st)) {
111                 Message(M_ERR,"hacky_par: retry failed\n");
112                 _exit(1);
113             }
114         }
115         _exit(0);
116     }
117 }
118
119 #else /*!HACKY_PARALLEL*/
120
121 int hacky_par_start_failnow(void) { return 0; }
122 int hacky_par_mid_failnow(void) { return 0; }
123 void hacky_par_end(int *ok,
124                    int32_t retries, int32_t timeout,
125                    bool_t (*send_msg)(struct site *st), struct site *st) { }
126
127 #endif /*HACKY_PARALLEL...else*/