diff options
author | akr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2014-09-05 12:46:09 +0000 |
---|---|---|
committer | akr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2014-09-05 12:46:09 +0000 |
commit | 0610a859d979db77aa6b1e3591d13c0d8a8a63c0 (patch) | |
tree | b295dd0d65b25028c26b3ff4d8f18b9e6300de46 /process.c | |
parent | 01689aa9b16a2d78b21c5d037beeda4eb201d1f6 (diff) |
* 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
Diffstat (limited to 'process.c')
-rw-r--r-- | process.c | 81 |
1 files changed, 79 insertions, 2 deletions
@@ -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 */ |