Subject: bug#41948: Shepherd deadlocks

From: Ludovic Courtès <[email-masked]>
Date: Sat, 08 May 2021 00:07:20 +0200

Ludovic Courtès <[email-masked]> skribis:

> While working on a fix for this issue (finalizer pipe shared between
> parent and child process), I found the ‘sleep_pipe’ of the main thread
> is also shared between the parent and its child.

Here’s a patch that fixes the problem as exposed by the reproducer.

Thoughts?

(We’d need these pipes to be “O_CLOFORK” rather than O_CLOEXEC.)

Ludo’.

diff --git a/libguile/posix.c b/libguile/posix.c
index eaf12de32..e0c157c20 100644
--- a/libguile/posix.c
+++ b/libguile/posix.c
@@ -1217,6 +1217,29 @@ SCM_DEFINE (scm_execle, "execle", 2, 0, 1,
 #undef FUNC_NAME
 
 #ifdef HAVE_FORK
+static void *
+do_fork (void *ret)
+{
+  pid_t pid = fork ();
+
+  if (pid == 0)
+    {
+      /* The child process must not share its sleep pipe with the
+         parent.  */
+      int err;
+      scm_thread *t = SCM_I_CURRENT_THREAD;
+
+      close (t->sleep_pipe[0]);
+      close (t->sleep_pipe[1]);
+      err = pipe2 (t->sleep_pipe, O_CLOEXEC);
+      if (err != 0)
+        abort ();
+    }
+
+  * (pid_t *) ret = pid;
+  return NULL;
+}
+
 SCM_DEFINE (scm_fork, "primitive-fork", 0, 0, 0,
             (),
 	    "Creates a new \"child\" process by duplicating the current \"parent\" process.\n"
@@ -1244,7 +1267,9 @@ SCM_DEFINE (scm_fork, "primitive-fork", 0, 0, 0,
         "         further behavior unspecified.  See \"Processes\" in the\n"
         "         manual, for more information.\n"),
        scm_current_warning_port ());
-  pid = fork ();
+
+  scm_without_guile (do_fork, &pid);
+
   if (pid == -1)
     SCM_SYSERROR;
   return scm_from_int (pid);