зеркало из https://github.com/github/ruby.git
* 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
This commit is contained in:
Родитель
01689aa9b1
Коммит
0610a859d9
|
@ -1,3 +1,11 @@
|
|||
Fri Sep 5 21:45:33 2014 Tanaka Akira <akr@fsij.org>
|
||||
|
||||
* 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.
|
||||
|
||||
Fri Sep 5 21:02:54 2014 Tanaka Akira <akr@fsij.org>
|
||||
|
||||
* process.c (handle_fork_error): Make try_gc_p argument volatile to
|
||||
|
|
81
process.c
81
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 */
|
||||
|
|
Загрузка…
Ссылка в новой задаче