emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

SIGCHLD in vfork child context


From: YAMAMOTO Mitsuharu
Subject: SIGCHLD in vfork child context
Date: Sat, 13 May 2017 14:41:59 +0900
User-agent: Wanderlust/2.14.0 (Africa) SEMI/1.14.6 (Maruoka) FLIM/1.14.8 (Shijō) APEL/10.6 Emacs/22.3 (sparc-sun-solaris2.8) MULE/5.0 (SAKAKI)

Recently Emacs on Darwin has changed to use vfork rather than fork for
performance reasons (Bug#26397).  The latest Mac port contains a
similar change, but I received a report telling that this causes
occasional hangs.

It seems that calling waitpid from the SIGCHLD handler results in
ECHILD in the vfork child context, and in this case, Emacs aborts and
then hangs in such a context for some reason on macOS.

src/sysdep.c:
   385    while (true)
   386      {
   387        /* Note: the MS-Windows emulation of waitpid calls maybe_quit
   388           internally.  */
   389        if (interruptible)
   390          maybe_quit ();
   391  
   392        pid = waitpid (child, status, options);
   393        if (0 <= pid)
   394          break;
   395  
   396        /* Check that CHILD is a child process that has not been reaped,
   397           and that STATUS and OPTIONS are valid.  Otherwise abort,
   398           as continuing after this internal error could cause Emacs to
   399           become confused and kill innocent-victim processes.  */
   400        if (errno != EINTR)
   401          emacs_abort ();
   402      }


I made a patch below to avoid calling the SIGCHLD handler on Darwin,
but I wonder if this can also be meaningful in other platforms.  WDYT?

                                     YAMAMOTO Mitsuharu
                                address@hidden

diff --git a/src/callproc.c b/src/callproc.c
index 333dbb8cb4..83597bd580 100644
--- a/src/callproc.c
+++ b/src/callproc.c
@@ -634,6 +634,11 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int 
filefd,
 
   if (pid == 0)
     {
+#ifdef DARWIN_OS
+      /* Call to waitpid from the SIGCHLD signal handler results in
+        ECHILD in the vfork child context.  */
+      signal (SIGCHLD, SIG_DFL);
+#endif
       unblock_child_signal (&oldset);
 
 #ifdef DARWIN_OS
@@ -681,6 +686,18 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int 
filefd,
        }
     }
 
+#ifdef DARWIN_OS
+  {
+    struct sigaction action;
+
+    /* Call the SIGCHLD handler in case we have received SIGCHLD in
+       the vfork child context.  The signal mask is restored by
+       unblock_child_signal below.  */
+    sigaction (SIGCHLD, 0, &action);
+    pthread_sigmask (SIG_BLOCK, &action.sa_mask, 0);
+    (*action.sa_handler) (SIGCHLD);
+  }
+#endif
   unblock_child_signal (&oldset);
   unblock_input ();
 
diff --git a/src/process.c b/src/process.c
index c47e1eac52..95867e27db 100644
--- a/src/process.c
+++ b/src/process.c
@@ -1940,6 +1940,11 @@ create_process (Lisp_Object process, char **new_argv, 
Lisp_Object current_dir)
       /* Emacs ignores SIGPIPE, but the child should not.  */
       signal (SIGPIPE, SIG_DFL);
 
+#ifdef DARWIN_OS
+      /* Call to waitpid from the SIGCHLD signal handler results in
+        ECHILD in the vfork child context.  */
+      signal (SIGCHLD, SIG_DFL);
+#endif
       /* Stop blocking SIGCHLD in the child.  */
       unblock_child_signal (&oldset);
 
@@ -1962,6 +1967,18 @@ create_process (Lisp_Object process, char **new_argv, 
Lisp_Object current_dir)
   if (pid >= 0)
     p->alive = 1;
 
+#ifdef DARWIN_OS
+  {
+    struct sigaction action;
+
+    /* Call the SIGCHLD handler in case we have received SIGCHLD in
+       the vfork child context.  The signal mask is restored by
+       unblock_child_signal below.  */
+    pthread_sigmask (SIG_BLOCK, &action.sa_mask, 0);
+    sigaction (SIGCHLD, 0, &action);
+    (*action.sa_handler) (SIGCHLD);
+  }
+#endif
   /* Stop blocking in the parent.  */
   unblock_child_signal (&oldset);
   unblock_input ();



reply via email to

[Prev in Thread] Current Thread [Next in Thread]