From 5aaea61844b92c452c201ce9832e3c5c68c6f84e Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Fri, 3 May 2019 10:34:09 +0000 Subject: listener: use EPOLLEXCLUSIVE for listen sockets Since our listen sockets are non-blocking and we may run multiple httpd|nntpd processes; we need a way to avoid thundering herds when there are multiple httpd|nntpd worker processes. EPOLLEXCLUSIVE was added just for that in Linux 4.5 --- lib/PublicInbox/DS.pm | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'lib/PublicInbox/DS.pm') diff --git a/lib/PublicInbox/DS.pm b/lib/PublicInbox/DS.pm index 543d3fdc..3ccc275d 100644 --- a/lib/PublicInbox/DS.pm +++ b/lib/PublicInbox/DS.pm @@ -78,6 +78,8 @@ our ( @Timers, # timers ); +# this may be set to zero with old kernels +our $EPOLLEXCLUSIVE = EPOLLEXCLUSIVE; Reset(); ##################################################################### @@ -666,11 +668,9 @@ This is normally (always?) called from your subclass via: =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 @@ sub new { $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 -- cgit v1.2.3-24-ge0c7