about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2021-01-21 19:46:18 +0000
committerEric Wong <e@80x24.org>2021-01-22 16:18:01 -0400
commit5c46247509080a4c0d6eb3db56ec62bfab29e76e (patch)
tree5a614c0eab4fbff04ea5b9833862b3e20da69dee
parente2cb80c33b015c407c19cddc327dcb5c50137a0c (diff)
downloadpublic-inbox-5c46247509080a4c0d6eb3db56ec62bfab29e76e.tar.gz
Worker exit causes DESTROY ordering to become unpredictable and
leads to Perl segfaulting.  Instead, rely on OnDestroy and
explicit triggering after wq_worker_loop to ensure we finish
all outstanding git requests before worker exit.
-rw-r--r--lib/PublicInbox/LeiToMail.pm18
1 files changed, 14 insertions, 4 deletions
diff --git a/lib/PublicInbox/LeiToMail.pm b/lib/PublicInbox/LeiToMail.pm
index 87cc9c47..cea68319 100644
--- a/lib/PublicInbox/LeiToMail.pm
+++ b/lib/PublicInbox/LeiToMail.pm
@@ -11,6 +11,7 @@ use PublicInbox::Lock;
 use PublicInbox::ProcessPipe;
 use PublicInbox::Spawn qw(which spawn popen_rd);
 use PublicInbox::LeiDedupe;
+use PublicInbox::OnDestroy;
 use Symbol qw(gensym);
 use IO::Handle; # ->autoflush
 use Fcntl qw(SEEK_SET SEEK_END O_CREAT O_EXCL O_WRONLY);
@@ -472,12 +473,21 @@ sub ipc_atfork_prepare {
         $self->SUPER::ipc_atfork_prepare; # PublicInbox::IPC
 }
 
-sub DESTROY {
+# We rely on OnDestroy to run this before ->DESTROY, since ->DESTROY
+# ordering is unstable at worker exit and may cause segfaults
+sub reap_gits {
         my ($self) = @_;
-        for my $pid_git (grep(/\A$$\0/, keys %$self)) {
-                $self->{$pid_git}->async_wait_all;
+        for my $git (delete @$self{grep(/\A$$\0/, keys %$self)}) {
+                $git->async_wait_all;
         }
-        $self->SUPER::DESTROY; # PublicInbox::IPC
+}
+
+sub ipc_atfork_child { # runs after IPC::wq_worker_loop
+        my ($self) = @_;
+        $self->SUPER::ipc_atfork_child;
+        # reap_gits needs to run before $self->DESTROY,
+        # IPC.pm will ensure that.
+        PublicInbox::OnDestroy->new($$, \&reap_gits, $self);
 }
 
 1;