unofficial mirror of bug-guile@gnu.org 
 help / color / mirror / Atom feed
* bug#43066: Hang when forking new process.
@ 2020-08-27  7:42 Mathieu Othacehe
  2021-05-11 10:43 ` Ludovic Courtès
  0 siblings, 1 reply; 2+ messages in thread
From: Mathieu Othacehe @ 2020-08-27  7:42 UTC (permalink / raw)
  To: 43066

[-- Attachment #1: Type: text/plain, Size: 797 bytes --]


Hello,

When forking, the finalization pipe file descriptors are
inherited. If the child process spawns a finalization thread, it will
use a copy of its parent finalization pipe file descriptors.

Hence, if the parent tries to stop its finalization thread, by forking
another process for instance, it may stop the child finalization thread
and hang forever waiting for its own finalization thread to stop.

Here's a small reproducer attached. On my machine, the program hangs
around iteration 100. Note that this has previously been discussed
here[1].

The attached patch should fix this by closing the finalization pipe file
descriptor copies in the child right after forking and opening a new
pipe by calling scm_init_finalizer_thread.

Thanks,

Mathieu

[1]: https://issues.guix.gnu.org/41948

[-- Attachment #2: t.scm --]
[-- Type: application/octet-stream, Size: 382 bytes --]

(use-modules (ice-9 match))

(define (start-process command)
  (match (primitive-fork)
    (0
     (execl "/bin/sh" "sh" "-c" command))
    (_ #t)))

(match (primitive-fork)
  (0
   (while #t
     (gc)
     (usleep 200000)))
  (pid
   (let loop ((count 0))
     (format #t "Forking ~a~%" count)
     (start-process "sleep 1")
     (usleep (random 200000))
     (loop (1+ count)))))

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 0001-Close-finalization-pipe-after-forking.patch --]
[-- Type: text/x-diff, Size: 2503 bytes --]

From 004c0c78c9c21c48b38d76b5d7b356b40c8e5a4a Mon Sep 17 00:00:00 2001
From: Mathieu Othacehe <othacehe@gnu.org>
Date: Thu, 27 Aug 2020 09:16:55 +0200
Subject: [PATCH] Close finalization pipe after forking.

When forking, the finalization pipe file descriptors are
inherited. If the child process spawns a finalization thread, it will
use a copy of its parent finalization pipe file descriptors.

Hence, if the parent tries to stop its finalization thread, by forking
another process for instance, it may stop the child finalization thread
and hang forever for its own finalization thread to stop.

Fix it by closing the finalization pipe file descriptor copies in the
child right after forking and opening a new pipe by calling
scm_init_finalizer_thread.

* libguile/finalizers.c (scm_i_finalizer_post_fork): New function.
* libguile/finalizers.c (scm_i_finalizer_post_fork): Declare it.
* libguile/posix.c (scm_fork): Call it in the child process, right after forking.
---
 libguile/finalizers.c | 13 +++++++++++++
 libguile/finalizers.h |  1 +
 libguile/posix.c      |  4 ++++
 3 files changed, 18 insertions(+)

diff --git a/libguile/finalizers.c b/libguile/finalizers.c
index 0ae165fd1..b1803b34b 100644
--- a/libguile/finalizers.c
+++ b/libguile/finalizers.c
@@ -305,6 +305,19 @@ scm_i_finalizer_pre_fork (void)
 #endif
 }
 
+void
+scm_i_finalizer_post_fork (void)
+{
+#if SCM_USE_PTHREAD_THREADS
+  if (automatic_finalization_p)
+    {
+      close (finalization_pipe[0]);
+      close (finalization_pipe[1]);
+      scm_init_finalizer_thread ();
+    }
+#endif
+}
+
 
 \f
 
diff --git a/libguile/finalizers.h b/libguile/finalizers.h
index 44bafb22e..866e4d1eb 100644
--- a/libguile/finalizers.h
+++ b/libguile/finalizers.h
@@ -36,6 +36,7 @@ SCM_INTERNAL void scm_i_add_resuscitator (void *obj, scm_t_finalizer_proc,
                                           void *data);
 
 SCM_INTERNAL void scm_i_finalizer_pre_fork (void);
+SCM_INTERNAL void scm_i_finalizer_post_fork  (void);
 
 /* CALLBACK will be called after each garbage collection.  It will be
    called from a finalizer, which may be from an async or from another
diff --git a/libguile/posix.c b/libguile/posix.c
index 47769003a..022bda6e3 100644
--- a/libguile/posix.c
+++ b/libguile/posix.c
@@ -1247,6 +1247,10 @@ SCM_DEFINE (scm_fork, "primitive-fork", 0, 0, 0,
   pid = fork ();
   if (pid == -1)
     SCM_SYSERROR;
+
+  if (!pid)
+    scm_i_finalizer_post_fork ();
+
   return scm_from_int (pid);
 }
 #undef FUNC_NAME
-- 
2.28.0


^ permalink raw reply	[flat|nested] 2+ messages in thread

* bug#43066: Hang when forking new process.
  2020-08-27  7:42 bug#43066: Hang when forking new process Mathieu Othacehe
@ 2021-05-11 10:43 ` Ludovic Courtès
  0 siblings, 0 replies; 2+ messages in thread
From: Ludovic Courtès @ 2021-05-11 10:43 UTC (permalink / raw)
  To: Mathieu Othacehe; +Cc: 43066-done

Hi Mathieu,

Mathieu Othacehe <othacehe@gnu.org> skribis:

>>From 004c0c78c9c21c48b38d76b5d7b356b40c8e5a4a Mon Sep 17 00:00:00 2001
> From: Mathieu Othacehe <othacehe@gnu.org>
> Date: Thu, 27 Aug 2020 09:16:55 +0200
> Subject: [PATCH] Close finalization pipe after forking.
>
> When forking, the finalization pipe file descriptors are
> inherited. If the child process spawns a finalization thread, it will
> use a copy of its parent finalization pipe file descriptors.
>
> Hence, if the parent tries to stop its finalization thread, by forking
> another process for instance, it may stop the child finalization thread
> and hang forever for its own finalization thread to stop.
>
> Fix it by closing the finalization pipe file descriptor copies in the
> child right after forking and opening a new pipe by calling
> scm_init_finalizer_thread.
>
> * libguile/finalizers.c (scm_i_finalizer_post_fork): New function.
> * libguile/finalizers.c (scm_i_finalizer_post_fork): Declare it.
> * libguile/posix.c (scm_fork): Call it in the child process, right after forking.

Apologies for overlooking this patch!

This was fixed differently in 5a281e35f4a5ae78fbcf10591d9358bec8f0bee0,
which is in 3.0.7.

Thanks,
Ludo’.





^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2021-05-11 10:43 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-08-27  7:42 bug#43066: Hang when forking new process Mathieu Othacehe
2021-05-11 10:43 ` Ludovic Courtès

unofficial mirror of bug-guile@gnu.org 

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://yhetil.org/guile-bugs/0 guile-bugs/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 guile-bugs guile-bugs/ https://yhetil.org/guile-bugs \
		bug-guile@gnu.org
	public-inbox-index guile-bugs

Example config snippet for mirrors.
Newsgroups are available over NNTP:
	nntp://news.yhetil.org/yhetil.lisp.guile.bugs
	nntp://news.gmane.io/gmane.lisp.guile.bugs


AGPL code for this site: git clone http://ou63pmih66umazou.onion/public-inbox.git