From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: X-Spam-Status: No, score=-4.2 required=3.0 tests=ALL_TRUSTED,AWL,BAYES_00, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF shortcircuit=no autolearn=ham autolearn_force=no version=3.4.6 Received: from localhost (dcvr.yhbt.net [127.0.0.1]) by dcvr.yhbt.net (Postfix) with ESMTP id 8B0B41F568 for ; Mon, 4 Sep 2023 10:36:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=80x24.org; s=selector1; t=1693823768; bh=rrRS2kwRsfqNI256cg5NVAM+4r4OFmnkuhanqkZ25ug=; h=From:To:Subject:Date:In-Reply-To:References:From; b=k+wS3k+cQnWb8A6eMdbBYPeOC6efYj6pkO2D/r520MKVkDBBrqGTlQ/yUysd2Rs9T 8nKcshNM3EFTV56I0VkwCdbkdYHOAqHzquvZSN73KNu8t701cD7jIb3AWTYPyEz4xt 8eFucWzcyi1GyZP8ey6+YCQdxZRi4Vq7HumsIGoE= From: Eric Wong To: meta@public-inbox.org Subject: [PATCH 05/10] daemon: workaround pre-EVFILT_SIGNAL signals Date: Mon, 4 Sep 2023 10:36:02 +0000 Message-ID: <20230904103607.1940839-6-e@80x24.org> In-Reply-To: <20230904103607.1940839-1-e@80x24.org> References: <20230904103607.1940839-1-e@80x24.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit List-Id: FreeBSD and OpenBSD kqueue EVFILT_SIGNAL isn't able to handle blocked signals which were sent before the filter is created. This behavior differs from Linux signalfd, which can process blocked signals that were sent before the signalfd existed. --- lib/PublicInbox/DS.pm | 30 ++++++++++++++++++++++++++---- lib/PublicInbox/Sigfd.pm | 3 ++- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/lib/PublicInbox/DS.pm b/lib/PublicInbox/DS.pm index 97546016..5168a6ee 100644 --- a/lib/PublicInbox/DS.pm +++ b/lib/PublicInbox/DS.pm @@ -24,11 +24,11 @@ use strict; use v5.10.1; use parent qw(Exporter); use bytes qw(length substr); # FIXME(?): needed for PublicInbox::NNTP -use POSIX qw(WNOHANG sigprocmask SIG_SETMASK); +use POSIX qw(WNOHANG sigprocmask SIG_SETMASK SIG_UNBLOCK); use Fcntl qw(SEEK_SET :DEFAULT O_APPEND); use Time::HiRes qw(clock_gettime CLOCK_MONOTONIC); use Scalar::Util qw(blessed); -use PublicInbox::Syscall qw(:epoll); +use PublicInbox::Syscall qw(:epoll %SIGNUM); use PublicInbox::Tmpfile; use Errno qw(EAGAIN EINVAL ECHILD EINTR); use Carp qw(carp croak); @@ -259,19 +259,41 @@ sub PostEventLoop () { : 1 } +sub allowset ($) { + my ($sig) = @_; # { signame => whatever } + my $ret = POSIX::SigSet->new; + $ret->fillset or die "fillset: $!"; + for my $s (keys %$sig) { + my $num = $SIGNUM{$s} // POSIX->can("SIG$s")->(); + $ret->delset($num) or die "delset ($s => $num): $!"; + } + for (@UNBLOCKABLE) { $ret->delset($_) or die "delset($_): $!" } + $ret; +} + # Start processing IO events. In most daemon programs this never exits. See # C for how to exit the loop. sub event_loop (;$$) { my ($sig, $oldset) = @_; $Epoll //= _InitPoller(); require PublicInbox::Sigfd if $sig; - my $sigfd = PublicInbox::Sigfd->new($sig, 1) if $sig; + my $sigfd = $sig ? PublicInbox::Sigfd->new($sig, 1) : undef; + if ($sigfd && $sigfd->{is_kq}) { + my $tmp = allowset($sig); + local @SIG{keys %$sig} = values(%$sig); + sig_setmask($tmp, my $old = POSIX::SigSet->new); + # Unlike Linux signalfd, EVFILT_SIGNAL can't handle + # signals received before the filter is created, + # so we peek at signals here. + sig_setmask($old); + } local @SIG{keys %$sig} = values(%$sig) if $sig && !$sigfd; local $SIG{PIPE} = 'IGNORE'; if (!$sigfd && $sig) { # wake up every second to accept signals if we don't # have signalfd or IO::KQueue: - sig_setmask($oldset); + sig_setmask($oldset) if $oldset; + sigprocmask(SIG_UNBLOCK, allowset($sig)) or die "SIG_UNBLOCK: $!"; PublicInbox::DS->SetLoopTimeout(1000); } $_[0] = $sigfd = $sig = undef; # $_[0] == sig diff --git a/lib/PublicInbox/Sigfd.pm b/lib/PublicInbox/Sigfd.pm index 3c1d3811..5656baeb 100644 --- a/lib/PublicInbox/Sigfd.pm +++ b/lib/PublicInbox/Sigfd.pm @@ -31,8 +31,9 @@ sub new { $self->SUPER::new($io, EPOLLIN | EPOLLET); } else { # master main loop $self->{sock} = $io; - $self; } + $self->{is_kq} = 1 if tied(*$io); + $self; } # PublicInbox::Daemon in master main loop (blocking)