about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2019-06-29 20:19:29 +0000
committerEric Wong <e@80x24.org>2019-06-29 20:41:38 +0000
commitf984b8ea898add0f67392723dd38c2ddd73dfa13 (patch)
treee5232c727055f7ace4410dbfb81ac6d298c16fd1
parent8922459f0fa7265cfe3dee21f56895aeeb560d47 (diff)
downloadpublic-inbox-f984b8ea898add0f67392723dd38c2ddd73dfa13.tar.gz
EV_DISPATCH is actually a better match for EPOLLONESHOT
semantics than EV_ONESHOT in that it doesn't require EV_ADD
for every mod operation.

Blindly using EV_ADD everywhere forces the FreeBSD kernel to
do extra allocations up front, so it's best avoided.
-rw-r--r--lib/PublicInbox/DSKQXS.pm20
1 files changed, 15 insertions, 5 deletions
diff --git a/lib/PublicInbox/DSKQXS.pm b/lib/PublicInbox/DSKQXS.pm
index 278d3f88..1c3b970b 100644
--- a/lib/PublicInbox/DSKQXS.pm
+++ b/lib/PublicInbox/DSKQXS.pm
@@ -17,7 +17,7 @@ use parent qw(IO::KQueue);
 use parent qw(Exporter);
 use IO::KQueue;
 use PublicInbox::Syscall qw(EPOLLONESHOT EPOLLIN EPOLLOUT EPOLLET
-        EPOLL_CTL_DEL);
+        EPOLL_CTL_ADD EPOLL_CTL_MOD EPOLL_CTL_DEL);
 our @EXPORT_OK = qw(epoll_ctl epoll_wait);
 my $owner_pid = -1; # kqueue is close-on-fork (yes, fork, not exec)
 
@@ -25,11 +25,15 @@ my $owner_pid = -1; # kqueue is close-on-fork (yes, fork, not exec)
 sub kq_flag ($$) {
         my ($bit, $ev) = @_;
         if ($ev & $bit) {
-                my $fl = EV_ADD | EV_ENABLE;
+                my $fl = EV_ENABLE;
                 $fl |= EV_CLEAR if $fl & EPOLLET;
-                ($ev & EPOLLONESHOT) ? ($fl | EV_ONESHOT) : $fl;
+
+                # EV_DISPATCH matches EPOLLONESHOT semantics more closely
+                # than EV_ONESHOT, in that EV_ADD is not required to
+                # re-enable a disabled watch.
+                ($ev & EPOLLONESHOT) ? ($fl | EV_DISPATCH) : $fl;
         } else {
-                EV_ADD | EV_DISABLE;
+                EV_DISABLE;
         }
 }
 
@@ -42,9 +46,15 @@ sub new {
 
 sub epoll_ctl {
         my ($self, $op, $fd, $ev) = @_;
-        if ($op != EPOLL_CTL_DEL) {
+        if ($op == EPOLL_CTL_MOD) {
                 $self->EV_SET($fd, EVFILT_READ, kq_flag(EPOLLIN, $ev));
                 $self->EV_SET($fd, EVFILT_WRITE, kq_flag(EPOLLOUT, $ev));
+        } elsif ($op == EPOLL_CTL_DEL) {
+                $self->EV_SET($fd, EVFILT_READ, EV_DISABLE);
+                $self->EV_SET($fd, EVFILT_WRITE, EV_DISABLE);
+        } else {
+                $self->EV_SET($fd, EVFILT_READ, EV_ADD|kq_flag(EPOLLIN, $ev));
+                $self->EV_SET($fd, EVFILT_WRITE, EV_ADD|kq_flag(EPOLLOUT, $ev));
         }
         0;
 }