From: Eric Wong <e@80x24.org>
To: meta@public-inbox.org
Subject: [PATCH] spawn: improve error checking for fork failures
Date: Tue, 21 Jun 2016 02:39:27 +0000 [thread overview]
Message-ID: <20160621023927.776-1-e@80x24.org> (raw)
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 ++++++
script/public-inbox-mda | 1 +
6 files changed, 19 insertions(+), 5 deletions(-)
diff --git a/lib/PublicInbox/Config.pm b/lib/PublicInbox/Config.pm
index ea84da3..ddb4f6b 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 bc0e506..f47bc43 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 9e4c8e0..9299096 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 8373030..41b08a3 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 36223e8..179aba5 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;
}
diff --git a/script/public-inbox-mda b/script/public-inbox-mda
index 145aa71..013642d 100755
--- a/script/public-inbox-mda
+++ b/script/public-inbox-mda
@@ -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));
reply other threads:[~2016-06-21 2:39 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://public-inbox.org/README
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20160621023927.776-1-e@80x24.org \
--to=e@80x24.org \
--cc=meta@public-inbox.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://80x24.org/public-inbox.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).