57
57
#else // __APPLE__
58
58
#include < linux/limits.h> // ARG_MAX
59
59
#endif // __APPLE__
60
+ #include < signal.h>
60
61
#include < sys/wait.h>
61
62
#include < unistd.h>
62
63
@@ -205,6 +206,48 @@ __attribute__((constructor(150))) void ForkServerCallMeVeryEarly() {
205
206
if (pipe1 < 0 ) Exit (" ###open pipe1 failed\n " );
206
207
Log (" ###Centipede fork server ready\n " );
207
208
209
+ struct sigaction old_sigterm_act;
210
+ struct sigaction sigterm_act;
211
+ std::memset (&sigterm_act, 0 , sizeof (struct sigaction ));
212
+ sigterm_act.sa_handler = *[](int _sig) {};
213
+ if (sigaction (SIGTERM, &sigterm_act, &old_sigterm_act) != 0 ) {
214
+ Exit (" ###sigaction failed on SIGTERM for the fork server" );
215
+ }
216
+
217
+ struct sigaction old_sigchld_act;
218
+ struct sigaction sigchld_act;
219
+ std::memset (&sigchld_act, 0 , sizeof (struct sigaction ));
220
+ sigchld_act.sa_handler = *[](int _sig) {};
221
+ if (sigaction (SIGCHLD, &sigchld_act, &old_sigchld_act) != 0 ) {
222
+ Exit (" ###sigaction failed on SIGCHLD for the fork server" );
223
+ }
224
+
225
+ sigset_t old_sigset;
226
+ sigset_t server_sigset;
227
+ if (sigprocmask (SIG_SETMASK, nullptr , &server_sigset) != 0 ) {
228
+ Exit (" ###sigprocmask() failed to get the existing sigset\n " );
229
+ }
230
+ if (sigaddset (&server_sigset, SIGTERM) != 0 ) {
231
+ Exit (" ###sigaddset() failed to add SIGTERM\n " );
232
+ }
233
+ if (sigaddset (&server_sigset, SIGCHLD) != 0 ) {
234
+ Exit (" ###sigaddset() failed to add SIGCHLD\n " );
235
+ }
236
+ if (sigprocmask (SIG_SETMASK, &server_sigset, &old_sigset) != 0 ) {
237
+ Exit (" ###sigprocmask() failed to set the fork server sigset\n " );
238
+ }
239
+
240
+ sigset_t wait_sigset;
241
+ if (sigemptyset (&wait_sigset) != 0 ) {
242
+ Exit (" ###sigemptyset() failed\n " );
243
+ }
244
+ if (sigaddset (&wait_sigset, SIGTERM) != 0 ) {
245
+ Exit (" ###sigaddset() failed to add SIGTERM to the wait sigset\n " );
246
+ }
247
+ if (sigaddset (&wait_sigset, SIGCHLD) != 0 ) {
248
+ Exit (" ###sigaddset() failed to add SIGCHLD to the wait sigset\n " );
249
+ }
250
+
208
251
// Loop.
209
252
while (true ) {
210
253
Log (" ###Centipede fork server blocking on pipe0\n " );
@@ -216,6 +259,15 @@ __attribute__((constructor(150))) void ForkServerCallMeVeryEarly() {
216
259
if (pid < 0 ) {
217
260
Exit (" ###fork failed\n " );
218
261
} else if (pid == 0 ) {
262
+ if (sigaction (SIGTERM, &old_sigterm_act, nullptr ) != 0 ) {
263
+ Exit (" ###sigaction failed on SIGTERM for the child" );
264
+ }
265
+ if (sigaction (SIGCHLD, &old_sigchld_act, nullptr ) != 0 ) {
266
+ Exit (" ###sigaction failed on SIGCHLD for the child" );
267
+ }
268
+ if (sigprocmask (SIG_SETMASK, &old_sigset, nullptr ) != 0 ) {
269
+ Exit (" ###sigprocmask() failed to restore the previous sigset\n " );
270
+ }
219
271
// Child process. Reset stdout/stderr and let it run normally.
220
272
for (int fd = 1 ; fd <= 2 ; fd++) {
221
273
lseek (fd, 0 , SEEK_SET);
@@ -227,7 +279,27 @@ __attribute__((constructor(150))) void ForkServerCallMeVeryEarly() {
227
279
} else {
228
280
// Parent process.
229
281
int status = -1 ;
230
- if (waitpid (pid, &status, 0 ) < 0 ) Exit (" ###waitpid failed\n " );
282
+ while (true ) {
283
+ int sig = -1 ;
284
+ if (sigwait (&wait_sigset, &sig) != 0 ) {
285
+ Exit (" ###sigwait() failed\n " );
286
+ }
287
+ if (sig == SIGCHLD) {
288
+ Log (" ###Got SIGCHLD\n " );
289
+ if (waitpid (pid, &status, WNOHANG) < 0 ) {
290
+ Exit (" ###waitpid failed\n " );
291
+ }
292
+ if (WIFEXITED (status) || WIFSIGNALED (status)) {
293
+ Log (" ###Got exit status\n " );
294
+ break ;
295
+ }
296
+ } else if (sig == SIGTERM) {
297
+ Log (" ###Got SIGTERM\n " );
298
+ kill (pid, SIGTERM);
299
+ } else {
300
+ Exit (" ###Unknown signal from sigwait\n " );
301
+ }
302
+ }
231
303
if (WIFEXITED (status)) {
232
304
if (WEXITSTATUS (status) == EXIT_SUCCESS)
233
305
Log (" ###Centipede fork returned EXIT_SUCCESS\n " );
@@ -239,8 +311,28 @@ __attribute__((constructor(150))) void ForkServerCallMeVeryEarly() {
239
311
Log (" ###Centipede fork crashed\n " );
240
312
}
241
313
Log (" ###Centipede fork writing status to pipe1\n " );
242
- if (write (pipe1, &status, sizeof (status)) == -1 )
314
+ if (write (pipe1, &status, sizeof (status)) == -1 ) {
243
315
Exit (" ###write to pipe1 failed\n " );
316
+ }
317
+ // Deplete any remaining signals before the next execution. Controller
318
+ // won't send more signals after write succeeded.
319
+ {
320
+ sigset_t pending;
321
+ while (true ) {
322
+ if (sigpending (&pending) != 0 ) {
323
+ Exit (" ###sigpending() failed\n " );
324
+ }
325
+ if (sigismember (&pending, SIGTERM) ||
326
+ sigismember (&pending, SIGCHLD)) {
327
+ int unused_sig;
328
+ if (sigwait (&wait_sigset, &unused_sig) != 0 ) {
329
+ Exit (" ###sigwait() failed\n " );
330
+ }
331
+ } else {
332
+ break ;
333
+ }
334
+ }
335
+ }
244
336
}
245
337
}
246
338
// The only way out of the loop is via Exit() or return.
0 commit comments