From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: X-Spam-Status: No, score=-4.0 required=3.0 tests=ALL_TRUSTED,AWL,BAYES_00 shortcircuit=no autolearn=ham autolearn_force=no version=3.4.2 Received: from localhost (dcvr.yhbt.net [127.0.0.1]) by dcvr.yhbt.net (Postfix) with ESMTP id AC4801F90E for ; Thu, 16 Apr 2020 01:48:39 +0000 (UTC) From: Eric Wong To: meta@public-inbox.org Subject: [PATCH 2/2] t/httpd-unix: reliability for non-signalfd/EVFILT_SIGNAL Date: Thu, 16 Apr 2020 01:48:38 +0000 Message-Id: <20200416014838.5939-3-e@yhbt.net> In-Reply-To: <20200416014838.5939-1-e@yhbt.net> References: <20200416014838.5939-1-e@yhbt.net> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit List-Id: Perl seems unable to detect a pending signal (`PL_sig_pending' flag) even in a sleep(1) loop which wakes up every second. The (SIGTTOU|SIGUSR2|SIGQUIT) signal itself in the `PL_psig_pend[sig]' array is not lost, so we can send SIGCHLD to the process to force the `PL_sig_pending' into being set, again. I tested this commit in a loop with the following patch on a Debian GNU/Linux system to disable signalfd use: diff --git a/lib/PublicInbox/Sigfd.pm b/lib/PublicInbox/Sigfd.pm index f500902e..597b40d1 100644 --- a/lib/PublicInbox/Sigfd.pm +++ b/lib/PublicInbox/Sigfd.pm @@ -12,6 +12,7 @@ use IO::Handle (); # are available. sub new { my ($class, $sig, $flags) = @_; + return; my $self = fields::new($class); my %signo = map {; my $cb = $sig->{$_}; --- t/httpd-unix.t | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/t/httpd-unix.t b/t/httpd-unix.t index 7ebc3464..3bfded0c 100644 --- a/t/httpd-unix.t +++ b/t/httpd-unix.t @@ -81,13 +81,27 @@ check_sock($unix); ok(-S $unix, 'unix socket still exists'); } +# Perl can delay signal dispatches due to races, so we repeatedly +# poke a process with an innocuous signal (SIGCHLD) when signalfd(2) +# (or EVFILT_SIGNAL) is missing +my $sig_poke; +if (my $sigfd = PublicInbox::Sigfd->new({}, 0)) { + $sig_poke = sub {}; # noop, we've got signalfd or EVFILT_SIGNAL +} else { + $sig_poke = sub { + my $pid = shift; + kill('CHLD', $pid); + }; +} + sub delay_until { my $cond = shift; - for (1..1000) { + my $end = time + 30; + do { return if $cond->(); select undef, undef, undef, 0.012; - } - Carp::croak('condition failed'); + } until (time > $end); + Carp::confess('condition failed'); } SKIP: { @@ -133,19 +147,23 @@ SKIP: { kill('USR2', $pid) or die "USR2 failed: $!"; delay_until(sub { + $sig_poke->($pid); $pid != (eval { $read_pid->($pid_file) } // $pid) }); my $new_pid = $read_pid->($pid_file); isnt($new_pid, $pid, 'new child started'); + ok($new_pid > 0, '$new_pid valid'); delay_until(sub { -s "$pid_file.oldbin" }); my $old_pid = $read_pid->("$pid_file.oldbin"); is($old_pid, $pid, '.oldbin pid file written'); + ok($old_pid > 0, '$old_pid valid'); check_sock($unix); # ensures $new_pid is ready to receive signals # first, back out of the upgrade kill('QUIT', $new_pid) or die "kill new PID failed: $!"; delay_until(sub { + $sig_poke->($new_pid); $pid == (eval { $read_pid->($pid_file) } // 0) }); is($read_pid->($pid_file), $pid, 'old PID file restored');