]> Sergey Matveev's repositories - public-inbox.git/blobdiff - lib/PublicInbox/Spawn.pm
wwwstream: reduce blob fetch paths for ->getline
[public-inbox.git] / lib / PublicInbox / Spawn.pm
index 1c74a5964aa59235d51eaa6af7bbb9b37fecb4eb..db679b770cfd81d985c4416db9b7186d718587a4 100644 (file)
@@ -1,8 +1,9 @@
-# Copyright (C) 2016-2019 all contributors <meta@public-inbox.org>
+# Copyright (C) 2016-2020 all contributors <meta@public-inbox.org>
 # License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
 #
 # This allows vfork to be used for spawning subprocesses if
-# PERL_INLINE_DIRECTORY is explicitly defined in the environment.
+# ~/.cache/public-inbox/inline-c is writable or if PERL_INLINE_DIRECTORY
+# is explicitly defined in the environment (and writable).
 # Under Linux, vfork can make a big difference in spawning performance
 # as process size increases (fork still needs to mark pages for CoW use).
 # Currently, we only use this for code intended for long running
 
 package PublicInbox::Spawn;
 use strict;
-use warnings;
-use base qw(Exporter);
+use parent qw(Exporter);
 use Symbol qw(gensym);
 use PublicInbox::ProcessPipe;
 our @EXPORT_OK = qw/which spawn popen_rd/;
-sub RLIMITS () { qw(RLIMIT_CPU RLIMIT_CORE RLIMIT_DATA) }
+our @RLIMITS = qw(RLIMIT_CPU RLIMIT_CORE RLIMIT_DATA);
 
 my $vfork_spawn = <<'VFORK_SPAWN';
 #include <sys/types.h>
-#include <sys/uio.h>
 #include <sys/time.h>
 #include <sys/resource.h>
 #include <unistd.h>
@@ -77,7 +76,7 @@ int pi_fork_exec(SV *redirref, SV *file, SV *cmdref, SV *envref, SV *rlimref,
        const char *filename = SvPV_nolen(file);
        pid_t pid;
        char **argv, **envp;
-       sigset_t set, old;
+       sigset_t set, old, cset;
        int ret, perrnum, cerrnum = 0;
 
        AV2C_COPY(argv, cmd);
@@ -87,6 +86,10 @@ int pi_fork_exec(SV *redirref, SV *file, SV *cmdref, SV *envref, SV *rlimref,
        assert(ret == 0 && "BUG calling sigfillset");
        ret = sigprocmask(SIG_SETMASK, &set, &old);
        assert(ret == 0 && "BUG calling sigprocmask to block");
+       ret = sigemptyset(&cset);
+       assert(ret == 0 && "BUG calling sigemptyset");
+       ret = sigaddset(&cset, SIGCHLD);
+       assert(ret == 0 && "BUG calling sigaddset for SIGCHLD");
        pid = vfork();
        if (pid == 0) {
                int sig;
@@ -119,9 +122,10 @@ int pi_fork_exec(SV *redirref, SV *file, SV *cmdref, SV *envref, SV *rlimref,
                }
 
                /*
-                * don't bother unblocking, we don't want signals
-                * to the group taking out a subprocess
+                * don't bother unblocking other signals for now, just SIGCHLD.
+                * we don't want signals to the group taking out a subprocess
                 */
+               (void)sigprocmask(SIG_UNBLOCK, &cset, NULL);
                execve(filename, argv, envp);
                exit_err(&cerrnum);
        }
@@ -140,8 +144,12 @@ int pi_fork_exec(SV *redirref, SV *file, SV *cmdref, SV *envref, SV *rlimref,
 }
 VFORK_SPAWN
 
-my $inline_dir = $ENV{PERL_INLINE_DIRECTORY};
-$vfork_spawn = undef unless defined $inline_dir && -d $inline_dir && -w _;
+my $inline_dir = $ENV{PERL_INLINE_DIRECTORY} //= (
+               $ENV{XDG_CACHE_HOME} //
+               ( ($ENV{HOME} // '/nonexistent').'/.cache' )
+       ).'/public-inbox/inline-c';
+
+$vfork_spawn = undef unless -d $inline_dir && -w _;
 if (defined $vfork_spawn) {
        # Inline 0.64 or later has locking in multi-process env,
        # but we support 0.5 on Debian wheezy
@@ -150,7 +158,7 @@ if (defined $vfork_spawn) {
                my $f = "$inline_dir/.public-inbox.lock";
                open my $fh, '>', $f or die "failed to open $f: $!\n";
                flock($fh, LOCK_EX) or die "LOCK_EX failed on $f: $!\n";
-               eval 'use Inline C => $vfork_spawn'; #, BUILD_NOISY => 1';
+               eval 'use Inline C => $vfork_spawn';
                my $err = $@;
                flock($fh, LOCK_UN) or die "LOCK_UN failed on $f: $!\n";
                die $err if $err;
@@ -199,7 +207,7 @@ sub spawn ($;$$) {
        }
        my $rlim = [];
 
-       foreach my $l (RLIMITS()) {
+       foreach my $l (@RLIMITS) {
                defined(my $v = $opts->{$l}) or next;
                my $r = eval "require BSD::Resource; BSD::Resource::$l();";
                unless (defined $r) {
@@ -210,7 +218,8 @@ sub spawn ($;$$) {
        }
        my $cd = $opts->{'-C'} // ''; # undef => NULL mapping doesn't work?
        my $pid = pi_fork_exec($redir, $f, $cmd, \@env, $rlim, $cd);
-       $pid < 0 ? undef : $pid;
+       die "fork_exec failed: $!\n" unless $pid > 0;
+       $pid;
 }
 
 sub popen_rd {
@@ -219,7 +228,6 @@ sub popen_rd {
        $opts ||= {};
        $opts->{1} = fileno($w);
        my $pid = spawn($cmd, $env, $opts);
-       return unless defined $pid;
        return ($r, $pid) if wantarray;
        my $ret = gensym;
        tie *$ret, 'PublicInbox::ProcessPipe', $pid, $r;