use IO::Poll;
use PublicInbox::Syscall qw(EPOLLONESHOT EPOLLIN EPOLLOUT);
-sub new { bless {}, __PACKAGE__ } # fd => events
+sub new { bless { poll => IO::Poll->new }, __PACKAGE__ } # fd => events
sub ep_wait {
my ($self, $maxevents, $timeout_msec, $events) = @_;
- my @pset;
- while (my ($fd, $events) = each %$self) {
- my $pevents = $events & EPOLLIN ? POLLIN : 0;
- $pevents |= $events & EPOLLOUT ? POLLOUT : 0;
- push(@pset, $fd, $pevents);
- }
- @$events = ();
- my $n = IO::Poll::_poll($timeout_msec, @pset);
- if ($n >= 0) {
- for (my $i = 0; $i < @pset; ) {
- my $fd = $pset[$i++];
- my $revents = $pset[$i++] or next;
- delete($self->{$fd}) if $self->{$fd} & EPOLLONESHOT;
- push @$events, $fd;
- }
- my $nevents = scalar @$events;
- if ($n != $nevents) {
- warn "BUG? poll() returned $n, but got $nevents";
- }
+ $self->{poll}->poll($timeout_msec/1000) > 0 or return (@$events = ());
+ my @io = $self->{poll}->handles(POLLIN|POLLOUT);
+ @$events = map { fileno($_) } @io;
+ for (@$events) {
+ my $io = shift @io;
+ $self->{poll}->remove($io) if delete($self->{oneshot}->{$_});
}
}
-sub ep_del { delete($_[0]->{fileno($_[1])}); 0 }
-sub ep_add { $_[0]->{fileno($_[1])} = $_[2]; 0 }
+sub ep_del {
+ my ($self, $io) = @_;
+ delete $self->{oneshot}->{fileno($io)};
+ $self->{poll}->remove($io);
+ 0;
+}
+
+sub ep_add {
+ my ($self, $io, $ev) = @_;
+ $self->{oneshot}->{fileno($io)} = 1 if $ev & EPOLLONESHOT;
+ $self->{poll}->mask($io, ($ev & EPOLLIN ? POLLIN : 0) |
+ ($ev & EPOLLOUT ? POLLOUT : 0));
+ 0;
+}
no warnings 'once';
*ep_mod = \&ep_add;