Makefile.in: Drop dist target
[secnet] / hackypar.c
1 /* Hacky parallelism */
2 /*
3 * This file is part of secnet.
4 * See README for full list of copyright holders.
5 *
6 * secnet is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * secnet is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * version 3 along with secnet; if not, see
18 * https://www.gnu.org/licenses/gpl.html.
19 */
20
21 #define _GNU_SOURCE
22
23 #include "secnet.h"
24 #include "util.h"
25 #include "hackypar.h"
26
27 #ifdef HACKY_PARALLEL
28
29 #include <stdio.h>
30 #include <unistd.h>
31 #include <errno.h>
32 #include <string.h>
33 #include <signal.h>
34 #include <assert.h>
35 #include <sys/wait.h>
36
37 #define HASHSIZE 16
38 #define CACHESIZE 16
39
40 typedef enum { hp_idle, hp_compute, hp_deferring, hp_fail } HPState;
41
42 static HPState state;
43 static pid_t child;
44
45 static void checkchild(void)
46 {
47 int r, status;
48
49 if (!child) return;
50
51 r= waitpid(child,&status,WNOHANG); if (!r) return;
52 if (r==-1) {
53 Message(M_ERR,"hacky_par: waitpid: %s\n",strerror(errno));
54 return;
55 }
56 child= 0;
57
58 if (WIFSIGNALED(status)) {
59 Message(M_ERR,"hacky_par: signaled! %s\n",strsignal(WTERMSIG(status)));
60 } else if (!WIFEXITED(status)) {
61 Message(M_ERR,"hacky_par: unexpected status! %d\n", r);
62 }
63 }
64
65 static HPState start(void)
66 {
67 assert(!child);
68
69 child= fork();
70 if (child == -1) {
71 Message(M_ERR,"hacky_par: fork failed: %s\n",strerror(errno));
72 return hp_fail;
73 }
74
75 if (!child) { /* we are the child */
76 afterfork();
77 return hp_compute;
78 }
79
80 Message(M_INFO,"hacky_par: started, punting\n");
81 return hp_deferring;
82 }
83
84 int hacky_par_start_failnow(void)
85 {
86 state= hp_idle;
87 checkchild();
88 if (child) {
89 state= hp_deferring;
90 Message(M_INFO,"hacky_par: busy, punting\n");
91 return 1;
92 }
93 return 0;
94 }
95
96 int hacky_par_mid_failnow(void)
97 {
98 state= start();
99 return state != hp_compute;
100 }
101
102 bool_t (*packy_par_gen)(struct site *st);
103
104 void hacky_par_end(int *ok,
105 int32_t retries, int32_t timeout,
106 bool_t (*send_msg)(struct site *st), struct site *st)
107 {
108 int i;
109
110 switch (state) {
111 case hp_deferring:
112 assert(!*ok);
113 *ok= 1;
114 return;
115 case hp_fail:
116 assert(!*ok);
117 return;
118 case hp_idle:
119 return;
120 case hp_compute:
121 if (!ok) {
122 Message(M_ERR,"hacky_par: compute failed\n");
123 _exit(2);
124 }
125 Message(M_INFO,"hacky_par: got result, sending\n");
126 for (i=1; i<retries; i++) {
127 sleep((timeout + 999)/1000);
128 if (!send_msg(st)) {
129 Message(M_ERR,"hacky_par: retry failed\n");
130 _exit(1);
131 }
132 }
133 _exit(0);
134 }
135 }
136
137 #else /*!HACKY_PARALLEL*/
138
139 int hacky_par_start_failnow(void) { return 0; }
140 int hacky_par_mid_failnow(void) { return 0; }
141 void hacky_par_end(int *ok,
142 int32_t retries, int32_t timeout,
143 bool_t (*send_msg)(struct site *st), struct site *st) { }
144
145 #endif /*HACKY_PARALLEL...else*/