-### The kqueue-based event loop. Gets installed as EventLoop if IO::KQueue works
-### okay.
-sub KQueueEventLoop {
- my $class = shift;
-
- while (1) {
- my $timeout = RunTimers();
- my @ret = eval { $KQueue->kevent($timeout) };
- if (my $err = $@) {
- # workaround https://rt.cpan.org/Ticket/Display.html?id=116615
- if ($err =~ /Interrupted system call/) {
- @ret = ();
- } else {
- die $err;
- }
- }
-
- foreach my $kev (@ret) {
- $DescriptorMap{$kev->[0]}->event_step;
- }
- return unless PostEventLoop();
- }
+# Start processing IO events. In most daemon programs this never exits. See
+# C<PostLoopCallback> 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;
+ 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);
+ PublicInbox::DS->SetLoopTimeout(1000);
+ }
+ $_[0] = $sigfd = $sig = undef; # $_[0] == sig
+ local $in_loop = 1;
+ my @events;
+ do {
+ my $timeout = RunTimers();
+
+ # get up to 1000 events
+ epoll_wait($Epoll, 1000, $timeout, \@events);
+ for my $fd (@events) {
+ # it's possible epoll_wait returned many events,
+ # including some at the end that ones in the front
+ # triggered unregister-interest actions. if we can't
+ # find the %sock entry, it's because we're no longer
+ # interested in that event.
+
+ # guard stack-not-refcounted w/ Carp + @DB::args
+ my $obj = $DescriptorMap{$fd};
+ $obj->event_step;
+ }
+ } while (PostEventLoop());