diff options
author | Eric Wong <e@80x24.org> | 2023-09-12 06:13:04 +0000 |
---|---|---|
committer | Eric Wong <e@80x24.org> | 2023-09-12 06:14:13 +0000 |
commit | 70a26c3af4e4e8eb9bcf86c9724bc560c3b1a8f9 (patch) | |
tree | 9351059ae64faba7394b9406057edd9a04dd065d /lib | |
parent | 6b278252cd994a866bd4cf15025033dd8afbd02b (diff) | |
download | public-inbox-70a26c3af4e4e8eb9bcf86c9724bc560c3b1a8f9.tar.gz |
This is safer than relying on an internal API of IO::Poll and doesn't create extra references to IO globs like the public one.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/PublicInbox/DS.pm | 6 | ||||
-rw-r--r-- | lib/PublicInbox/Select.pm | 40 |
2 files changed, 43 insertions, 3 deletions
diff --git a/lib/PublicInbox/DS.pm b/lib/PublicInbox/DS.pm index b3edc094..d47df491 100644 --- a/lib/PublicInbox/DS.pm +++ b/lib/PublicInbox/DS.pm @@ -31,7 +31,7 @@ use Scalar::Util qw(blessed); use PublicInbox::Syscall qw(%SIGNUM EPOLLIN EPOLLOUT EPOLLONESHOT EPOLLEXCLUSIVE); use PublicInbox::Tmpfile; -use PublicInbox::DSPoll; +use PublicInbox::Select; use Errno qw(EAGAIN EINVAL ECHILD EINTR); use Carp qw(carp croak); our @EXPORT_OK = qw(now msg_more awaitpid add_timer add_uniq_timer); @@ -43,7 +43,7 @@ my $reap_armed; my $ToClose; # sockets to close when event loop is done our ( %DescriptorMap, # fd (num) -> PublicInbox::DS object - $Poller, # global Epoll, DSPoll, or DSKQXS ref + $Poller, # global Select, Epoll, DSPoll, or DSKQXS ref @post_loop_do, # subref + args to call at the end of each loop @@ -83,7 +83,7 @@ sub Reset { $reap_armed = undef; $LoopTimeout = -1; # no timeout by default - $Poller = PublicInbox::DSPoll->new; + $Poller = PublicInbox::Select->new; } =head2 C<< CLASS->SetLoopTimeout( $timeout ) >> diff --git a/lib/PublicInbox/Select.pm b/lib/PublicInbox/Select.pm new file mode 100644 index 00000000..9df3a6bd --- /dev/null +++ b/lib/PublicInbox/Select.pm @@ -0,0 +1,40 @@ +# Copyright (C) all contributors <meta@public-inbox.org> +# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt> +# +# This makes select(2) look like epoll to simplify the code in DS.pm. +# Unlike IO::Select, it does NOT hold references to IO handles. +# This is NOT meant to be an all encompassing emulation of epoll +# via select, but only to support cases we care about. +package PublicInbox::Select; +use v5.12; +use PublicInbox::Syscall qw(EPOLLONESHOT EPOLLIN EPOLLOUT); + +sub new { bless {}, __PACKAGE__ } # fd => events + +sub ep_wait { + my ($self, $maxevents, $msec, $events) = @_; + my ($rvec, $wvec) = ('', ''); # we don't use EPOLLERR + while (my ($fd, $ev) = each %$self) { + vec($rvec, $fd, 1) = 1 if $ev & EPOLLIN; + vec($wvec, $fd, 1) = 1 if $ev & EPOLLOUT; + } + @$events = (); + my $n = select($rvec, $wvec, undef, $msec < 0 ? undef : ($msec/1000)); + return if $n <= 0; + while (my ($fd, $ev) = each %$self) { + if (vec($rvec, $fd, 1) || vec($wvec, $fd, 1)) { + delete($self->{$fd}) if $ev & EPOLLONESHOT; + push @$events, $fd; + } + } + $n == scalar(@$events) or + warn "BUG? select() returned $n, but got ".scalar(@$events); +} + +sub ep_del { delete($_[0]->{fileno($_[1])}); 0 } +sub ep_add { $_[0]->{fileno($_[1])} = $_[2]; 0 } + +no warnings 'once'; +*ep_mod = \&ep_add; + +1; |