This source file includes following definitions.
- cleanup_slaves
- cleanup_slaves_action
- register_slave_subprocess
- unregister_slave_subprocess
- wait_subprocess
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 #include <config.h>
20
21
22 #include "wait-process.h"
23
24 #include <errno.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <signal.h>
28
29 #include <sys/types.h>
30 #include <sys/wait.h>
31
32 #include "error.h"
33 #include "fatal-signal.h"
34 #include "xalloc.h"
35 #include "gettext.h"
36
37 #define _(str) gettext (str)
38
39 #define SIZEOF(a) (sizeof(a) / sizeof(a[0]))
40
41
42 #if defined _WIN32 && ! defined __CYGWIN__
43
44 # define WIN32_LEAN_AND_MEAN
45 # include <windows.h>
46
47
48
49 # define kill(pid,sig) TerminateProcess ((HANDLE) (pid), sig)
50
51 #endif
52
53
54
55
56
57
58
59
60
61 typedef struct
62 {
63 volatile sig_atomic_t used;
64 volatile pid_t child;
65 }
66 slaves_entry_t;
67
68
69 static slaves_entry_t static_slaves[32];
70 static slaves_entry_t * volatile slaves = static_slaves;
71 static sig_atomic_t volatile slaves_count = 0;
72 static size_t slaves_allocated = SIZEOF (static_slaves);
73
74
75
76 #ifdef SIGHUP
77 # define TERMINATOR SIGHUP
78 #else
79 # define TERMINATOR SIGTERM
80 #endif
81
82
83 static _GL_ASYNC_SAFE void
84 cleanup_slaves (void)
85 {
86 for (;;)
87 {
88
89 size_t n = slaves_count;
90 if (n == 0)
91 break;
92 n--;
93 slaves_count = n;
94
95 if (slaves[n].used)
96 {
97 pid_t slave = slaves[n].child;
98
99
100 kill (slave, TERMINATOR);
101 }
102 }
103 }
104
105
106
107 static _GL_ASYNC_SAFE void
108 cleanup_slaves_action (_GL_UNUSED int sig)
109 {
110 cleanup_slaves ();
111 }
112
113
114
115
116
117 void
118 register_slave_subprocess (pid_t child)
119 {
120 static bool cleanup_slaves_registered = false;
121 if (!cleanup_slaves_registered)
122 {
123 atexit (cleanup_slaves);
124 if (at_fatal_signal (cleanup_slaves_action) < 0)
125 xalloc_die ();
126 cleanup_slaves_registered = true;
127 }
128
129
130 {
131 slaves_entry_t *s = slaves;
132 slaves_entry_t *s_end = s + slaves_count;
133
134 for (; s < s_end; s++)
135 if (!s->used)
136 {
137
138
139
140
141 s->child = child;
142 s->used = 1;
143 return;
144 }
145 }
146
147 if (slaves_count == slaves_allocated)
148 {
149
150
151
152 slaves_entry_t *old_slaves = slaves;
153 size_t new_slaves_allocated = 2 * slaves_allocated;
154 slaves_entry_t *new_slaves =
155 (slaves_entry_t *)
156 malloc (new_slaves_allocated * sizeof (slaves_entry_t));
157 if (new_slaves == NULL)
158 {
159
160
161
162 kill (child, TERMINATOR);
163 xalloc_die ();
164 }
165 memcpy (new_slaves, old_slaves,
166 slaves_allocated * sizeof (slaves_entry_t));
167 slaves = new_slaves;
168 slaves_allocated = new_slaves_allocated;
169
170 if (old_slaves != static_slaves)
171 free (old_slaves);
172 }
173
174
175
176
177 slaves[slaves_count].child = child;
178 slaves[slaves_count].used = 1;
179 slaves_count++;
180 }
181
182
183 static void
184 unregister_slave_subprocess (pid_t child)
185 {
186
187
188
189 slaves_entry_t *s = slaves;
190 slaves_entry_t *s_end = s + slaves_count;
191
192 for (; s < s_end; s++)
193 if (s->used && s->child == child)
194 s->used = 0;
195 }
196
197
198
199
200
201 int
202 wait_subprocess (pid_t child, const char *progname,
203 bool ignore_sigpipe, bool null_stderr,
204 bool slave_process, bool exit_on_error,
205 int *termsigp)
206 {
207 #if HAVE_WAITID && defined WNOWAIT && 0
208
209
210
211
212
213
214
215
216
217 siginfo_t info;
218
219 if (termsigp != NULL)
220 *termsigp = 0;
221 for (;;)
222 {
223 if (waitid (P_PID, child, &info, WEXITED | (slave_process ? WNOWAIT : 0))
224 < 0)
225 {
226 # ifdef EINTR
227 if (errno == EINTR)
228 continue;
229 # endif
230 if (exit_on_error || !null_stderr)
231 error (exit_on_error ? EXIT_FAILURE : 0, errno,
232 _("%s subprocess"), progname);
233 return 127;
234 }
235
236
237
238
239 if (info.si_code == CLD_EXITED
240 || info.si_code == CLD_KILLED || info.si_code == CLD_DUMPED)
241 break;
242 }
243
244
245
246 if (slave_process)
247 {
248
249
250
251 unregister_slave_subprocess (child);
252
253
254 for (;;)
255 {
256 if (waitid (P_PID, child, &info, WEXITED) < 0)
257 {
258 # ifdef EINTR
259 if (errno == EINTR)
260 continue;
261 # endif
262 if (exit_on_error || !null_stderr)
263 error (exit_on_error ? EXIT_FAILURE : 0, errno,
264 _("%s subprocess"), progname);
265 return 127;
266 }
267 break;
268 }
269 }
270
271 switch (info.si_code)
272 {
273 case CLD_KILLED:
274 case CLD_DUMPED:
275 if (termsigp != NULL)
276 *termsigp = info.si_status;
277 # ifdef SIGPIPE
278 if (info.si_status == SIGPIPE && ignore_sigpipe)
279 return 0;
280 # endif
281 if (exit_on_error || (!null_stderr && termsigp == NULL))
282 error (exit_on_error ? EXIT_FAILURE : 0, 0,
283 _("%s subprocess got fatal signal %d"),
284 progname, info.si_status);
285 return 127;
286 case CLD_EXITED:
287 if (info.si_status == 127)
288 {
289 if (exit_on_error || !null_stderr)
290 error (exit_on_error ? EXIT_FAILURE : 0, 0,
291 _("%s subprocess failed"), progname);
292 return 127;
293 }
294 return info.si_status;
295 default:
296 abort ();
297 }
298 #else
299
300 int status;
301
302 if (termsigp != NULL)
303 *termsigp = 0;
304 status = 0;
305 for (;;)
306 {
307 int result = waitpid (child, &status, 0);
308
309 if (result != child)
310 {
311 # ifdef EINTR
312 if (errno == EINTR)
313 continue;
314 # endif
315 # if 0
316 if (errno == ECHILD)
317 {
318
319
320 status = 0;
321 break;
322 }
323 # endif
324 if (exit_on_error || !null_stderr)
325 error (exit_on_error ? EXIT_FAILURE : 0, errno,
326 _("%s subprocess"), progname);
327 return 127;
328 }
329
330
331
332
333 if (!WIFSTOPPED (status))
334 break;
335 }
336
337
338
339 if (slave_process)
340
341
342
343 unregister_slave_subprocess (child);
344
345 if (WIFSIGNALED (status))
346 {
347 if (termsigp != NULL)
348 *termsigp = WTERMSIG (status);
349 # ifdef SIGPIPE
350 if (WTERMSIG (status) == SIGPIPE && ignore_sigpipe)
351 return 0;
352 # endif
353 if (exit_on_error || (!null_stderr && termsigp == NULL))
354 error (exit_on_error ? EXIT_FAILURE : 0, 0,
355 _("%s subprocess got fatal signal %d"),
356 progname, (int) WTERMSIG (status));
357 return 127;
358 }
359 if (!WIFEXITED (status))
360 abort ();
361 if (WEXITSTATUS (status) == 127)
362 {
363 if (exit_on_error || !null_stderr)
364 error (exit_on_error ? EXIT_FAILURE : 0, 0,
365 _("%s subprocess failed"), progname);
366 return 127;
367 }
368 return WEXITSTATUS (status);
369 #endif
370 }