TODO | 3 --- lib/PublicInbox/DS.pm | 22 ++++++++++++++++------ lib/PublicInbox/Listener.pm | 2 +- lib/PublicInbox/Syscall.pm | 7 +++++-- diff --git a/TODO b/TODO index 372f7331e78d345fd44117707bd9cc87618f34b4..ac255b861ca3e21d6598be1493845b79afbaf812 100644 --- a/TODO +++ b/TODO @@ -56,9 +56,6 @@ * portability to FreeBSD (and other Free Software *BSDs) ugh... https://rt.cpan.org/Ticket/Display.html?id=116615 (IO::KQueue is broken with Danga::Socket / PublicInbox::DS) -* EPOLLEXCLUSIVE for listen socket fairness across -httpd/nntpd - worker processes. - * improve documentation * linkify thread skeletons better diff --git a/lib/PublicInbox/DS.pm b/lib/PublicInbox/DS.pm index 543d3fdcc755da03c910892b16c6a596a20c34d4..3ccc275d727e6a5245eab59f112ef7759c28ac33 100644 --- a/lib/PublicInbox/DS.pm +++ b/lib/PublicInbox/DS.pm @@ -78,6 +78,8 @@ $DoneInit, # if we've done the one-time module init yet @Timers, # timers ); +# this may be set to zero with old kernels +our $EPOLLEXCLUSIVE = EPOLLEXCLUSIVE; Reset(); ##################################################################### @@ -666,10 +668,8 @@ $class->SUPER::new($socket); =cut sub new { - my PublicInbox::DS $self = shift; + my ($self, $sock, $exclusive) = @_; $self = fields::new($self) unless ref $self; - - my $sock = shift; $self->{sock} = $sock; my $fd = fileno($sock); @@ -685,13 +685,23 @@ $self->{closed} = 0; $self->{corked} = 0; $self->{read_push_back} = []; - $self->{event_watch} = POLLERR|POLLHUP|POLLNVAL; + my $ev = $self->{event_watch} = POLLERR|POLLHUP|POLLNVAL; _InitPoller(); if ($HaveEpoll) { - epoll_ctl($Epoll, EPOLL_CTL_ADD, $fd, $self->{event_watch}) - and die "couldn't add epoll watch for $fd\n"; + if ($exclusive) { + $ev = $self->{event_watch} = EPOLLIN|EPOLLERR|EPOLLHUP|$EPOLLEXCLUSIVE; + } +retry: + if (epoll_ctl($Epoll, EPOLL_CTL_ADD, $fd, $ev)) { + if ($!{EINVAL} && ($ev & $EPOLLEXCLUSIVE)) { + $EPOLLEXCLUSIVE = 0; # old kernel + $ev = $self->{event_watch} = EPOLLIN|EPOLLERR|EPOLLHUP; + goto retry; + } + die "couldn't add epoll watch for $fd: $!\n"; + } } elsif ($HaveKQueue) { # Add them to the queue but disabled for now diff --git a/lib/PublicInbox/Listener.pm b/lib/PublicInbox/Listener.pm index d1f0d2e943b03dc860d57246059a842f52b5b727..a75a6fd9964ed1c9c2d2780b6680aa1b39ee76b2 100644 --- a/lib/PublicInbox/Listener.pm +++ b/lib/PublicInbox/Listener.pm @@ -17,7 +17,7 @@ setsockopt($s, IPPROTO_TCP, TCP_NODELAY, 1); # ignore errors on non-TCP listen($s, 1024); IO::Handle::blocking($s, 0); my $self = fields::new($class); - $self->SUPER::new($s); # calls epoll_create for the first socket + $self->SUPER::new($s, 1); # calls epoll_create for the first socket $self->watch_read(1); $self->{post_accept} = $cb; $self diff --git a/lib/PublicInbox/Syscall.pm b/lib/PublicInbox/Syscall.pm index cf7004548684c857607b7a46ac8a726d5733a932..919436471b0e4dc98871a3a5658dd99049027c5f 100644 --- a/lib/PublicInbox/Syscall.pm +++ b/lib/PublicInbox/Syscall.pm @@ -23,10 +23,12 @@ $VERSION = "0.25"; @ISA = qw(Exporter); @EXPORT_OK = qw(sendfile epoll_ctl epoll_create epoll_wait EPOLLIN EPOLLOUT EPOLLERR EPOLLHUP EPOLLRDBAND - EPOLL_CTL_ADD EPOLL_CTL_DEL EPOLL_CTL_MOD); + EPOLL_CTL_ADD EPOLL_CTL_DEL EPOLL_CTL_MOD + EPOLLEXCLUSIVE); %EXPORT_TAGS = (epoll => [qw(epoll_ctl epoll_create epoll_wait EPOLLIN EPOLLOUT EPOLLERR EPOLLHUP EPOLLRDBAND - EPOLL_CTL_ADD EPOLL_CTL_DEL EPOLL_CTL_MOD)], + EPOLL_CTL_ADD EPOLL_CTL_DEL EPOLL_CTL_MOD + EPOLLEXCLUSIVE)], sendfile => [qw(sendfile)], ); @@ -35,6 +37,7 @@ use constant EPOLLOUT => 4; use constant EPOLLERR => 8; use constant EPOLLHUP => 16; use constant EPOLLRDBAND => 128; +use constant EPOLLEXCLUSIVE => (1 << 28); use constant EPOLL_CTL_ADD => 1; use constant EPOLL_CTL_DEL => 2; use constant EPOLL_CTL_MOD => 3;