ruby-changes:35330
From: akr <ko1@a...>
Date: Fri, 5 Sep 2014 21:46:26 +0900 (JST)
Subject: [ruby-changes:35330] akr:r47412 (trunk): * process.c (disable_child_handler_before_fork): New function.
akr 2014-09-05 21:46:09 +0900 (Fri, 05 Sep 2014) New Revision: 47412 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=47412 Log: * 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. Modified files: trunk/ChangeLog trunk/process.c Index: ChangeLog =================================================================== --- ChangeLog (revision 47411) +++ ChangeLog (revision 47412) @@ -1,3 +1,11 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Fri Sep 5 21:45:33 2014 Tanaka Akira <akr@f...> + + * 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@f...> * process.c (handle_fork_error): Make try_gc_p argument volatile to Index: process.c =================================================================== --- process.c (revision 47411) +++ process.c (revision 47412) @@ -3384,6 +3384,77 @@ has_privilege(void) https://github.com/ruby/ruby/blob/trunk/process.c#L3384 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 https://github.com/ruby/ruby/blob/trunk/process.c#L3462 { 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 https://github.com/ruby/ruby/blob/trunk/process.c#L3478 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 https://github.com/ruby/ruby/blob/trunk/process.c#L3490 _exit(127); #endif } + preserving_errno(disable_child_handler_fork_parent(&oldsigmask)); if (0 < pid) /* fork succeed, parent process */ return pid; /* fork failed */ -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/