about summary refs log tree commit homepage
path: root/script
diff options
context:
space:
mode:
authorEric Wong <e@yhbt.net>2020-06-27 10:03:37 +0000
committerEric Wong <e@yhbt.net>2020-06-28 22:27:14 +0000
commit58c0333adbdd9f5f82309cb6eef3c379f0ff064e (patch)
tree5e0d2304c4003fcd9c858db4b955abab7e6e3a8f /script
parentb2b1006759730507731fcd3fc3e0de68239e3b92 (diff)
downloadpublic-inbox-58c0333adbdd9f5f82309cb6eef3c379f0ff064e.tar.gz
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.
Diffstat (limited to 'script')
-rwxr-xr-xscript/public-inbox-watch24
1 files changed, 18 insertions, 6 deletions
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);
 }