Search for location of waf script
[Samba.git] / lib / util / tfork.c
blob4a5c08f7d7970d0a646a20ad07e636708767afd4
1 /*
2 fork on steroids to avoid SIGCHLD and waitpid
4 Copyright (C) Stefan Metzmacher 2010
5 Copyright (C) Ralph Boehme 2017
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.
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.
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/>.
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"
30 #ifdef HAVE_PTHREAD
31 #include <pthread.h>
32 #endif
34 #ifdef NDEBUG
35 #undef NDEBUG
36 #endif
37 #include <assert.h>
40 * This is how the process hierarchy looks like:
42 * +----------+
43 * | caller |
44 * +----------+
45 * |
46 * fork
47 * |
48 * v
49 * +----------+
50 * | waiter |
51 * +----------+
52 * |
53 * fork
54 * |
55 * v
56 * +----------+
57 * | worker |
58 * +----------+
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
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");
74 * The resulting (private) state per tfork_create() call, returned as a opaque
75 * handle to the caller.
77 struct tfork {
79 * This is returned to the caller with tfork_event_fd()
81 int event_fd;
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.
87 int status_fd;
89 pid_t waiter_pid;
90 pid_t worker_pid;
94 * Internal per-thread state maintained while inside tfork.
96 struct tfork_state {
97 pid_t waiter_pid;
98 int waiter_errno;
100 pid_t worker_pid;
104 * A global state that synchronizes access to handling SIGCHLD and waiting for
105 * childs.
107 struct tfork_signal_state {
108 bool available;
110 #ifdef HAVE_PTHREAD
111 pthread_cond_t cond;
112 pthread_mutex_t mutex;
113 #endif
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().
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.
124 pid_t *pid;
126 struct sigaction oldact;
127 sigset_t oldset;
130 static struct tfork_signal_state signal_state;
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
139 static void tfork_sigchld_handler(int signum, siginfo_t *si, void *p);
141 #ifdef HAVE_PTHREAD
142 static void tfork_global_destructor(void *state)
144 anonymous_shared_free(state);
146 #endif
148 static int tfork_acquire_sighandling(void)
150 int ret = 0;
152 #ifdef HAVE_PTHREAD
153 ret = pthread_mutex_lock(&signal_state.mutex);
154 if (ret != 0) {
155 return ret;
158 while (!signal_state.available) {
159 ret = pthread_cond_wait(&signal_state.cond,
160 &signal_state.mutex);
161 if (ret != 0) {
162 return ret;
166 signal_state.available = false;
168 ret = pthread_mutex_unlock(&signal_state.mutex);
169 if (ret != 0) {
170 return ret;
172 #endif
174 return ret;
177 static int tfork_release_sighandling(void)
179 int ret = 0;
181 #ifdef HAVE_PTHREAD
182 ret = pthread_mutex_lock(&signal_state.mutex);
183 if (ret != 0) {
184 return ret;
187 signal_state.available = true;
189 ret = pthread_cond_signal(&signal_state.cond);
190 if (ret != 0) {
191 pthread_mutex_unlock(&signal_state.mutex);
192 return ret;
195 ret = pthread_mutex_unlock(&signal_state.mutex);
196 if (ret != 0) {
197 return ret;
199 #endif
201 return ret;
204 #ifdef HAVE_PTHREAD
205 static void tfork_atfork_prepare(void)
207 int ret;
209 ret = pthread_mutex_lock(&signal_state.mutex);
210 assert(ret == 0);
213 static void tfork_atfork_parent(void)
215 int ret;
217 ret = pthread_mutex_unlock(&signal_state.mutex);
218 assert(ret == 0);
220 #endif
222 static void tfork_atfork_child(void)
224 int ret;
226 #ifdef HAVE_PTHREAD
227 ret = pthread_mutex_unlock(&signal_state.mutex);
228 assert(ret == 0);
230 ret = pthread_key_delete(tfork_global_key);
231 assert(ret == 0);
233 ret = pthread_key_create(&tfork_global_key, tfork_global_destructor);
234 assert(ret == 0);
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.
242 TFORK_ANNOTATE_BENIGN_RACE(&signal_state.cond);
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.
249 ZERO_STRUCT(signal_state.cond);
250 ret = pthread_cond_init(&signal_state.cond, NULL);
251 assert(ret == 0);
252 #endif
254 if (signal_state.pid != NULL) {
256 ret = sigaction(SIGCHLD, &signal_state.oldact, NULL);
257 assert(ret == 0);
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
266 signal_state.pid = NULL;
269 signal_state.available = true;
272 static void tfork_global_initialize(void)
274 #ifdef HAVE_PTHREAD
275 int ret;
277 pthread_atfork(tfork_atfork_prepare,
278 tfork_atfork_parent,
279 tfork_atfork_child);
281 ret = pthread_key_create(&tfork_global_key, tfork_global_destructor);
282 assert(ret == 0);
284 ret = pthread_mutex_init(&signal_state.mutex, NULL);
285 assert(ret == 0);
287 ret = pthread_cond_init(&signal_state.cond, NULL);
288 assert(ret == 0);
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().
295 TFORK_ANNOTATE_BENIGN_RACE(&signal_state.pid);
296 #endif
298 signal_state.available = true;
301 static struct tfork_state *tfork_global_get(void)
303 struct tfork_state *state = NULL;
304 #ifdef HAVE_PTHREAD
305 int ret;
306 #endif
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;
317 state = (struct tfork_state *)anonymous_shared_allocate(
318 sizeof(struct tfork_state));
319 if (state == NULL) {
320 return NULL;
323 #ifdef HAVE_PTHREAD
324 ret = pthread_setspecific(tfork_global_key, state);
325 if (ret != 0) {
326 anonymous_shared_free(state);
327 return NULL;
329 #endif
330 return state;
333 static void tfork_global_free(void)
335 struct tfork_state *state = NULL;
336 #ifdef HAVE_PTHREAD
337 int ret;
338 #endif
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;
349 #ifdef HAVE_PTHREAD
350 ret = pthread_setspecific(tfork_global_key, NULL);
351 if (ret != 0) {
352 return;
354 #endif
355 anonymous_shared_free(state);
359 * Only one thread at a time is allowed to handle SIGCHLD signals
361 static int tfork_install_sigchld_handler(pid_t *pid)
363 int ret;
364 struct sigaction act;
365 sigset_t set;
367 ret = tfork_acquire_sighandling();
368 if (ret != 0) {
369 return -1;
372 assert(signal_state.pid == NULL);
373 signal_state.pid = pid;
375 act = (struct sigaction) {
376 .sa_sigaction = tfork_sigchld_handler,
377 .sa_flags = SA_SIGINFO,
380 ret = sigaction(SIGCHLD, &act, &signal_state.oldact);
381 if (ret != 0) {
382 return -1;
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;
396 return 0;
399 static int tfork_uninstall_sigchld_handler(void)
401 int ret;
403 signal_state.pid = NULL;
405 ret = sigaction(SIGCHLD, &signal_state.oldact, NULL);
406 if (ret != 0) {
407 return -1;
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;
419 ret = tfork_release_sighandling();
420 if (ret != 0) {
421 return -1;
424 return 0;
427 static void tfork_sigchld_handler(int signum, siginfo_t *si, void *p)
429 if ((signal_state.pid != NULL) &&
430 (*signal_state.pid != -1) &&
431 (si->si_pid == *signal_state.pid))
433 return;
437 * Not our child, forward to old handler
439 if (signal_state.oldact.sa_flags & SA_SIGINFO) {
440 signal_state.oldact.sa_sigaction(signum, si, p);
441 return;
444 if (signal_state.oldact.sa_handler == SIG_IGN) {
445 return;
447 if (signal_state.oldact.sa_handler == SIG_DFL) {
448 return;
450 signal_state.oldact.sa_handler(signum);
453 static pid_t tfork_start_waiter_and_worker(struct tfork_state *state,
454 int *_event_fd,
455 int *_status_fd)
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;
472 *_event_fd = -1;
473 *_status_fd = -1;
475 if (state == NULL) {
476 return -1;
479 ret = socketpair(AF_UNIX, SOCK_STREAM, 0, p);
480 if (ret != 0) {
481 return -1;
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];
488 ret = pipe(p);
489 if (ret != 0) {
490 close(status_sp_caller_fd);
491 close(status_sp_waiter_fd);
492 return -1;
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];
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;
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];
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;
523 if (pid != 0) {
524 /* The caller */
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().
531 TFORK_ANNOTATE_BENIGN_RACE(&state->waiter_pid);
533 state->waiter_pid = pid;
535 close(status_sp_waiter_fd);
536 close(event_pipe_waiter_fd);
537 close(ready_pipe_worker_fd);
539 set_blocking(event_pipe_caller_fd, false);
542 * wait for the waiter to get ready.
544 nread = sys_read(status_sp_caller_fd, &c, sizeof(char));
545 if (nread != sizeof(char)) {
546 return -1;
550 * Notify the worker to start.
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;
558 close(ready_pipe_caller_fd);
560 *_event_fd = event_pipe_caller_fd;
561 *_status_fd = status_sp_caller_fd;
563 return pid;
566 #ifndef HAVE_PTHREAD
567 /* cleanup sigchld_handler */
568 tfork_atfork_child();
569 #endif
572 * The "waiter" child.
574 setproctitle("tfork waiter process");
575 CatchSignal(SIGCHLD, SIG_DFL);
577 close(status_sp_caller_fd);
578 close(event_pipe_caller_fd);
579 close(ready_pipe_caller_fd);
581 pid = fork();
582 if (pid == -1) {
583 state->waiter_errno = errno;
584 _exit(0);
586 if (pid == 0) {
588 * The worker child.
591 close(status_sp_waiter_fd);
592 close(event_pipe_waiter_fd);
595 * Wait for the caller to give us a go!
597 nread = sys_read(ready_pipe_worker_fd, &c, sizeof(char));
598 if (nread != sizeof(char)) {
599 _exit(1);
601 close(ready_pipe_worker_fd);
603 return 0;
605 state->worker_pid = pid;
607 close(ready_pipe_worker_fd);
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.
613 * Dup event_sp_waiter_fd and status_sp_waiter_fd onto fds 0 and 1 so we
614 * can then call closefrom(2).
616 if (event_pipe_waiter_fd > 0) {
617 int dup_fd = 0;
619 if (status_sp_waiter_fd == 0) {
620 dup_fd = 1;
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);
632 event_pipe_waiter_fd = fd;
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);
645 status_sp_waiter_fd = fd;
648 closefrom(2);
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);
656 tfork_global_free();
657 state = NULL;
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);
668 * This writes the worker child exit status via our internal socketpair
669 * so the tfork_status() implementation can read it from its end.
671 nwritten = sys_write(status_sp_waiter_fd, &status, sizeof(status));
672 if (nwritten == -1) {
673 if (errno != EPIPE && errno != ECONNRESET) {
674 _exit(errno);
677 * The caller exitted and didn't call tfork_status().
679 _exit(0);
681 if (nwritten != sizeof(status)) {
682 _exit(1);
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().
690 nwritten = sys_write(event_pipe_waiter_fd, &(char){0}, sizeof(char));
691 if (nwritten != sizeof(char)) {
692 _exit(1);
696 * Wait for our parent (the process that called tfork_create()) to
697 * close() the socketpair fd in tfork_status().
699 * Again, the caller might have exitted without calling tfork_status().
701 nread = sys_read(status_sp_waiter_fd, &c, 1);
702 if (nread == -1) {
703 if (errno == EPIPE || errno == ECONNRESET) {
704 _exit(0);
706 _exit(errno);
708 if (nread != 1) {
709 _exit(255);
712 _exit(0);
715 static int tfork_create_reap_waiter(pid_t waiter_pid)
717 pid_t pid;
718 int waiter_status;
720 if (waiter_pid == -1) {
721 return 0;
724 kill(waiter_pid, SIGKILL);
726 do {
727 pid = waitpid(waiter_pid, &waiter_status, 0);
728 } while ((pid == -1) && (errno == EINTR));
729 assert(pid == waiter_pid);
731 return 0;
734 struct tfork *tfork_create(void)
736 struct tfork_state *state = NULL;
737 struct tfork *t = NULL;
738 pid_t pid;
739 int saved_errno;
740 int ret = 0;
742 #ifdef HAVE_PTHREAD
743 ret = pthread_once(&tfork_global_is_initialized,
744 tfork_global_initialize);
745 if (ret != 0) {
746 return NULL;
748 #else
749 tfork_global_initialize();
750 #endif
752 state = tfork_global_get();
753 if (state == NULL) {
754 return NULL;
756 *state = (struct tfork_state) {
757 .waiter_pid = -1,
758 .waiter_errno = ECANCELED,
759 .worker_pid = -1,
762 t = malloc(sizeof(struct tfork));
763 if (t == NULL) {
764 ret = -1;
765 goto cleanup;
768 *t = (struct tfork) {
769 .event_fd = -1,
770 .status_fd = -1,
771 .waiter_pid = -1,
772 .worker_pid = -1,
775 ret = tfork_install_sigchld_handler(&state->waiter_pid);
776 if (ret != 0) {
777 goto cleanup;
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;
787 if (pid == 0) {
788 /* In the worker */
789 tfork_global_free();
790 t->worker_pid = 0;
791 return t;
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().
799 TFORK_ANNOTATE_BENIGN_RACE(&t->waiter_pid);
801 t->waiter_pid = pid;
802 t->worker_pid = state->worker_pid;
804 cleanup:
805 if (ret == -1) {
806 saved_errno = errno;
808 if (t != NULL) {
809 if (t->status_fd != -1) {
810 close(t->status_fd);
812 if (t->event_fd != -1) {
813 close(t->event_fd);
816 ret = tfork_create_reap_waiter(state->waiter_pid);
817 assert(ret == 0);
819 free(t);
820 t = NULL;
824 ret = tfork_uninstall_sigchld_handler();
825 assert(ret == 0);
827 tfork_global_free();
829 if (ret == -1) {
830 errno = saved_errno;
832 return t;
835 pid_t tfork_child_pid(const struct tfork *t)
837 return t->worker_pid;
840 int tfork_event_fd(struct tfork *t)
842 int fd = t->event_fd;
844 assert(t->event_fd != -1);
845 t->event_fd = -1;
847 return fd;
850 int tfork_status(struct tfork **_t, bool wait)
852 struct tfork *t = *_t;
853 int status;
854 ssize_t nread;
855 int waiter_status;
856 pid_t pid;
857 int ret;
859 if (t == NULL) {
860 return -1;
863 if (wait) {
864 set_blocking(t->status_fd, true);
866 nread = sys_read(t->status_fd, &status, sizeof(int));
867 } else {
868 set_blocking(t->status_fd, false);
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;
877 if (nread != sizeof(int)) {
878 return -1;
881 ret = tfork_install_sigchld_handler(&t->waiter_pid);
882 if (ret != 0) {
883 return -1;
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.
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;
900 close(t->status_fd);
902 do {
903 pid = waitpid(t->waiter_pid, &waiter_status, 0);
904 } while ((pid == -1) && (errno == EINTR));
905 assert(pid == t->waiter_pid);
907 if (t->event_fd != -1) {
908 close(t->event_fd);
909 t->event_fd = -1;
912 free(t);
913 t = NULL;
914 *_t = NULL;
916 ret = tfork_uninstall_sigchld_handler();
917 assert(ret == 0);
919 return status;
922 int tfork_destroy(struct tfork **_t)
924 struct tfork *t = *_t;
925 int ret;
927 if (t == NULL) {
928 errno = EINVAL;
929 return -1;
932 kill(t->worker_pid, SIGKILL);
934 ret = tfork_status(_t, true);
935 if (ret == -1) {
936 return -1;
939 return 0;