[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 ();