summaryrefslogtreecommitdiff
path: root/libguile/posix.c
diff options
context:
space:
mode:
authorLudovic Courtès <ludo@gnu.org>2021-05-08 21:39:15 +0200
committerLudovic Courtès <ludo@gnu.org>2021-05-08 21:39:15 +0200
commit381291f5ff4480afbb197bf5e5a2272cfe54a386 (patch)
tree31ba38ab2f583db9db457a54f801b638d43d7400 /libguile/posix.c
parent5a281e35f4a5ae78fbcf10591d9358bec8f0bee0 (diff)
downloadguile-381291f5ff4480afbb197bf5e5a2272cfe54a386.tar.gz
'primitive-fork' closes and recreates the current thread's 'sleep_pipe'.
Partly fixes <https://bugs.gnu.org/41948>. Previously, the child process could end up using the same 'sleep_pipe' as its parent, leading to a race condition handling signals. * libguile/posix.c (do_fork): New function. (scm_fork): Call 'do_fork' via 'scm_without_guile'. * test-suite/standalone/test-signal-fork: New test. * test-suite/standalone/Makefile.am (check_SCRIPTS, TESTS): Add it.
Diffstat (limited to 'libguile/posix.c')
-rw-r--r--libguile/posix.c29
1 files changed, 28 insertions, 1 deletions
diff --git a/libguile/posix.c b/libguile/posix.c
index eaf12de32..31c4ab192 100644
--- a/libguile/posix.c
+++ b/libguile/posix.c
@@ -1217,6 +1217,31 @@ SCM_DEFINE (scm_execle, "execle", 2, 0, 1,
#undef FUNC_NAME
#ifdef HAVE_FORK
+
+/* Create a process and perform post-fork cleanups in the child. */
+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. Close it and create a new one. */
+ 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 +1269,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);