From 0610a859d979db77aa6b1e3591d13c0d8a8a63c0 Mon Sep 17 00:00:00 2001 From: akr Date: Fri, 5 Sep 2014 12:46:09 +0000 Subject: * process.c (disable_child_handler_before_fork): New function. (disable_child_handler_fork_parent): Ditto. (disable_child_handler_fork_child): Ditto. (retry_fork_async_signal_safe): Call above functions to disable signal handlers in child process. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@47412 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- process.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 79 insertions(+), 2 deletions(-) (limited to 'process.c') diff --git a/process.c b/process.c index 5dd505b559..46547025eb 100644 --- a/process.c +++ b/process.c @@ -3384,6 +3384,77 @@ has_privilege(void) return 0; } +static void +disable_child_handler_before_fork(sigset_t *oldset) +{ + int ret; + sigset_t all; + + ret = sigfillset(&all); + if (ret == -1) + rb_sys_fail("sigfillset"); + + ret = pthread_sigmask(SIG_SETMASK, &all, oldset); /* not async-signal-safe */ + if (ret != 0) { + errno = ret; + rb_sys_fail("pthread_sigmask"); + } +} + +static void +disable_child_handler_fork_parent(sigset_t *oldset) +{ + int ret; + + ret = pthread_sigmask(SIG_SETMASK, oldset, NULL); /* not async-signal-safe */ + if (ret != 0) { + errno = ret; + rb_sys_fail("pthread_sigmask"); + } +} + +/* This function should be async-signal-safe. Actually it is. */ +static int +disable_child_handler_fork_child(sigset_t *oldset, char *errmsg, size_t errmsg_buflen) +{ + int sig; + int ret; + struct sigaction act, oact; + + act.sa_handler = SIG_DFL; + act.sa_flags = 0; + ret = sigemptyset(&act.sa_mask); /* async-signal-safe */ + if (ret == -1) { + ERRMSG("sigemptyset"); + return -1; + } + + for (sig = 1; sig < NSIG; sig++) { + ret = sigaction(sig, NULL, &oact); /* async-signal-safe */ + if (ret == -1 && errno == EINVAL) { + continue; /* Ignore invalid signal number. */ + } + if (ret == -1) { + ERRMSG("sigaction to obtain old action"); + return -1; + } + if ((oact.sa_flags & SA_SIGINFO) || (oact.sa_handler != SIG_IGN && oact.sa_handler != SIG_DFL)) { + ret = sigaction(sig, &act, NULL); /* async-signal-safe */ + if (ret == -1) { + ERRMSG("sigaction to set default action"); + return -1; + } + } + } + + ret = sigprocmask(SIG_SETMASK, oldset, NULL); /* async-signal-safe */ + if (ret != 0) { + ERRMSG("sigprocmask"); + return -1; + } + return 0; +} + static rb_pid_t retry_fork_async_signal_safe(int *status, int *ep, int (*chfunc)(void*, char *, size_t), void *charg, @@ -3391,9 +3462,11 @@ retry_fork_async_signal_safe(int *status, int *ep, { rb_pid_t pid; volatile int try_gc = 1; + sigset_t oldsigmask; while (1) { prefork(); + disable_child_handler_before_fork(&oldsigmask); #ifdef HAVE_WORKING_VFORK if (!has_privilege()) pid = vfork(); @@ -3405,8 +3478,11 @@ retry_fork_async_signal_safe(int *status, int *ep, if (pid == 0) {/* fork succeed, child process */ int ret; close(ep[0]); - ret = chfunc(charg, errmsg, errmsg_buflen); - if (!ret) _exit(EXIT_SUCCESS); + ret = disable_child_handler_fork_child(&oldsigmask, errmsg, errmsg_buflen); /* async-signal-safe */ + if (ret == 0) { + ret = chfunc(charg, errmsg, errmsg_buflen); + if (!ret) _exit(EXIT_SUCCESS); + } send_child_error(ep[1], errmsg, errmsg_buflen); #if EXIT_SUCCESS == 127 _exit(EXIT_FAILURE); @@ -3414,6 +3490,7 @@ retry_fork_async_signal_safe(int *status, int *ep, _exit(127); #endif } + preserving_errno(disable_child_handler_fork_parent(&oldsigmask)); if (0 < pid) /* fork succeed, parent process */ return pid; /* fork failed */ -- cgit v1.2.3