From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: X-Spam-Status: No, score=-4.0 required=3.0 tests=ALL_TRUSTED,BAYES_00 shortcircuit=no autolearn=ham autolearn_force=no version=3.4.2 Received: from localhost (dcvr.yhbt.net [127.0.0.1]) by dcvr.yhbt.net (Postfix) with ESMTP id 042D51F9FF for ; Sun, 24 Nov 2019 00:22:41 +0000 (UTC) From: Eric Wong To: meta@public-inbox.org Subject: [PATCH 10/17] daemon: avoid race when quitting workers Date: Sun, 24 Nov 2019 00:22:30 +0000 Message-Id: <20191124002237.15713-11-e@80x24.org> In-Reply-To: <20191124002237.15713-1-e@80x24.org> References: <20191124002237.15713-1-e@80x24.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit List-Id: 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. --- lib/PublicInbox/Daemon.pm | 21 +++++++++++++++++---- 1 file 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;