talloc: version 2.1.12
[Samba.git] / lib / util / tfork.c
blob8ed5811c536fed5e64b7c89eb272f7f2aecaa7df
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 * +----------+
62 * The resulting (private) state per tfork_create() call, returned as a opaque
63 * handle to the caller.
65 struct tfork {
67 * This is returned to the caller with tfork_event_fd()
69 int event_fd;
72 * This is used in the caller by tfork_status() to read the worker exit
73 * status and to tell the waiter to exit by closing the fd.
75 int status_fd;
77 pid_t waiter_pid;
78 pid_t worker_pid;
82 * Internal per-thread state maintained while inside tfork.
84 struct tfork_state {
85 pid_t waiter_pid;
86 int waiter_errno;
88 pid_t worker_pid;
92 * A global state that synchronizes access to handling SIGCHLD and waiting for
93 * childs.
95 struct tfork_signal_state {
96 bool available;
98 #ifdef HAVE_PTHREAD
99 pthread_cond_t cond;
100 pthread_mutex_t mutex;
101 #endif
104 * pid of the waiter child. This points at waiter_pid in either struct
105 * tfork or struct tfork_state, depending on who called
106 * tfork_install_sigchld_handler().
108 * When tfork_install_sigchld_handler() is called the waiter_pid is
109 * still -1 and only set later after fork(), that's why this is must be
110 * a pointer. The signal handler checks this.
112 pid_t *pid;
114 struct sigaction oldact;
115 sigset_t oldset;
118 static struct tfork_signal_state signal_state;
120 #ifdef HAVE_PTHREAD
121 static pthread_once_t tfork_global_is_initialized = PTHREAD_ONCE_INIT;
122 static pthread_key_t tfork_global_key;
123 #else
124 static struct tfork_state *global_state;
125 #endif
127 static void tfork_sigchld_handler(int signum, siginfo_t *si, void *p);
129 #ifdef HAVE_PTHREAD
130 static void tfork_global_destructor(void *state)
132 anonymous_shared_free(state);
134 #endif
136 static int tfork_acquire_sighandling(void)
138 int ret = 0;
140 #ifdef HAVE_PTHREAD
141 ret = pthread_mutex_lock(&signal_state.mutex);
142 if (ret != 0) {
143 return ret;
146 while (!signal_state.available) {
147 ret = pthread_cond_wait(&signal_state.cond,
148 &signal_state.mutex);
149 if (ret != 0) {
150 return ret;
154 signal_state.available = false;
156 ret = pthread_mutex_unlock(&signal_state.mutex);
157 if (ret != 0) {
158 return ret;
160 #endif
162 return ret;
165 static int tfork_release_sighandling(void)
167 int ret = 0;
169 #ifdef HAVE_PTHREAD
170 ret = pthread_mutex_lock(&signal_state.mutex);
171 if (ret != 0) {
172 return ret;
175 signal_state.available = true;
177 ret = pthread_cond_signal(&signal_state.cond);
178 if (ret != 0) {
179 pthread_mutex_unlock(&signal_state.mutex);
180 return ret;
183 ret = pthread_mutex_unlock(&signal_state.mutex);
184 if (ret != 0) {
185 return ret;
187 #endif
189 return ret;
192 #ifdef HAVE_PTHREAD
193 static void tfork_atfork_prepare(void)
195 int ret;
197 ret = pthread_mutex_lock(&signal_state.mutex);
198 assert(ret == 0);
201 static void tfork_atfork_parent(void)
203 int ret;
205 ret = pthread_mutex_unlock(&signal_state.mutex);
206 assert(ret == 0);
208 #endif
210 static void tfork_atfork_child(void)
212 int ret;
214 #ifdef HAVE_PTHREAD
215 ret = pthread_mutex_unlock(&signal_state.mutex);
216 assert(ret == 0);
218 ret = pthread_key_delete(tfork_global_key);
219 assert(ret == 0);
221 ret = pthread_key_create(&tfork_global_key, tfork_global_destructor);
222 assert(ret == 0);
225 * There's no way to destroy a condition variable if there are waiters,
226 * pthread_cond_destroy() will return EBUSY. Just zero out memory and
227 * then initialize again. This is not backed by POSIX but should be ok.
229 ZERO_STRUCT(signal_state.cond);
230 ret = pthread_cond_init(&signal_state.cond, NULL);
231 assert(ret == 0);
232 #endif
234 if (signal_state.pid != NULL) {
236 ret = sigaction(SIGCHLD, &signal_state.oldact, NULL);
237 assert(ret == 0);
239 #ifdef HAVE_PTHREAD
240 ret = pthread_sigmask(SIG_SETMASK, &signal_state.oldset, NULL);
241 #else
242 ret = sigprocmask(SIG_SETMASK, &signal_state.oldset, NULL);
243 assert(ret == 0);
244 #endif
246 signal_state.pid = NULL;
249 signal_state.available = true;
252 static void tfork_global_initialize(void)
254 #ifdef HAVE_PTHREAD
255 int ret;
257 pthread_atfork(tfork_atfork_prepare,
258 tfork_atfork_parent,
259 tfork_atfork_child);
261 ret = pthread_key_create(&tfork_global_key, tfork_global_destructor);
262 assert(ret == 0);
264 ret = pthread_mutex_init(&signal_state.mutex, NULL);
265 assert(ret == 0);
267 ret = pthread_cond_init(&signal_state.cond, NULL);
268 assert(ret == 0);
269 #endif
271 signal_state.available = true;
274 static struct tfork_state *tfork_global_get(void)
276 struct tfork_state *state = NULL;
277 #ifdef HAVE_PTHREAD
278 int ret;
279 #endif
281 #ifdef HAVE_PTHREAD
282 state = (struct tfork_state *)pthread_getspecific(tfork_global_key);
283 #else
284 state = global_state;
285 #endif
286 if (state != NULL) {
287 return state;
290 state = (struct tfork_state *)anonymous_shared_allocate(
291 sizeof(struct tfork_state));
292 if (state == NULL) {
293 return NULL;
296 #ifdef HAVE_PTHREAD
297 ret = pthread_setspecific(tfork_global_key, state);
298 if (ret != 0) {
299 anonymous_shared_free(state);
300 return NULL;
302 #endif
303 return state;
306 static void tfork_global_free(void)
308 struct tfork_state *state = NULL;
309 #ifdef HAVE_PTHREAD
310 int ret;
311 #endif
313 #ifdef HAVE_PTHREAD
314 state = (struct tfork_state *)pthread_getspecific(tfork_global_key);
315 #else
316 state = global_state;
317 #endif
318 if (state == NULL) {
319 return;
322 #ifdef HAVE_PTHREAD
323 ret = pthread_setspecific(tfork_global_key, NULL);
324 if (ret != 0) {
325 return;
327 #endif
328 anonymous_shared_free(state);
332 * Only one thread at a time is allowed to handle SIGCHLD signals
334 static int tfork_install_sigchld_handler(pid_t *pid)
336 int ret;
337 struct sigaction act;
338 sigset_t set;
340 ret = tfork_acquire_sighandling();
341 if (ret != 0) {
342 return -1;
345 assert(signal_state.pid == NULL);
346 signal_state.pid = pid;
348 act = (struct sigaction) {
349 .sa_sigaction = tfork_sigchld_handler,
350 .sa_flags = SA_SIGINFO,
353 ret = sigaction(SIGCHLD, &act, &signal_state.oldact);
354 if (ret != 0) {
355 return -1;
358 sigemptyset(&set);
359 sigaddset(&set, SIGCHLD);
360 #ifdef HAVE_PTHREAD
361 ret = pthread_sigmask(SIG_UNBLOCK, &set, &signal_state.oldset);
362 #else
363 ret = sigprocmask(SIG_UNBLOCK, &set, &signal_state.oldset);
364 #endif
365 if (ret != 0) {
366 return -1;
369 return 0;
372 static int tfork_uninstall_sigchld_handler(void)
374 int ret;
376 signal_state.pid = NULL;
378 ret = sigaction(SIGCHLD, &signal_state.oldact, NULL);
379 if (ret != 0) {
380 return -1;
383 #ifdef HAVE_PTHREAD
384 ret = pthread_sigmask(SIG_SETMASK, &signal_state.oldset, NULL);
385 #else
386 ret = sigprocmask(SIG_SETMASK, &signal_state.oldset, NULL);
387 #endif
388 if (ret != 0) {
389 return -1;
392 ret = tfork_release_sighandling();
393 if (ret != 0) {
394 return -1;
397 return 0;
400 static void tfork_sigchld_handler(int signum, siginfo_t *si, void *p)
402 if ((signal_state.pid != NULL) &&
403 (*signal_state.pid != -1) &&
404 (si->si_pid == *signal_state.pid))
406 return;
410 * Not our child, forward to old handler
412 if (signal_state.oldact.sa_flags & SA_SIGINFO) {
413 signal_state.oldact.sa_sigaction(signum, si, p);
414 return;
417 if (signal_state.oldact.sa_handler == SIG_IGN) {
418 return;
420 if (signal_state.oldact.sa_handler == SIG_DFL) {
421 return;
423 signal_state.oldact.sa_handler(signum);
426 static pid_t tfork_start_waiter_and_worker(struct tfork_state *state,
427 int *_event_fd,
428 int *_status_fd)
430 int p[2];
431 int status_sp_caller_fd = -1;
432 int status_sp_waiter_fd = -1;
433 int event_pipe_caller_fd = -1;
434 int event_pipe_waiter_fd = -1;
435 int ready_pipe_caller_fd = -1;
436 int ready_pipe_worker_fd = -1;
437 ssize_t nwritten;
438 ssize_t nread;
439 pid_t pid;
440 int status;
441 int fd;
442 char c;
443 int ret;
445 *_event_fd = -1;
446 *_status_fd = -1;
448 if (state == NULL) {
449 return -1;
452 ret = socketpair(AF_UNIX, SOCK_STREAM, 0, p);
453 if (ret != 0) {
454 return -1;
456 set_close_on_exec(p[0]);
457 set_close_on_exec(p[1]);
458 status_sp_caller_fd = p[0];
459 status_sp_waiter_fd = p[1];
461 ret = pipe(p);
462 if (ret != 0) {
463 close(status_sp_caller_fd);
464 close(status_sp_waiter_fd);
465 return -1;
467 set_close_on_exec(p[0]);
468 set_close_on_exec(p[1]);
469 event_pipe_caller_fd = p[0];
470 event_pipe_waiter_fd = p[1];
473 ret = pipe(p);
474 if (ret != 0) {
475 close(status_sp_caller_fd);
476 close(status_sp_waiter_fd);
477 close(event_pipe_caller_fd);
478 close(event_pipe_waiter_fd);
479 return -1;
481 set_close_on_exec(p[0]);
482 set_close_on_exec(p[1]);
483 ready_pipe_worker_fd = p[0];
484 ready_pipe_caller_fd = p[1];
486 pid = fork();
487 if (pid == -1) {
488 close(status_sp_caller_fd);
489 close(status_sp_waiter_fd);
490 close(event_pipe_caller_fd);
491 close(event_pipe_waiter_fd);
492 close(ready_pipe_caller_fd);
493 close(ready_pipe_worker_fd);
494 return -1;
496 if (pid != 0) {
497 /* The caller */
499 state->waiter_pid = pid;
501 close(status_sp_waiter_fd);
502 close(event_pipe_waiter_fd);
503 close(ready_pipe_worker_fd);
505 set_blocking(event_pipe_caller_fd, false);
508 * wait for the waiter to get ready.
510 nread = sys_read(status_sp_caller_fd, &c, sizeof(char));
511 if (nread != sizeof(char)) {
512 return -1;
516 * Notify the worker to start.
518 nwritten = sys_write(ready_pipe_caller_fd,
519 &(char){0}, sizeof(char));
520 if (nwritten != sizeof(char)) {
521 close(ready_pipe_caller_fd);
522 return -1;
524 close(ready_pipe_caller_fd);
526 *_event_fd = event_pipe_caller_fd;
527 *_status_fd = status_sp_caller_fd;
529 return pid;
532 #ifndef HAVE_PTHREAD
533 /* cleanup sigchld_handler */
534 tfork_atfork_child();
535 #endif
538 * The "waiter" child.
540 setproctitle("tfork waiter process");
541 CatchSignal(SIGCHLD, SIG_DFL);
543 close(status_sp_caller_fd);
544 close(event_pipe_caller_fd);
545 close(ready_pipe_caller_fd);
547 pid = fork();
548 if (pid == -1) {
549 state->waiter_errno = errno;
550 _exit(0);
552 if (pid == 0) {
554 * The worker child.
557 close(status_sp_waiter_fd);
558 close(event_pipe_waiter_fd);
561 * Wait for the caller to give us a go!
563 nread = sys_read(ready_pipe_worker_fd, &c, sizeof(char));
564 if (nread != sizeof(char)) {
565 _exit(1);
567 close(ready_pipe_worker_fd);
569 return 0;
571 state->worker_pid = pid;
573 close(ready_pipe_worker_fd);
576 * We're going to stay around until child2 exits, so lets close all fds
577 * other then the pipe fd we may have inherited from the caller.
579 * Dup event_sp_waiter_fd and status_sp_waiter_fd onto fds 0 and 1 so we
580 * can then call closefrom(2).
582 if (event_pipe_waiter_fd > 0) {
583 int dup_fd = 0;
585 if (status_sp_waiter_fd == 0) {
586 dup_fd = 1;
589 do {
590 fd = dup2(event_pipe_waiter_fd, dup_fd);
591 } while ((fd == -1) && (errno == EINTR));
592 if (fd == -1) {
593 state->waiter_errno = errno;
594 kill(state->worker_pid, SIGKILL);
595 state->worker_pid = -1;
596 _exit(1);
598 event_pipe_waiter_fd = fd;
601 if (status_sp_waiter_fd > 1) {
602 do {
603 fd = dup2(status_sp_waiter_fd, 1);
604 } while ((fd == -1) && (errno == EINTR));
605 if (fd == -1) {
606 state->waiter_errno = errno;
607 kill(state->worker_pid, SIGKILL);
608 state->worker_pid = -1;
609 _exit(1);
611 status_sp_waiter_fd = fd;
614 closefrom(2);
616 /* Tell the caller we're ready */
617 nwritten = sys_write(status_sp_waiter_fd, &(char){0}, sizeof(char));
618 if (nwritten != sizeof(char)) {
619 _exit(1);
622 tfork_global_free();
623 state = NULL;
625 do {
626 ret = waitpid(pid, &status, 0);
627 } while ((ret == -1) && (errno == EINTR));
628 if (ret == -1) {
629 status = errno;
630 kill(pid, SIGKILL);
634 * This writes the worker child exit status via our internal socketpair
635 * so the tfork_status() implementation can read it from its end.
637 nwritten = sys_write(status_sp_waiter_fd, &status, sizeof(status));
638 if (nwritten == -1) {
639 if (errno != EPIPE && errno != ECONNRESET) {
640 _exit(errno);
643 * The caller exitted and didn't call tfork_status().
645 _exit(0);
647 if (nwritten != sizeof(status)) {
648 _exit(1);
652 * This write to the event_fd returned by tfork_event_fd() and notifies
653 * the caller that the worker child is done and he may now call
654 * tfork_status().
656 nwritten = sys_write(event_pipe_waiter_fd, &(char){0}, sizeof(char));
657 if (nwritten != sizeof(char)) {
658 _exit(1);
662 * Wait for our parent (the process that called tfork_create()) to
663 * close() the socketpair fd in tfork_status().
665 * Again, the caller might have exitted without calling tfork_status().
667 nread = sys_read(status_sp_waiter_fd, &c, 1);
668 if (nread == -1) {
669 if (errno == EPIPE || errno == ECONNRESET) {
670 _exit(0);
672 _exit(errno);
674 if (nread != 1) {
675 _exit(255);
678 _exit(0);
681 static int tfork_create_reap_waiter(pid_t waiter_pid)
683 pid_t pid;
684 int waiter_status;
686 if (waiter_pid == -1) {
687 return 0;
690 kill(waiter_pid, SIGKILL);
692 do {
693 pid = waitpid(waiter_pid, &waiter_status, 0);
694 } while ((pid == -1) && (errno == EINTR));
695 assert(pid == waiter_pid);
697 return 0;
700 struct tfork *tfork_create(void)
702 struct tfork_state *state = NULL;
703 struct tfork *t = NULL;
704 pid_t pid;
705 int saved_errno;
706 int ret = 0;
708 #ifdef HAVE_PTHREAD
709 ret = pthread_once(&tfork_global_is_initialized,
710 tfork_global_initialize);
711 if (ret != 0) {
712 return NULL;
714 #else
715 tfork_global_initialize();
716 #endif
718 state = tfork_global_get();
719 if (state == NULL) {
720 return NULL;
722 *state = (struct tfork_state) {
723 .waiter_pid = -1,
724 .waiter_errno = ECANCELED,
725 .worker_pid = -1,
728 t = malloc(sizeof(struct tfork));
729 if (t == NULL) {
730 ret = -1;
731 goto cleanup;
734 *t = (struct tfork) {
735 .event_fd = -1,
736 .status_fd = -1,
737 .waiter_pid = -1,
738 .worker_pid = -1,
741 ret = tfork_install_sigchld_handler(&state->waiter_pid);
742 if (ret != 0) {
743 goto cleanup;
746 pid = tfork_start_waiter_and_worker(state,
747 &t->event_fd,
748 &t->status_fd);
749 if (pid == -1) {
750 ret = -1;
751 goto cleanup;
753 if (pid == 0) {
754 /* In the worker */
755 tfork_global_free();
756 t->worker_pid = 0;
757 return t;
760 t->waiter_pid = pid;
761 t->worker_pid = state->worker_pid;
763 cleanup:
764 if (ret == -1) {
765 saved_errno = errno;
767 if (t != NULL) {
768 if (t->status_fd != -1) {
769 close(t->status_fd);
771 if (t->event_fd != -1) {
772 close(t->event_fd);
775 ret = tfork_create_reap_waiter(state->waiter_pid);
776 assert(ret == 0);
778 free(t);
779 t = NULL;
783 ret = tfork_uninstall_sigchld_handler();
784 assert(ret == 0);
786 tfork_global_free();
788 if (ret == -1) {
789 errno = saved_errno;
791 return t;
794 pid_t tfork_child_pid(const struct tfork *t)
796 return t->worker_pid;
799 int tfork_event_fd(struct tfork *t)
801 int fd = t->event_fd;
803 assert(t->event_fd != -1);
804 t->event_fd = -1;
806 return fd;
809 int tfork_status(struct tfork **_t, bool wait)
811 struct tfork *t = *_t;
812 int status;
813 ssize_t nread;
814 int waiter_status;
815 pid_t pid;
816 int ret;
818 if (t == NULL) {
819 return -1;
822 if (wait) {
823 set_blocking(t->status_fd, true);
825 nread = sys_read(t->status_fd, &status, sizeof(int));
826 } else {
827 set_blocking(t->status_fd, false);
829 nread = read(t->status_fd, &status, sizeof(int));
830 if ((nread == -1) &&
831 ((errno == EAGAIN) || (errno == EWOULDBLOCK) || errno == EINTR)) {
832 errno = EAGAIN;
833 return -1;
836 if (nread != sizeof(int)) {
837 return -1;
840 ret = tfork_install_sigchld_handler(&t->waiter_pid);
841 if (ret != 0) {
842 return -1;
846 * This triggers process exit in the waiter.
847 * We write to the fd as well as closing it, as any tforked sibling
848 * processes will also have the writable end of this socket open.
852 size_t nwritten;
853 nwritten = sys_write(t->status_fd, &(char){0}, sizeof(char));
854 if (nwritten != sizeof(char)) {
855 close(t->status_fd);
856 return -1;
859 close(t->status_fd);
861 do {
862 pid = waitpid(t->waiter_pid, &waiter_status, 0);
863 } while ((pid == -1) && (errno == EINTR));
864 assert(pid == t->waiter_pid);
866 if (t->event_fd != -1) {
867 close(t->event_fd);
868 t->event_fd = -1;
871 free(t);
872 t = NULL;
873 *_t = NULL;
875 ret = tfork_uninstall_sigchld_handler();
876 assert(ret == 0);
878 return status;
881 int tfork_destroy(struct tfork **_t)
883 struct tfork *t = *_t;
884 int ret;
886 if (t == NULL) {
887 errno = EINVAL;
888 return -1;
891 kill(t->worker_pid, SIGKILL);
893 ret = tfork_status(_t, true);
894 if (ret == -1) {
895 return -1;
898 return 0;