From b04e5cf1bc8969cca74ef764f2de960b1ea821a4 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Tue, 21 Jun 2016 02:39:27 +0000 Subject: spawn: improve error checking for fork failures fork failures are unfortunately common when Xapian has gigabytes and gigabytes mmapped. --- lib/PublicInbox/Config.pm | 2 +- lib/PublicInbox/Git.pm | 5 ++++- lib/PublicInbox/Qspawn.pm | 2 +- lib/PublicInbox/Spawn.pm | 8 ++++++-- lib/PublicInbox/SpawnPP.pm | 6 ++++++ 5 files changed, 18 insertions(+), 5 deletions(-) (limited to 'lib/PublicInbox') diff --git a/lib/PublicInbox/Config.pm b/lib/PublicInbox/Config.pm index ea84da35..ddb4f6b1 100644 --- a/lib/PublicInbox/Config.pm +++ b/lib/PublicInbox/Config.pm @@ -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>) { diff --git a/lib/PublicInbox/Git.pm b/lib/PublicInbox/Git.pm index bc0e5064..f47bc439 100644 --- a/lib/PublicInbox/Git.pm +++ b/lib/PublicInbox/Git.pm @@ -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 $/; diff --git a/lib/PublicInbox/Qspawn.pm b/lib/PublicInbox/Qspawn.pm index 9e4c8e08..9299096a 100644 --- a/lib/PublicInbox/Qspawn.pm +++ b/lib/PublicInbox/Qspawn.pm @@ -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} = $!; diff --git a/lib/PublicInbox/Spawn.pm b/lib/PublicInbox/Spawn.pm index 83730302..41b08a33 100644 --- a/lib/PublicInbox/Spawn.pm +++ b/lib/PublicInbox/Spawn.pm @@ -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; diff --git a/lib/PublicInbox/SpawnPP.pm b/lib/PublicInbox/SpawnPP.pm index 36223e81..179aba5e 100644 --- a/lib/PublicInbox/SpawnPP.pm +++ b/lib/PublicInbox/SpawnPP.pm @@ -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; } -- cgit v1.2.3-24-ge0c7