debug: add an empty line
[samba.git] / lib / util / tfork.c
1 /*
2    fork on steroids to avoid SIGCHLD and waitpid
3
4    Copyright (C) Stefan Metzmacher 2010
5    Copyright (C) Ralph Boehme 2017
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "replace.h"
22 #include "system/wait.h"
23 #include "system/filesys.h"
24 #include "system/network.h"
25 #include "lib/util/samba_util.h"
26 #include "lib/util/sys_rw.h"
27 #include "lib/util/tfork.h"
28 #include "lib/util/debug.h"
29
30 #ifdef HAVE_PTHREAD
31 #include <pthread.h>
32 #endif
33
34 #ifdef NDEBUG
35 #undef NDEBUG
36 #endif
37 #include <assert.h>
38
39 /*
40  * This is how the process hierarchy looks like:
41  *
42  *   +----------+
43  *   |  caller  |
44  *   +----------+
45  *         |
46  *       fork
47  *         |
48  *         v
49  *   +----------+
50  *   |  waiter  |
51  *   +----------+
52  *         |
53  *       fork
54  *         |
55  *         v
56  *   +----------+
57  *   |  worker  |
58  *   +----------+
59  */
60
61 #ifdef HAVE_VALGRIND_HELGRIND_H
62 #include <valgrind/helgrind.h>
63 #endif
64 #ifndef ANNOTATE_BENIGN_RACE_SIZED
65 #define ANNOTATE_BENIGN_RACE_SIZED(obj, size, description)
66 #endif
67
68 #define TFORK_ANNOTATE_BENIGN_RACE(obj)                                 \
69         ANNOTATE_BENIGN_RACE_SIZED(                                     \
70                 (obj), sizeof(*(obj)),                                  \
71                 "no race, serialized by tfork_[un]install_sigchld_handler");
72
73 /*
74  * The resulting (private) state per tfork_create() call, returned as a opaque
75  * handle to the caller.
76  */
77 struct tfork {
78         /*
79          * This is returned to the caller with tfork_event_fd()
80          */
81         int event_fd;
82
83         /*
84          * This is used in the caller by tfork_status() to read the worker exit
85          * status and to tell the waiter to exit by closing the fd.
86          */
87         int status_fd;
88
89         pid_t waiter_pid;
90         pid_t worker_pid;
91 };
92
93 /*
94  * Internal per-thread state maintained while inside tfork.
95  */
96 struct tfork_state {
97         pid_t waiter_pid;
98         int waiter_errno;
99
100         pid_t worker_pid;
101 };
102
103 /*
104  * A global state that synchronizes access to handling SIGCHLD and waiting for
105  * childs.
106  */
107 struct tfork_signal_state {
108         bool available;
109
110 #ifdef HAVE_PTHREAD
111         pthread_cond_t cond;
112         pthread_mutex_t mutex;
113 #endif
114
115         /*
116          * pid of the waiter child. This points at waiter_pid in either struct
117          * tfork or struct tfork_state, depending on who called
118          * tfork_install_sigchld_handler().
119          *
120          * When tfork_install_sigchld_handler() is called the waiter_pid is
121          * still -1 and only set later after fork(), that's why this is must be
122          * a pointer. The signal handler checks this.
123          */
124         pid_t *pid;
125
126         struct sigaction oldact;
127         sigset_t oldset;
128 };
129
130 static struct tfork_signal_state signal_state;
131
132 #ifdef HAVE_PTHREAD
133 static pthread_once_t tfork_global_is_initialized = PTHREAD_ONCE_INIT;
134 static pthread_key_t tfork_global_key;
135 #else
136 static struct tfork_state *global_state;
137 #endif
138
139 static void tfork_sigchld_handler(int signum, siginfo_t *si, void *p);
140
141 #ifdef HAVE_PTHREAD
142 static void tfork_global_destructor(void *state)
143 {
144         anonymous_shared_free(state);
145 }
146 #endif
147
148 static int tfork_acquire_sighandling(void)
149 {
150         int ret = 0;
151
152 #ifdef HAVE_PTHREAD
153         ret = pthread_mutex_lock(&signal_state.mutex);
154         if (ret != 0) {
155                 return ret;
156         }
157
158         while (!signal_state.available) {
159                 ret = pthread_cond_wait(&signal_state.cond,
160                                         &signal_state.mutex);
161                 if (ret != 0) {
162                         return ret;
163                 }
164         }
165
166         signal_state.available = false;
167
168         ret = pthread_mutex_unlock(&signal_state.mutex);
169         if (ret != 0) {
170                 return ret;
171         }
172 #endif
173
174         return ret;
175 }
176
177 static int tfork_release_sighandling(void)
178 {
179         int ret = 0;
180
181 #ifdef HAVE_PTHREAD
182         ret = pthread_mutex_lock(&signal_state.mutex);
183         if (ret != 0) {
184                 return ret;
185         }
186
187         signal_state.available = true;
188
189         ret = pthread_cond_signal(&signal_state.cond);
190         if (ret != 0) {
191                 pthread_mutex_unlock(&signal_state.mutex);
192                 return ret;
193         }
194
195         ret = pthread_mutex_unlock(&signal_state.mutex);
196         if (ret != 0) {
197                 return ret;
198         }
199 #endif
200
201         return ret;
202 }
203
204 #ifdef HAVE_PTHREAD
205 static void tfork_atfork_prepare(void)
206 {
207         int ret;
208
209         ret = pthread_mutex_lock(&signal_state.mutex);
210         assert(ret == 0);
211 }
212
213 static void tfork_atfork_parent(void)
214 {
215         int ret;
216
217         ret = pthread_mutex_unlock(&signal_state.mutex);
218         assert(ret == 0);
219 }
220 #endif
221
222 static void tfork_atfork_child(void)
223 {
224         int ret;
225
226 #ifdef HAVE_PTHREAD
227         ret = pthread_mutex_unlock(&signal_state.mutex);
228         assert(ret == 0);
229
230         ret = pthread_key_delete(tfork_global_key);
231         assert(ret == 0);
232
233         ret = pthread_key_create(&tfork_global_key, tfork_global_destructor);
234         assert(ret == 0);
235
236         /*
237          * There's no data race on the cond variable from the signal state, we
238          * are writing here, but there are no readers yet. Some data race
239          * detection tools report a race, but the readers are in the parent
240          * process.
241          */
242         TFORK_ANNOTATE_BENIGN_RACE(&signal_state.cond);
243
244         /*
245          * There's no way to destroy a condition variable if there are waiters,
246          * pthread_cond_destroy() will return EBUSY. Just zero out memory and
247          * then initialize again. This is not backed by POSIX but should be ok.
248          */
249         ZERO_STRUCT(signal_state.cond);
250         ret = pthread_cond_init(&signal_state.cond, NULL);
251         assert(ret == 0);
252 #endif
253
254         if (signal_state.pid != NULL) {
255
256                 ret = sigaction(SIGCHLD, &signal_state.oldact, NULL);
257                 assert(ret == 0);
258
259 #ifdef HAVE_PTHREAD
260                 ret = pthread_sigmask(SIG_SETMASK, &signal_state.oldset, NULL);
261 #else
262                 ret = sigprocmask(SIG_SETMASK, &signal_state.oldset, NULL);
263                 assert(ret == 0);
264 #endif
265
266                 signal_state.pid = NULL;
267         }
268
269         signal_state.available = true;
270 }
271
272 static void tfork_global_initialize(void)
273 {
274 #ifdef HAVE_PTHREAD
275         int ret;
276
277         pthread_atfork(tfork_atfork_prepare,
278                        tfork_atfork_parent,
279                        tfork_atfork_child);
280
281         ret = pthread_key_create(&tfork_global_key, tfork_global_destructor);
282         assert(ret == 0);
283
284         ret = pthread_mutex_init(&signal_state.mutex, NULL);
285         assert(ret == 0);
286
287         ret = pthread_cond_init(&signal_state.cond, NULL);
288         assert(ret == 0);
289
290         /*
291          * In a threaded process there's no data race on t->waiter_pid as
292          * we're serializing globally via tfork_acquire_sighandling() and
293          * tfork_release_sighandling().
294          */
295         TFORK_ANNOTATE_BENIGN_RACE(&signal_state.pid);
296 #endif
297
298         signal_state.available = true;
299 }
300
301 static struct tfork_state *tfork_global_get(void)
302 {
303         struct tfork_state *state = NULL;
304 #ifdef HAVE_PTHREAD
305         int ret;
306 #endif
307
308 #ifdef HAVE_PTHREAD
309         state = (struct tfork_state *)pthread_getspecific(tfork_global_key);
310 #else
311         state = global_state;
312 #endif
313         if (state != NULL) {
314                 return state;
315         }
316
317         state = (struct tfork_state *)anonymous_shared_allocate(
318                 sizeof(struct tfork_state));
319         if (state == NULL) {
320                 return NULL;
321         }
322
323 #ifdef HAVE_PTHREAD
324         ret = pthread_setspecific(tfork_global_key, state);
325         if (ret != 0) {
326                 anonymous_shared_free(state);
327                 return NULL;
328         }
329 #endif
330         return state;
331 }
332
333 static void tfork_global_free(void)
334 {
335         struct tfork_state *state = NULL;
336 #ifdef HAVE_PTHREAD
337         int ret;
338 #endif
339
340 #ifdef HAVE_PTHREAD
341         state = (struct tfork_state *)pthread_getspecific(tfork_global_key);
342 #else
343         state = global_state;
344 #endif
345         if (state == NULL) {
346                 return;
347         }
348
349 #ifdef HAVE_PTHREAD
350         ret = pthread_setspecific(tfork_global_key, NULL);
351         if (ret != 0) {
352                 return;
353         }
354 #endif
355         anonymous_shared_free(state);
356 }
357
358 /**
359  * Only one thread at a time is allowed to handle SIGCHLD signals
360  **/
361 static int tfork_install_sigchld_handler(pid_t *pid)
362 {
363         int ret;
364         struct sigaction act;
365         sigset_t set;
366
367         ret = tfork_acquire_sighandling();
368         if (ret != 0) {
369                 return -1;
370         }
371
372         assert(signal_state.pid == NULL);
373         signal_state.pid = pid;
374
375         act = (struct sigaction) {
376                 .sa_sigaction = tfork_sigchld_handler,
377                 .sa_flags = SA_SIGINFO,
378         };
379
380         ret = sigaction(SIGCHLD, &act, &signal_state.oldact);
381         if (ret != 0) {
382                 return -1;
383         }
384
385         sigemptyset(&set);
386         sigaddset(&set, SIGCHLD);
387 #ifdef HAVE_PTHREAD
388         ret = pthread_sigmask(SIG_UNBLOCK, &set, &signal_state.oldset);
389 #else
390         ret = sigprocmask(SIG_UNBLOCK, &set, &signal_state.oldset);
391 #endif
392         if (ret != 0) {
393                 return -1;
394         }
395
396         return 0;
397 }
398
399 static int tfork_uninstall_sigchld_handler(void)
400 {
401         int ret;
402
403         signal_state.pid = NULL;
404
405         ret = sigaction(SIGCHLD, &signal_state.oldact, NULL);
406         if (ret != 0) {
407                 return -1;
408         }
409
410 #ifdef HAVE_PTHREAD
411         ret = pthread_sigmask(SIG_SETMASK, &signal_state.oldset, NULL);
412 #else
413         ret = sigprocmask(SIG_SETMASK, &signal_state.oldset, NULL);
414 #endif
415         if (ret != 0) {
416                 return -1;
417         }
418
419         ret = tfork_release_sighandling();
420         if (ret != 0) {
421                 return -1;
422         }
423
424         return 0;
425 }
426
427 static void tfork_sigchld_handler(int signum, siginfo_t *si, void *p)
428 {
429         if ((signal_state.pid != NULL) &&
430             (*signal_state.pid != -1) &&
431             (si->si_pid == *signal_state.pid))
432         {
433                 return;
434         }
435
436         /*
437          * Not our child, forward to old handler
438          */
439         if (signal_state.oldact.sa_flags & SA_SIGINFO) {
440                 signal_state.oldact.sa_sigaction(signum, si, p);
441                 return;
442         }
443
444         if (signal_state.oldact.sa_handler == SIG_IGN) {
445                 return;
446         }
447         if (signal_state.oldact.sa_handler == SIG_DFL) {
448                 return;
449         }
450         signal_state.oldact.sa_handler(signum);
451 }
452
453 static pid_t tfork_start_waiter_and_worker(struct tfork_state *state,
454                                            int *_event_fd,
455                                            int *_status_fd)
456 {
457         int p[2];
458         int status_sp_caller_fd = -1;
459         int status_sp_waiter_fd = -1;
460         int event_pipe_caller_fd = -1;
461         int event_pipe_waiter_fd = -1;
462         int ready_pipe_caller_fd = -1;
463         int ready_pipe_worker_fd = -1;
464         ssize_t nwritten;
465         ssize_t nread;
466         pid_t pid;
467         int status;
468         int fd;
469         char c;
470         int ret;
471
472         *_event_fd = -1;
473         *_status_fd = -1;
474
475         if (state == NULL) {
476                 return -1;
477         }
478
479         ret = socketpair(AF_UNIX, SOCK_STREAM, 0, p);
480         if (ret != 0) {
481                 return -1;
482         }
483         set_close_on_exec(p[0]);
484         set_close_on_exec(p[1]);
485         status_sp_caller_fd = p[0];
486         status_sp_waiter_fd = p[1];
487
488         ret = pipe(p);
489         if (ret != 0) {
490                 close(status_sp_caller_fd);
491                 close(status_sp_waiter_fd);
492                 return -1;
493         }
494         set_close_on_exec(p[0]);
495         set_close_on_exec(p[1]);
496         event_pipe_caller_fd = p[0];
497         event_pipe_waiter_fd = p[1];
498
499
500         ret = pipe(p);
501         if (ret != 0) {
502                 close(status_sp_caller_fd);
503                 close(status_sp_waiter_fd);
504                 close(event_pipe_caller_fd);
505                 close(event_pipe_waiter_fd);
506                 return -1;
507         }
508         set_close_on_exec(p[0]);
509         set_close_on_exec(p[1]);
510         ready_pipe_worker_fd = p[0];
511         ready_pipe_caller_fd = p[1];
512
513         pid = fork();
514         if (pid == -1) {
515                 close(status_sp_caller_fd);
516                 close(status_sp_waiter_fd);
517                 close(event_pipe_caller_fd);
518                 close(event_pipe_waiter_fd);
519                 close(ready_pipe_caller_fd);
520                 close(ready_pipe_worker_fd);
521                 return -1;
522         }
523         if (pid != 0) {
524                 /* The caller */
525
526                 /*
527                  * In a threaded process there's no data race on
528                  * state->waiter_pid as we're serializing globally via
529                  * tfork_acquire_sighandling() and tfork_release_sighandling().
530                  */
531                 TFORK_ANNOTATE_BENIGN_RACE(&state->waiter_pid);
532
533                 state->waiter_pid = pid;
534
535                 close(status_sp_waiter_fd);
536                 close(event_pipe_waiter_fd);
537                 close(ready_pipe_worker_fd);
538
539                 set_blocking(event_pipe_caller_fd, false);
540
541                 /*
542                  * wait for the waiter to get ready.
543                  */
544                 nread = sys_read(status_sp_caller_fd, &c, sizeof(char));
545                 if (nread != sizeof(char)) {
546                         return -1;
547                 }
548
549                 /*
550                  * Notify the worker to start.
551                  */
552                 nwritten = sys_write(ready_pipe_caller_fd,
553                                      &(char){0}, sizeof(char));
554                 if (nwritten != sizeof(char)) {
555                         close(ready_pipe_caller_fd);
556                         return -1;
557                 }
558                 close(ready_pipe_caller_fd);
559
560                 *_event_fd = event_pipe_caller_fd;
561                 *_status_fd = status_sp_caller_fd;
562
563                 return pid;
564         }
565
566 #ifndef HAVE_PTHREAD
567         /* cleanup sigchld_handler */
568         tfork_atfork_child();
569 #endif
570
571         /*
572          * The "waiter" child.
573          */
574         setproctitle("tfork waiter process");
575         CatchSignal(SIGCHLD, SIG_DFL);
576
577         close(status_sp_caller_fd);
578         close(event_pipe_caller_fd);
579         close(ready_pipe_caller_fd);
580
581         pid = fork();
582         if (pid == -1) {
583                 state->waiter_errno = errno;
584                 _exit(0);
585         }
586         if (pid == 0) {
587                 /*
588                  * The worker child.
589                  */
590
591                 close(status_sp_waiter_fd);
592                 close(event_pipe_waiter_fd);
593
594                 /*
595                  * Wait for the caller to give us a go!
596                  */
597                 nread = sys_read(ready_pipe_worker_fd, &c, sizeof(char));
598                 if (nread != sizeof(char)) {
599                         _exit(1);
600                 }
601                 close(ready_pipe_worker_fd);
602
603                 return 0;
604         }
605         state->worker_pid = pid;
606
607         close(ready_pipe_worker_fd);
608
609         /*
610          * We're going to stay around until child2 exits, so lets close all fds
611          * other then the pipe fd we may have inherited from the caller.
612          *
613          * Dup event_sp_waiter_fd and status_sp_waiter_fd onto fds 0 and 1 so we
614          * can then call closefrom(2).
615          */
616         if (event_pipe_waiter_fd > 0) {
617                 int dup_fd = 0;
618
619                 if (status_sp_waiter_fd == 0) {
620                         dup_fd = 1;
621                 }
622
623                 do {
624                         fd = dup2(event_pipe_waiter_fd, dup_fd);
625                 } while ((fd == -1) && (errno == EINTR));
626                 if (fd == -1) {
627                         state->waiter_errno = errno;
628                         kill(state->worker_pid, SIGKILL);
629                         state->worker_pid = -1;
630                         _exit(1);
631                 }
632                 event_pipe_waiter_fd = fd;
633         }
634
635         if (status_sp_waiter_fd > 1) {
636                 do {
637                         fd = dup2(status_sp_waiter_fd, 1);
638                 } while ((fd == -1) && (errno == EINTR));
639                 if (fd == -1) {
640                         state->waiter_errno = errno;
641                         kill(state->worker_pid, SIGKILL);
642                         state->worker_pid = -1;
643                         _exit(1);
644                 }
645                 status_sp_waiter_fd = fd;
646         }
647
648         closefrom(2);
649
650         /* Tell the caller we're ready */
651         nwritten = sys_write(status_sp_waiter_fd, &(char){0}, sizeof(char));
652         if (nwritten != sizeof(char)) {
653                 _exit(1);
654         }
655
656         tfork_global_free();
657         state = NULL;
658
659         do {
660                 ret = waitpid(pid, &status, 0);
661         } while ((ret == -1) && (errno == EINTR));
662         if (ret == -1) {
663                 status = errno;
664                 kill(pid, SIGKILL);
665         }
666
667         /*
668          * This writes the worker child exit status via our internal socketpair
669          * so the tfork_status() implementation can read it from its end.
670          */
671         nwritten = sys_write(status_sp_waiter_fd, &status, sizeof(status));
672         if (nwritten == -1) {
673                 if (errno != EPIPE && errno != ECONNRESET) {
674                         _exit(errno);
675                 }
676                 /*
677                  * The caller exitted and didn't call tfork_status().
678                  */
679                 _exit(0);
680         }
681         if (nwritten != sizeof(status)) {
682                 _exit(1);
683         }
684
685         /*
686          * This write to the event_fd returned by tfork_event_fd() and notifies
687          * the caller that the worker child is done and he may now call
688          * tfork_status().
689          */
690         nwritten = sys_write(event_pipe_waiter_fd, &(char){0}, sizeof(char));
691         if (nwritten != sizeof(char)) {
692                 _exit(1);
693         }
694
695         /*
696          * Wait for our parent (the process that called tfork_create()) to
697          * close() the socketpair fd in tfork_status().
698          *
699          * Again, the caller might have exitted without calling tfork_status().
700          */
701         nread = sys_read(status_sp_waiter_fd, &c, 1);
702         if (nread == -1) {
703                 if (errno == EPIPE || errno == ECONNRESET) {
704                         _exit(0);
705                 }
706                 _exit(errno);
707         }
708         if (nread != 1) {
709                 _exit(255);
710         }
711
712         _exit(0);
713 }
714
715 static int tfork_create_reap_waiter(pid_t waiter_pid)
716 {
717         pid_t pid;
718         int waiter_status;
719
720         if (waiter_pid == -1) {
721                 return 0;
722         }
723
724         kill(waiter_pid, SIGKILL);
725
726         do {
727                 pid = waitpid(waiter_pid, &waiter_status, 0);
728         } while ((pid == -1) && (errno == EINTR));
729         assert(pid == waiter_pid);
730
731         return 0;
732 }
733
734 struct tfork *tfork_create(void)
735 {
736         struct tfork_state *state = NULL;
737         struct tfork *t = NULL;
738         pid_t pid;
739         int saved_errno;
740         int ret = 0;
741
742 #ifdef HAVE_PTHREAD
743         ret = pthread_once(&tfork_global_is_initialized,
744                            tfork_global_initialize);
745         if (ret != 0) {
746                 return NULL;
747         }
748 #else
749         tfork_global_initialize();
750 #endif
751
752         state = tfork_global_get();
753         if (state == NULL) {
754                 return NULL;
755         }
756         *state = (struct tfork_state) {
757                 .waiter_pid = -1,
758                 .waiter_errno = ECANCELED,
759                 .worker_pid = -1,
760         };
761
762         t = malloc(sizeof(struct tfork));
763         if (t == NULL) {
764                 ret = -1;
765                 goto cleanup;
766         }
767
768         *t = (struct tfork) {
769                 .event_fd = -1,
770                 .status_fd = -1,
771                 .waiter_pid = -1,
772                 .worker_pid = -1,
773         };
774
775         ret = tfork_install_sigchld_handler(&state->waiter_pid);
776         if (ret != 0) {
777                 goto cleanup;
778         }
779
780         pid = tfork_start_waiter_and_worker(state,
781                                             &t->event_fd,
782                                             &t->status_fd);
783         if (pid == -1) {
784                 ret = -1;
785                 goto cleanup;
786         }
787         if (pid == 0) {
788                 /* In the worker */
789                 tfork_global_free();
790                 t->worker_pid = 0;
791                 return t;
792         }
793
794         /*
795          * In a threaded process there's no data race on t->waiter_pid as
796          * we're serializing globally via tfork_acquire_sighandling() and
797          * tfork_release_sighandling().
798          */
799         TFORK_ANNOTATE_BENIGN_RACE(&t->waiter_pid);
800
801         t->waiter_pid = pid;
802         t->worker_pid = state->worker_pid;
803
804 cleanup:
805         if (ret == -1) {
806                 saved_errno = errno;
807
808                 if (t != NULL) {
809                         if (t->status_fd != -1) {
810                                 close(t->status_fd);
811                         }
812                         if (t->event_fd != -1) {
813                                 close(t->event_fd);
814                         }
815
816                         ret = tfork_create_reap_waiter(state->waiter_pid);
817                         assert(ret == 0);
818
819                         free(t);
820                         t = NULL;
821                 }
822         }
823
824         ret = tfork_uninstall_sigchld_handler();
825         assert(ret == 0);
826
827         tfork_global_free();
828
829         if (ret == -1) {
830                 errno = saved_errno;
831         }
832         return t;
833 }
834
835 pid_t tfork_child_pid(const struct tfork *t)
836 {
837         return t->worker_pid;
838 }
839
840 int tfork_event_fd(struct tfork *t)
841 {
842         int fd = t->event_fd;
843
844         assert(t->event_fd != -1);
845         t->event_fd = -1;
846
847         return fd;
848 }
849
850 int tfork_status(struct tfork **_t, bool wait)
851 {
852         struct tfork *t = *_t;
853         int status;
854         ssize_t nread;
855         int waiter_status;
856         pid_t pid;
857         int ret;
858
859         if (t == NULL) {
860                 return -1;
861         }
862
863         if (wait) {
864                 set_blocking(t->status_fd, true);
865
866                 nread = sys_read(t->status_fd, &status, sizeof(int));
867         } else {
868                 set_blocking(t->status_fd, false);
869
870                 nread = read(t->status_fd, &status, sizeof(int));
871                 if ((nread == -1) &&
872                     ((errno == EAGAIN) || (errno == EWOULDBLOCK) || errno == EINTR)) {
873                         errno = EAGAIN;
874                         return -1;
875                 }
876         }
877         if (nread != sizeof(int)) {
878                 return -1;
879         }
880
881         ret = tfork_install_sigchld_handler(&t->waiter_pid);
882         if (ret != 0) {
883                 return -1;
884         }
885
886         /*
887          * This triggers process exit in the waiter.
888          * We write to the fd as well as closing it, as any tforked sibling
889          * processes will also have the writable end of this socket open.
890          *
891          */
892         {
893                 size_t nwritten;
894                 nwritten = sys_write(t->status_fd, &(char){0}, sizeof(char));
895                 if (nwritten != sizeof(char)) {
896                         close(t->status_fd);
897                         return -1;
898                 }
899         }
900         close(t->status_fd);
901
902         do {
903                 pid = waitpid(t->waiter_pid, &waiter_status, 0);
904         } while ((pid == -1) && (errno == EINTR));
905         assert(pid == t->waiter_pid);
906
907         if (t->event_fd != -1) {
908                 close(t->event_fd);
909                 t->event_fd = -1;
910         }
911
912         free(t);
913         t = NULL;
914         *_t = NULL;
915
916         ret = tfork_uninstall_sigchld_handler();
917         assert(ret == 0);
918
919         return status;
920 }
921
922 int tfork_destroy(struct tfork **_t)
923 {
924         struct tfork *t = *_t;
925         int ret;
926
927         if (t == NULL) {
928                 errno = EINVAL;
929                 return -1;
930         }
931
932         kill(t->worker_pid, SIGKILL);
933
934         ret = tfork_status(_t, true);
935         if (ret == -1) {
936                 return -1;
937         }
938
939         return 0;
940 }