From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: X-Spam-Status: No, score=-4.2 required=3.0 tests=ALL_TRUSTED,BAYES_00, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF shortcircuit=no autolearn=ham autolearn_force=no version=3.4.6 Received: from localhost (dcvr.yhbt.net [127.0.0.1]) by dcvr.yhbt.net (Postfix) with ESMTP id A36E21F55F for ; Tue, 12 Sep 2023 06:13:10 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=80x24.org; s=selector1; t=1694499190; bh=CeBtnCbxijhmqqUfEVA9WGJXgXTeQse3mj9AvKtzRds=; h=Date:From:To:Subject:References:In-Reply-To:From; b=pmLs9hV/+XrCZiqiUTrivy5ERMpUhNqy4MaNOLKUxPtRFjOh/2BRCaJtsRVnwK/Po buflfCdfyoi/V0dgaMnQ2rC7gslA7UsyCONhm3hsMlDW7oatfv1eYMQs6BeUFACXzY J2OaGKuWc2Qu9+X10BqdTbAGH/v83r9F/ceYWP+k= Date: Tue, 12 Sep 2023 06:13:04 +0000 From: Eric Wong To: meta@public-inbox.org Subject: [PATCH 8/7] provide select(2) backend for PublicInbox::DS Message-ID: <20230912061304.M916432@dcvr> References: <20230911094132.75792-1-e@80x24.org> <20230911094132.75792-6-e@80x24.org> <20230912023402.M761405@dcvr> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline In-Reply-To: <20230912023402.M761405@dcvr> List-Id: 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. --- Not sure if this is redundant or not, or if perhaps dropping DSPoll would be preferable, even... MANIFEST | 2 ++ lib/PublicInbox/DS.pm | 6 +++--- lib/PublicInbox/Select.pm | 40 +++++++++++++++++++++++++++++++++++++++ t/select.t | 4 ++++ 4 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 lib/PublicInbox/Select.pm create mode 100644 t/select.t diff --git a/MANIFEST b/MANIFEST index d7a670b8..63287bad 100644 --- a/MANIFEST +++ b/MANIFEST @@ -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 +# License: AGPL-3.0+ +# +# 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 +use v5.12; +local $ENV{TEST_IOPOLLER} = 'PublicInbox::Select'; +require './t/ds-poll.t';