]> Sergey Matveev's repositories - public-inbox.git/blobdiff - lib/PublicInbox/DSKQXS.pm
Merge remote-tracking branch 'origin/inboxdir'
[public-inbox.git] / lib / PublicInbox / DSKQXS.pm
index 38e13446888ea893ec88f8091e6d1a156c460604..1c3b970b7a332d3fd681fd885157005c70fea504 100644 (file)
@@ -16,18 +16,24 @@ 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);
+use PublicInbox::Syscall qw(EPOLLONESHOT EPOLLIN EPOLLOUT EPOLLET
+       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)
 
 # 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;
+               my $fl = EV_ENABLE;
+               $fl |= EV_CLEAR if $fl & EPOLLET;
+
+               # 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;
        }
 }
 
@@ -40,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;
 }