diff options
author | Eric Wong <e@80x24.org> | 2019-06-24 02:52:55 +0000 |
---|---|---|
committer | Eric Wong <e@80x24.org> | 2019-06-24 05:26:36 +0000 |
commit | df5755b40b4ba1d6048042e18d8ea501755b9a02 (patch) | |
tree | f25a2ac8d90af25e46f7b440073684301a153b1d /lib/PublicInbox/DSKQXS.pm | |
parent | fbcd2b5eb401a8e1811d803cef9b1c156acb50f6 (diff) | |
download | public-inbox-df5755b40b4ba1d6048042e18d8ea501755b9a02.tar.gz |
We don't need to code multiple event loops or have branches in watch() if we can easily make the IO::KQueue-based interface look like our lower-level epoll_* API.
Diffstat (limited to 'lib/PublicInbox/DSKQXS.pm')
-rw-r--r-- | lib/PublicInbox/DSKQXS.pm | 73 |
1 files changed, 73 insertions, 0 deletions
diff --git a/lib/PublicInbox/DSKQXS.pm b/lib/PublicInbox/DSKQXS.pm new file mode 100644 index 00000000..38e13446 --- /dev/null +++ b/lib/PublicInbox/DSKQXS.pm @@ -0,0 +1,73 @@ +# Copyright (C) 2019 all contributors <meta@public-inbox.org> +# Licensed the same as Danga::Socket (and Perl5) +# License: GPL-1.0+ or Artistic-1.0-Perl +# <https://www.gnu.org/licenses/gpl-1.0.txt> +# <https://dev.perl.org/licenses/artistic.html> +# +# kqueue support via IO::KQueue XS module. This makes kqueue look +# like epoll to simplify the code in DS.pm. This is NOT meant to be +# an all encompassing emulation of epoll via IO::KQueue, but just to +# support cases public-inbox-nntpd/httpd care about. +# A pure-Perl version using syscall() is planned, and it should be +# faster due to the lack of syscall overhead. +package PublicInbox::DSKQXS; +use strict; +use warnings; +use parent qw(IO::KQueue); +use parent qw(Exporter); +use IO::KQueue; +use PublicInbox::Syscall qw(EPOLLONESHOT EPOLLIN EPOLLOUT EPOLL_CTL_DEL); +our @EXPORT = qw(epoll_ctl epoll_wait); +my $owner_pid = -1; # kqueue is close-on-fork (yes, fork, not exec) + +# map EPOLL* bits to kqueue EV_* flags for EV_SET +sub kq_flag ($$) { + my ($bit, $ev) = @_; + if ($ev & $bit) { + my $fl = EV_ADD | EV_ENABLE; + ($ev & EPOLLONESHOT) ? ($fl | EV_ONESHOT) : $fl; + } else { + EV_ADD | EV_DISABLE; + } +} + +sub new { + my ($class) = @_; + die 'non-singleton use not supported' if $owner_pid == $$; + $owner_pid = $$; + $class->SUPER::new; +} + +sub epoll_ctl { + my ($self, $op, $fd, $ev) = @_; + if ($op != EPOLL_CTL_DEL) { + $self->EV_SET($fd, EVFILT_READ, kq_flag(EPOLLIN, $ev)); + $self->EV_SET($fd, EVFILT_WRITE, kq_flag(EPOLLOUT, $ev)); + } + 0; +} + +sub epoll_wait { + my ($self, $maxevents, $timeout_msec, $events) = @_; + @$events = eval { $self->kevent($timeout_msec) }; + if (my $err = $@) { + # workaround https://rt.cpan.org/Ticket/Display.html?id=116615 + if ($err =~ /Interrupted system call/) { + @$events = (); + } else { + die $err; + } + } + # caller only cares for $events[$i]->[0] + scalar(@$events); +} + +sub DESTROY { + my ($self) = @_; + if ($owner_pid == $$) { + POSIX::close($$self); + $owner_pid = -1; + } +} + +1; |