]> Sergey Matveev's repositories - public-inbox.git/commitdiff
spawn: improve error checking for fork failures
authorEric Wong <e@80x24.org>
Tue, 21 Jun 2016 02:39:27 +0000 (02:39 +0000)
committerEric Wong <e@80x24.org>
Tue, 21 Jun 2016 02:40:44 +0000 (02:40 +0000)
fork failures are unfortunately common when Xapian has
gigabytes and gigabytes mmapped.

lib/PublicInbox/Config.pm
lib/PublicInbox/Git.pm
lib/PublicInbox/Qspawn.pm
lib/PublicInbox/Spawn.pm
lib/PublicInbox/SpawnPP.pm
script/public-inbox-mda

index ea84da353c81827bcd018aa3a880d17959a52893..ddb4f6b1e95fe2af6a326c45d5025c64549b2918 100644 (file)
@@ -94,7 +94,7 @@ sub git_config_dump {
        my ($in, $out);
        my @cmd = (qw/git config/, "--file=$file", '-l');
        my $cmd = join(' ', @cmd);
-       my $fh = popen_rd(\@cmd);
+       my $fh = popen_rd(\@cmd) or die "popen_rd failed for $file: $!\n";
        my %rv;
        local $/ = "\n";
        foreach my $line (<$fh>) {
index bc0e5064d7ca5da0e69febb7076d3639baa2c79b..f47bc439080749c25100aca9cb1bb0f32b2d7c13 100644 (file)
@@ -28,7 +28,9 @@ sub _bidi_pipe {
 
        my @cmd = ('git', "--git-dir=$self->{git_dir}", qw(cat-file), $batch);
        my $redir = { 0 => fileno($out_r), 1 => fileno($in_w) };
-       $self->{$pid} = spawn(\@cmd, undef, $redir);
+       my $p = spawn(\@cmd, undef, $redir);
+       defined $p or fail($self, "spawn failed: $!");
+       $self->{$pid} = $p;
        $out_w->autoflush(1);
        $self->{$out} = $out_w;
        $self->{$in} = $in_r;
@@ -122,6 +124,7 @@ sub popen {
 sub qx {
        my ($self, @cmd) = @_;
        my $fh = $self->popen(@cmd);
+       defined $fh or return;
        local $/ = "\n";
        return <$fh> if wantarray;
        local $/;
index 9e4c8e081903ff183aec7a2a8ad4a2cd35289d2b..9299096a40d9d36b07e488b626ed0e1ecf3e1fed 100644 (file)
@@ -17,7 +17,7 @@ sub _do_spawn {
        my ($self, $cb) = @_;
        my $err;
        ($self->{rpipe}, $self->{pid}) = popen_rd(@{$self->{args}});
-       if ($self->{pid}) {
+       if (defined $self->{pid}) {
                $running++;
        } else {
                $self->{err} = $!;
index 83730302a00ba126d435f63f359511a08e89b89a..41b08a33e9b2aa512d5eff91109c791569f5b849 100644 (file)
@@ -84,7 +84,7 @@ int public_inbox_fork_exec(int in, int out, int err,
        char **argv, **envp;
        I32 max;
        sigset_t set, old;
-       int ret;
+       int ret, errnum;
 
        argv = AV_ALLOCA(cmd, max);
        av2c_copy(argv, cmd, max);
@@ -112,8 +112,10 @@ int public_inbox_fork_exec(int in, int out, int err,
                execve(filename, argv, envp);
                xerr("execve failed");
        }
+       errnum = errno;
        ret = sigprocmask(SIG_SETMASK, &old, NULL);
        assert(ret == 0 && "BUG calling sigprocmask to restore");
+       errno = errnum;
 
        return (int)pid;
 }
@@ -180,7 +182,8 @@ sub spawn ($;$$) {
        my $in = $opts->{0} || 0;
        my $out = $opts->{1} || 1;
        my $err = $opts->{2} || 2;
-       public_inbox_fork_exec($in, $out, $err, $f, $cmd, \@env);
+       my $pid = public_inbox_fork_exec($in, $out, $err, $f, $cmd, \@env);
+       $pid < 0 ? undef : $pid;
 }
 
 sub popen_rd {
@@ -191,6 +194,7 @@ sub popen_rd {
        IO::Handle::blocking($r, $blocking) if defined $blocking;
        $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;
index 36223e8132eefa30c380bf1b07fef42bbf40628b..179aba5e737ccb524947dfd424d208c2618abed8 100644 (file)
@@ -12,7 +12,12 @@ sub public_inbox_fork_exec ($$$$$$) {
        my $set = POSIX::SigSet->new();
        $set->fillset or die "fillset failed: $!";
        sigprocmask(SIG_SETMASK, $set, $old) or die "can't block signals: $!";
+       my $syserr;
        my $pid = fork;
+       unless (defined $pid) { # compat with Inline::C version
+               $syserr = $!;
+               $pid = -1;
+       }
        if ($pid == 0) {
                if ($in != 0) {
                        dup2($in, 0) or die "dup2 failed for stdin: $!";
@@ -34,6 +39,7 @@ sub public_inbox_fork_exec ($$$$$$) {
                }
        }
        sigprocmask(SIG_SETMASK, $old) or die "can't unblock signals: $!";
+       $! = $syserr;
        $pid;
 }
 
index 145aa7106b958a20083eeba9b74678497b06bd71..013642d0bb86ebd6c587a3fda352b6f913a1e772 100755 (executable)
@@ -97,6 +97,7 @@ sub do_spamc {
        my ($in, $out) = @_;
        my $rdr = { 0 => fileno($in) };
        my ($fh, $pid) = popen_rd([qw/spamc -E --headers/], undef, $rdr);
+       defined $pid or die "failed to popen_rd spamc: $!\n";
        my $r;
        do {
                $r = sysread($fh, $$out, 65536, length($$out));