diff options
-rw-r--r-- | MANIFEST | 2 | ||||
-rw-r--r-- | lib/PublicInbox/DS.pm | 6 | ||||
-rw-r--r-- | lib/PublicInbox/Select.pm | 40 | ||||
-rw-r--r-- | t/select.t | 4 |
4 files changed, 49 insertions, 3 deletions
@@ -331,6 +331,7 @@ lib/PublicInbox/SearchIdxShard.pm lib/PublicInbox/SearchQuery.pm lib/PublicInbox/SearchThread.pm lib/PublicInbox/SearchView.pm +lib/PublicInbox/Select.pm lib/PublicInbox/SharedKV.pm lib/PublicInbox/Sigfd.pm lib/PublicInbox/Smsg.pm @@ -578,6 +579,7 @@ t/run.perl t/search-amsg.eml t/search-thr-index.t t/search.t +t/select.t t/sha.t t/shared_kv.t t/sigfd.t 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; diff --git a/t/select.t b/t/select.t new file mode 100644 index 00000000..e8032c5a --- /dev/null +++ b/t/select.t @@ -0,0 +1,4 @@ +# Copyright (C) all contributors <meta@public-inbox.org> +use v5.12; +local $ENV{TEST_IOPOLLER} = 'PublicInbox::Select'; +require './t/ds-poll.t'; |