]> Sergey Matveev's repositories - public-inbox.git/commitdiff
spawn: try to keep signals blocked in spawned child
authorEric Wong <e@80x24.org>
Sat, 18 Jun 2016 10:53:32 +0000 (10:53 +0000)
committerEric Wong <e@80x24.org>
Sat, 18 Jun 2016 21:48:25 +0000 (21:48 +0000)
While we only want to stop our daemons and gracefully destroy
subprocesses, it is common for 'Ctrl-C' from a terminal to kill
the entire pgroup.

Killing an entire pgroup nukes subprocesses like git-upload-pack
breaks graceful shutdown on long clones.  Make a best effort to
ensure git-upload-pack processes are not broken when somebody
signals an entire process group.

Followup-to: commit 37bf2db81bbbe114d7fc5a00e30d3d5a6fa74de5
("doc: systemd examples should only kill one process")

lib/PublicInbox/Spawn.pm
lib/PublicInbox/SpawnPP.pm
t/spawn.t

index 66dce3353e3bd872fad51838a53200bf94f50632..83730302a00ba126d435f63f359511a08e89b89a 100644 (file)
@@ -104,9 +104,11 @@ int public_inbox_fork_exec(int in, int out, int err,
                REDIR(out, 1);
                REDIR(err, 2);
                for (sig = 1; sig < NSIG; sig++)
-                       signal(sig, SIG_DFL); /* ignore errorrs on signals */
-               ret = sigprocmask(SIG_SETMASK, &old, NULL);
-               if (ret != 0) xerr("sigprocmask failed in vfork child");
+                       signal(sig, SIG_DFL); /* ignore errors on signals */
+               /*
+                * don't bother unblocking, we don't want signals
+                * to the group taking out a subprocess
+                */
                execve(filename, argv, envp);
                xerr("execve failed");
        }
index fe95d1269c210efb35720fd4d24584ac3eac101c..36223e8132eefa30c380bf1b07fef42bbf40628b 100644 (file)
@@ -3,11 +3,15 @@
 package PublicInbox::SpawnPP;
 use strict;
 use warnings;
-use POSIX qw(dup2);
+use POSIX qw(dup2 :signal_h);
 
 # Pure Perl implementation for folks that do not use Inline::C
 sub public_inbox_fork_exec ($$$$$$) {
        my ($in, $out, $err, $f, $cmd, $env) = @_;
+       my $old = POSIX::SigSet->new();
+       my $set = POSIX::SigSet->new();
+       $set->fillset or die "fillset failed: $!";
+       sigprocmask(SIG_SETMASK, $set, $old) or die "can't block signals: $!";
        my $pid = fork;
        if ($pid == 0) {
                if ($in != 0) {
@@ -29,6 +33,7 @@ sub public_inbox_fork_exec ($$$$$$) {
                        die "exec $cmd->[0] failed: $!\n";
                }
        }
+       sigprocmask(SIG_SETMASK, $old) or die "can't unblock signals: $!";
        $pid;
 }
 
index 9e58f675fe2a8fd140e7dd96982d1e639cbd674b..0f756462d02999831eff5307a87a8312acc419ca 100644 (file)
--- a/t/spawn.t
+++ b/t/spawn.t
@@ -87,7 +87,7 @@ use PublicInbox::Spawn qw(which spawn popen_rd);
        is(kill(0, $pid), 1, 'child process is running');
        ok(!defined(sysread($fh, my $buf, 1)) && $!{EAGAIN},
           'sysread returned quickly with EAGAIN');
-       is(kill(15, $pid), 1, 'child process killed early');
+       is(kill(9, $pid), 1, 'child process killed early');
        is(waitpid($pid, 0), $pid, 'child process reapable');
        isnt($?, 0, '$? set properly: '.$?);
 }