From: Waldemar Kozaczuk <jwkozac...@gmail.com>
Committer: WALDEMAR KOZACZUK <jwkozac...@gmail.com>
Branch: master

Support EPOLLRDHUP in AF_LOCAL sockets

On startup, nginx tries to detect if EPOLLRDHUP is supported by epoll
by creating a pair of AF_LOCAL sockets and checking if the event is
reported when one of the sockets is abruptly closed. This causes a 5
seconds delay before nginx can start responding to any traffic.
The code in nginx is actually quite similar to the unit test added by this 
commit.

To address this shortcoming this commit changes underlying pipe_buffer
implementation to report POLLRDHUP instead of POLLERR|POLLOUT when
receiver is disconnected for af_local. It still reports the latter
events for pipes.

Signed-off-by: Waldemar Kozaczuk <jwkozac...@gmail.com>

---
diff --git a/libc/af_local.cc b/libc/af_local.cc
--- a/libc/af_local.cc
+++ b/libc/af_local.cc
@@ -65,6 +65,7 @@ int af_local::ioctl(u_long cmd, void *data)
 void af_local::init()
 {
     send->attach_sender(this);
+    send->set_no_receiver_event(POLLRDHUP);
     receive->attach_receiver(this);
 }
 
diff --git a/libc/pipe_buffer.cc b/libc/pipe_buffer.cc
--- a/libc/pipe_buffer.cc
+++ b/libc/pipe_buffer.cc
@@ -29,7 +29,7 @@ void pipe_buffer::detach_receiver()
     if (receiver) {
         receiver = nullptr;
         if (sender)
-            poll_wake(sender, POLLERR|POLLOUT);
+            poll_wake(sender, no_receiver_event);
         may_write.wake_all();
     }
 }
@@ -57,7 +57,7 @@ int pipe_buffer::read_events_unlocked()
 int pipe_buffer::write_events_unlocked()
 {
     if (!receiver) {
-        return POLLERR|POLLOUT;
+        return no_receiver_event;
     }
     int ret = 0;
     ret |= q.size() < max_buf ? POLLOUT : 0;
diff --git a/libc/pipe_buffer.hh b/libc/pipe_buffer.hh
--- a/libc/pipe_buffer.hh
+++ b/libc/pipe_buffer.hh
@@ -30,6 +30,9 @@ public:
     void detach_receiver();
     void attach_sender(struct file *f);
     void attach_receiver(struct file *f);
+    void set_no_receiver_event(int event) {
+        this->no_receiver_event = event;
+    }
 private:
     int read_events_unlocked();
     int write_events_unlocked();
@@ -41,6 +44,7 @@ private:
     std::atomic<unsigned> refs = {};
     condvar may_read;
     condvar may_write;
+    int no_receiver_event = POLLERR|POLLOUT;
     friend void intrusive_ptr_add_ref(pipe_buffer* p) {
         p->refs.fetch_add(1, std::memory_order_relaxed);
     }
diff --git a/tests/tst-epoll.cc b/tests/tst-epoll.cc
--- a/tests/tst-epoll.cc
+++ b/tests/tst-epoll.cc
@@ -184,6 +184,60 @@ static void test_socket_epollrdhup()
     client.join();
 }
 
+static void test_af_local_epollrdhup()
+{
+    int s[2], events;
+    struct epoll_event ee;
+
+    int ep = epoll_create(1);
+    report(ep >= 0, "epoll_create");
+
+    if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == -1) {
+        report(0, "socketpair() failed");
+        return;
+    }
+    report(1, "socketpair() succeeded");
+
+    ee.events = EPOLLET|EPOLLIN|EPOLLRDHUP;
+
+    if (epoll_ctl(ep, EPOLL_CTL_ADD, s[0], &ee) == -1) {
+        report(0, "epoll_ctl() failed");
+        goto failed;
+    }
+    report(1, "epoll_crtl() succeeded");
+
+    if (close(s[1]) == -1) {
+        report(0, "close() failed");
+        s[1] = -1;
+        goto failed;
+    }
+
+    s[1] = -1;
+
+    events = epoll_wait(ep, &ee, 1, 5000);
+
+    if (events == -1) {
+        report(0, "epoll_wait() failed");
+        goto failed;
+    }
+
+    if (events) {
+        report(ee.events & EPOLLRDHUP, "EPOLLRDHUP active");
+    } else {
+        report(0, "epoll_wait() timed out\n");
+    }
+
+failed:
+
+    if (s[1] != -1 && close(s[1]) == -1) {
+        report(0, "close() failed");
+    }
+
+    if (close(s[0]) == -1) {
+        report(0, "close() failed");
+    }
+}
+
 int main(int ac, char** av)
 {
     int ep = epoll_create(1);
@@ -338,6 +392,7 @@ int main(int ac, char** av)
     test_epolloneshot();
     test_epoll_file();
     test_socket_epollrdhup();
+    test_af_local_epollrdhup();
 
     std::cout << "SUMMARY: " << tests << ", " << fails << " failures\n";
     return !!fails;

-- 
You received this message because you are subscribed to the Google Groups "OSv 
Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to osv-dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/osv-dev/000000000000425a9d0602724b4f%40google.com.

Reply via email to