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
(path->complete-path "unix_check.c" (or (current-load-relative-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)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

View File

@ -1,5 +1,6 @@
#include <stdio.h>
#include <signal.h>
#include <stdio.h>
/* Make sure a child process is started with normal properties, such
as no blocked signals */
@ -11,10 +12,12 @@ int main()
int i;
/* 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 (sa.sa_handler != SIG_DFL)
if (sa.sa_handler != SIG_DFL) {
printf("handler %d: %p\n", i, (void *)sa.sa_handler);
return 1;
}
} else {
/* sigaction sometimes isn't allowed at all on SIGKILL,
for example, so ignore that failure */
@ -24,8 +27,22 @@ int main()
sigemptyset(&set);
sigprocmask(SIG_BLOCK, &set, &old_set);
return (sigismember(&old_set, SIGCHLD)
|| sigismember(&old_set, SIGINT)
|| sigismember(&old_set, SIGHUP)
|| sigismember(&old_set, SIGQUIT));
if (sigismember(&old_set, SIGCHLD)) {
printf("masked: SIGCHLD\n");
return 1;
}
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
the signal for reporting via `rktio_poll_os_signal`. Only one
`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);
/* 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
`sig_id` is a signal identifier --- such as SIGINT or SIGTERM. This
notification allows rktio to record the current signal disposition
so that it can be restored after forking a new Unix process.
Signal registrations should happen only before multiple threads use
rktio, and registration of the signal can happen before any
`rktio_init` call. On the first `rktio_will_modify_os_signal_handler`
call, the signal mask is also recorded to be restored in a fork. */
so that it can be restored after forking a new Unix process. Signal
registrations should happen only before multiple threads use rktio,
and registration of the signal can happen before any `rktio_init`
call. After a signal is registered, trying to re-register it after
threads start is harmless. */
/*************************************************/
/* 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. */
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();
#endif

View File

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