From 58c0333adbdd9f5f82309cb6eef3c379f0ff064e Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sat, 27 Jun 2020 10:03:37 +0000 Subject: watch: use signalfd for Maildir watching We can get rid of the janky wannabe self-using-a-directory-instead-of-pipe thing we needed to workaround Filesys::Notify::Simple being blocking. For existing Maildir users, this should be more robust and immune to missed wakeups for signalfd and kqueue-enabled systems; as well as being immune to BOFHs clearing $TMPDIR and preventing notifications from firing. The IMAP IDLE code still uses normal Perl signals, so it's still vulnerable to missed wakeups. That will be addressed in future commits. --- script/public-inbox-watch | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) (limited to 'script') diff --git a/script/public-inbox-watch b/script/public-inbox-watch index 2057066a..b6d545ad 100755 --- a/script/public-inbox-watch +++ b/script/public-inbox-watch @@ -5,6 +5,10 @@ use strict; use warnings; use PublicInbox::WatchMaildir; use PublicInbox::Config; +use PublicInbox::DS; +use PublicInbox::Sigfd; +use PublicInbox::Syscall qw(SFD_NONBLOCK); +my $oldset = PublicInbox::Sigfd::block_signals(); my ($config, $watch_md); my $reload = sub { $config = PublicInbox::Config->new; @@ -14,14 +18,22 @@ my $reload = sub { $reload->(); if ($watch_md) { my $scan = sub { $watch_md->trigger_scan('full') if $watch_md }; - $SIG{HUP} = $reload; - $SIG{USR1} = $scan; - $SIG{ALRM} = sub { $SIG{ALRM} = 'DEFAULT'; $scan->() }; - $SIG{QUIT} = $SIG{TERM} = $SIG{INT} = sub { + my $quit = sub { $watch_md->quit if $watch_md; $watch_md = undef; }; + my $sig = { HUP => $reload, USR1 => $scan }; + $sig->{QUIT} = $sig->{TERM} = $sig->{INT} = $quit; + # --no-scan is only intended for testing atm, undocumented. - alarm(1) unless (grep(/\A--no-scan\z/, @ARGV)); - $watch_md->watch while ($watch_md); + unless (grep(/\A--no-scan\z/, @ARGV)) { + PublicInbox::DS::requeue($scan); + } + my $sigfd = PublicInbox::Sigfd->new($sig, SFD_NONBLOCK); + local %SIG = (%SIG, %$sig) if !$sigfd; + if (!$sigfd) { + PublicInbox::Sigfd::set_sigmask($oldset); + PublicInbox::DS->SetLoopTimeout(1000); + } + $watch_md->watch($sig, $oldset) while ($watch_md); } -- cgit v1.2.3-24-ge0c7