[前][次][番号順一覧][スレッド一覧]

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/

[前][次][番号順一覧][スレッド一覧]