rktio: always set signal mask to empty after fork

Saving and restoring the signal-mask state does not work right, since
rktio itself may block SIGCHLD in some cases, and it doesn't seem
useful/right to preserve the mask after fork.
This commit is contained in:
Matthew Flatt 2021-02-12 05:43:04 -07:00
parent 6cfc7b880b
commit 4c836a1dd1
5 changed files with 45 additions and 27 deletions

View File

@ -595,7 +595,10 @@
exe exe
(path->complete-path "unix_check.c" (or (current-load-relative-directory) (path->complete-path "unix_check.c" (or (current-load-relative-directory)
(current-directory))))) (current-directory)))))
(test #t 'subprocess-state (system* exe))) (test #t 'subprocess-state (let ([o (open-output-bytes)])
(or (parameterize ([current-output-port o])
(system* exe))
(get-output-bytes o)))))
(delete-directory/files dir))) (delete-directory/files dir)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

View File

@ -1,5 +1,6 @@
#include <stdio.h> #include <stdio.h>
#include <signal.h> #include <signal.h>
#include <stdio.h>
/* Make sure a child process is started with normal properties, such /* Make sure a child process is started with normal properties, such
as no blocked signals */ as no blocked signals */
@ -11,10 +12,12 @@ int main()
int i; int i;
/* SIGPROF tends to be near the end of the range of signal IDs */ /* SIGPROF tends to be near the end of the range of signal IDs */
for (i = 1; i < SIGPROF; i++) { for (i = 1; i <= SIGPROF; i++) {
if (sigaction(i, NULL, &sa) == 0) { if (sigaction(i, NULL, &sa) == 0) {
if (sa.sa_handler != SIG_DFL) if (sa.sa_handler != SIG_DFL) {
printf("handler %d: %p\n", i, (void *)sa.sa_handler);
return 1; return 1;
}
} else { } else {
/* sigaction sometimes isn't allowed at all on SIGKILL, /* sigaction sometimes isn't allowed at all on SIGKILL,
for example, so ignore that failure */ for example, so ignore that failure */
@ -24,8 +27,22 @@ int main()
sigemptyset(&set); sigemptyset(&set);
sigprocmask(SIG_BLOCK, &set, &old_set); sigprocmask(SIG_BLOCK, &set, &old_set);
return (sigismember(&old_set, SIGCHLD) if (sigismember(&old_set, SIGCHLD)) {
|| sigismember(&old_set, SIGINT) printf("masked: SIGCHLD\n");
|| sigismember(&old_set, SIGHUP) return 1;
|| sigismember(&old_set, SIGQUIT)); }
if (sigismember(&old_set, SIGINT)) {
printf("masked: SIGINT\n");
return 1;
}
if (sigismember(&old_set, SIGHUP)) {
printf("masked: SIGHUP\n");
return 1;
}
if (sigismember(&old_set, SIGQUIT)) {
printf("masked: SIGQUIT\n");
return 1;
}
return 0;
} }

View File

@ -1004,7 +1004,9 @@ RKTIO_EXTERN void rktio_install_os_signal_handler(rktio_t *rktio);
Ctl-C on Windows) to signal the handle of `rktio` and also records Ctl-C on Windows) to signal the handle of `rktio` and also records
the signal for reporting via `rktio_poll_os_signal`. Only one the signal for reporting via `rktio_poll_os_signal`. Only one
`rktio` can be registered this way at a time. This function must `rktio` can be registered this way at a time. This function must
not be called in two threads at the same time. */ not be called in two threads at the same time; more generally, it
can only be called when `rktio_will_modify_os_signal_handler`
can be called for SIGINT, etc. */
RKTIO_EXTERN_NOERR int rktio_poll_os_signal(rktio_t *rktio); RKTIO_EXTERN_NOERR int rktio_poll_os_signal(rktio_t *rktio);
/* Returns one of the following, not counting the last one: */ /* Returns one of the following, not counting the last one: */
@ -1021,11 +1023,11 @@ RKTIO_EXTERN void rktio_will_modify_os_signal_handler(int sig_id);
about to be modified within the process but outside of rktio, where about to be modified within the process but outside of rktio, where
`sig_id` is a signal identifier --- such as SIGINT or SIGTERM. This `sig_id` is a signal identifier --- such as SIGINT or SIGTERM. This
notification allows rktio to record the current signal disposition notification allows rktio to record the current signal disposition
so that it can be restored after forking a new Unix process. so that it can be restored after forking a new Unix process. Signal
Signal registrations should happen only before multiple threads use registrations should happen only before multiple threads use rktio,
rktio, and registration of the signal can happen before any and registration of the signal can happen before any `rktio_init`
`rktio_init` call. On the first `rktio_will_modify_os_signal_handler` call. After a signal is registered, trying to re-register it after
call, the signal mask is also recorded to be restored in a fork. */ threads start is harmless. */
/*************************************************/ /*************************************************/
/* Time and date */ /* Time and date */

View File

@ -982,6 +982,10 @@ int rktio_process_init(rktio_t *rktio)
it's a per-thread setting on Linux, and we want SIGCHLD blocked everywhere. */ it's a per-thread setting on Linux, and we want SIGCHLD blocked everywhere. */
block_sigchld(); block_sigchld();
/* We'll set a handler later (possibly after other threads start),
so register SIGCHLD now: */
rktio_will_modify_os_signal_handler(SIGCHLD);
centralized_start_child_signal_handler(); centralized_start_child_signal_handler();
#endif #endif

View File

@ -127,18 +127,10 @@ typedef struct signal_handler_saved_disposition {
} signal_handler_saved_disposition; } signal_handler_saved_disposition;
static signal_handler_saved_disposition *saved_dispositions; static signal_handler_saved_disposition *saved_dispositions;
#ifdef RKTIO_SYSTEM_UNIX
static sigset_t initial_procmask;
#endif
void rktio_will_modify_os_signal_handler(int sig_id) { void rktio_will_modify_os_signal_handler(int sig_id) {
signal_handler_saved_disposition *saved; signal_handler_saved_disposition *saved;
#ifdef RKTIO_SYSTEM_UNIX
if (saved_dispositions == NULL)
sigprocmask(SIG_SETMASK, NULL, &initial_procmask);
#endif
for (saved = saved_dispositions; saved; saved = saved->next) for (saved = saved_dispositions; saved; saved = saved->next)
if (saved->sig_id == sig_id) if (saved->sig_id == sig_id)
return; return;
@ -156,13 +148,13 @@ void rktio_will_modify_os_signal_handler(int sig_id) {
#ifdef RKTIO_SYSTEM_UNIX #ifdef RKTIO_SYSTEM_UNIX
/* called in a child thread after `fork */ /* called in a child thread after `fork */
void rktio_restore_modified_signal_handlers() { void rktio_restore_modified_signal_handlers() {
if (saved_dispositions) {
signal_handler_saved_disposition *saved; signal_handler_saved_disposition *saved;
sigset_t set;
for (saved = saved_dispositions; saved; saved = saved->next) for (saved = saved_dispositions; saved; saved = saved->next)
sigaction(saved->sig_id, &saved->sa, NULL); sigaction(saved->sig_id, &saved->sa, NULL);
sigprocmask(SIG_SETMASK, &initial_procmask, NULL); sigemptyset(&set);
} sigprocmask(SIG_SETMASK, &set, NULL);
} }
#endif #endif