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-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 91D081FA1A for ; Tue, 15 Dec 2020 11:47:23 +0000 (UTC) From: Eric Wong To: meta@public-inbox.org Subject: [RFC 7/7] lei: use spawn (vfork + execve) for lazy start Date: Tue, 15 Dec 2020 11:47:22 +0000 Message-Id: <20201215114722.27400-8-e@80x24.org> In-Reply-To: <20201215114722.27400-1-e@80x24.org> References: <20201215114722.27400-1-e@80x24.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit List-Id: This allows us to rely on FD_CLOEXEC being set on pipes from prove(1), so forgetting `daemon-stop' won't cause tests to hang. Unfortunately, daemon tests will be slower with this. --- lib/PublicInbox/LeiDaemon.pm | 12 +++++------- script/lei | 14 ++++++++++---- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/lib/PublicInbox/LeiDaemon.pm b/lib/PublicInbox/LeiDaemon.pm index 20ff0758..2f614ba4 100644 --- a/lib/PublicInbox/LeiDaemon.pm +++ b/lib/PublicInbox/LeiDaemon.pm @@ -335,29 +335,27 @@ sub accept_dispatch { # Listener {post_accept} callback sub noop {} # lei(1) calls this when it can't connect -sub lazy_start ($$) { +sub lazy_start { my ($path, $err) = @_; if ($err == ECONNREFUSED) { unlink($path) or die "unlink($path): $!"; } elsif ($err != ENOENT) { die "connect($path): $!"; } + require IO::FDPass; my $umask = umask(077) // die("umask(077): $!"); my $l = IO::Socket::UNIX->new(Local => $path, Listen => 1024, Type => SOCK_STREAM) or $err = $!; umask($umask) or die("umask(restore): $!"); - $l or return $err; + $l or return die "bind($path): $err"; my @st = stat($path) or die "stat($path): $!"; my $dev_ino_expect = pack('dd', $st[0], $st[1]); # dev+ino pipe(my ($eof_r, $eof_w)) or die "pipe: $!"; my $oldset = PublicInbox::Sigfd::block_signals(); my $pid = fork // die "fork: $!"; - if ($pid) { - PublicInbox::Sigfd::sig_setmask($oldset); - return; # client will connect to $path - } + return if $pid; openlog($path, 'pid', 'user'); local $SIG{__DIE__} = sub { syslog('crit', "@_"); @@ -371,7 +369,7 @@ sub lazy_start ($$) { open STDERR, '>&STDIN' or die "redirect stderr failed: $!\n"; setsid(); $pid = fork // die "fork: $!"; - exit if $pid; + return if $pid; $0 = "lei-daemon $path"; require PublicInbox::Listener; require PublicInbox::EOFpipe; diff --git a/script/lei b/script/lei index 1b5af3a1..637c1951 100755 --- a/script/lei +++ b/script/lei @@ -21,13 +21,19 @@ if (eval { require IO::FDPass; 1 }) { # use daemon to reduce load time }; my $sock = IO::Socket::UNIX->new(Peer => $path, Type => SOCK_STREAM); unless ($sock) { # start the daemon if not started - my $err = $!; - require PublicInbox::LeiDaemon; - $err = PublicInbox::LeiDaemon::lazy_start($path, $err); + my $err = $! + 0; + my $env = { PERL5LIB => join(':', @INC) }; + my $cmd = [ $^X, qw[-MPublicInbox::LeiDaemon + -E PublicInbox::LeiDaemon::lazy_start(@ARGV)], + $path, $err ]; + require PublicInbox::Spawn; + waitpid(PublicInbox::Spawn::spawn($cmd, $env), 0); + warn "lei-daemon exited with \$?=$?\n" if $?; + # try connecting again anyways, unlink+bind may be racy $sock = IO::Socket::UNIX->new(Peer => $path, Type => SOCK_STREAM) // die - "connect($path): $! (bind($path): $err)"; + "connect($path): $! (after attempted daemon start)"; } my $pwd = $ENV{PWD}; my $cwd = cwd();