about summary refs log tree commit
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2019-11-24 00:22:30 +0000
committerEric Wong <e@80x24.org>2019-11-24 21:35:19 +0000
commit8576a48b2344905229737fde45498c80a1171ca5 (patch)
tree0ff343124cd1498415babfd8b74efc827c56b6c7
parent34a51e5736d7d1b7d2da7f7640eb2b87eec121ff (diff)
downloadpublic-inbox-8576a48b2344905229737fde45498c80a1171ca5.tar.gz
While the master process has a self-pipe to avoid missing
signals, worker processes lack that aside from a pipe to
detect master death.

That pipe doesn't exist when there's no master process,
so it's possible DS::close never finishes because it
never woke up from epoll_wait.  So create a pipe on
the worker_quit signal and force it into epoll/kevent
so it wakes up right away.
-rw-r--r--lib/PublicInbox/Daemon.pm21
1 files changed, 17 insertions, 4 deletions
diff --git a/lib/PublicInbox/Daemon.pm b/lib/PublicInbox/Daemon.pm
index 90f11137..0e3b95d2 100644
--- a/lib/PublicInbox/Daemon.pm
+++ b/lib/PublicInbox/Daemon.pm
@@ -252,6 +252,11 @@ sub daemonize () {
         }
 }
 
+sub shrink_pipes {
+        if ($^O eq 'linux') { # 1031: F_SETPIPE_SZ, 4096: page size
+                fcntl($_, 1031, 4096) for @_;
+        }
+}
 
 sub worker_quit {
         # killing again terminates immediately:
@@ -260,6 +265,17 @@ sub worker_quit {
         $_->close foreach @listeners; # call PublicInbox::DS::close
         @listeners = ();
 
+        # create a lazy self-pipe which kicks us out of the EventLoop
+        # so DS::PostEventLoop can fire
+        if (pipe(my ($r, $w))) {
+                shrink_pipes($w);
+
+                # shrink_pipes == noop
+                PublicInbox::ParentPipe->new($r, *shrink_pipes);
+                close $w; # wake up from the event loop
+        } else {
+                warn "E: pipe failed ($!), quit unreliable\n";
+        }
         my $proc_name;
         my $warn = 0;
         # drop idle connections and try to quit gracefully
@@ -468,10 +484,7 @@ sub unlink_pid_file_safe_ish ($$) {
 sub master_loop {
         pipe(my ($p0, $p1)) or die "failed to create parent-pipe: $!";
         pipe(my ($r, $w)) or die "failed to create self-pipe: $!";
-
-        if ($^O eq 'linux') { # 1031: F_SETPIPE_SZ = 1031
-                fcntl($_, 1031, 4096) for ($w, $p1);
-        }
+        shrink_pipes($w, $p1);
 
         IO::Handle::blocking($w, 0);
         my $set_workers = $worker_processes;