]> granicus.if.org Git - libevent/commitdiff
Support EV_CLOSED on linux for poll(2)
authorAzat Khuzhin <azat@libevent.org>
Mon, 4 May 2020 22:13:49 +0000 (01:13 +0300)
committerAzat Khuzhin <azat@libevent.org>
Mon, 4 May 2020 22:21:12 +0000 (01:21 +0300)
Refs: #984

poll.c

diff --git a/poll.c b/poll.c
index fe4407117770e926c8b702424739f47e6ffe9f02..ddae2bf04d2bd394038cfd77b1c0f750c1415502 100644 (file)
--- a/poll.c
+++ b/poll.c
 #include "evthread-internal.h"
 #include "time-internal.h"
 
+/* Since Linux 2.6.17, poll is able to report about peer half-closed connection
+   using special POLLRDHUP flag on a read event.
+*/
+#if !defined(POLLRDHUP)
+#define POLLRDHUP 0
+#define EARLY_CLOSE_IF_HAVE_RDHUP 0
+#else
+#define EARLY_CLOSE_IF_HAVE_RDHUP EV_FEATURE_EARLY_CLOSE
+#endif
+
+
 struct pollidx {
        int idxplus1;
 };
@@ -80,7 +91,7 @@ const struct eventop pollops = {
        poll_dispatch,
        poll_dealloc,
        0, /* doesn't need_reinit */
-       EV_FEATURE_FDS,
+       EV_FEATURE_FDS|EARLY_CLOSE_IF_HAVE_RDHUP,
        sizeof(struct pollidx),
 };
 
@@ -204,6 +215,8 @@ poll_dispatch(struct event_base *base, struct timeval *tv)
                        res |= EV_READ;
                if (what & POLLOUT)
                        res |= EV_WRITE;
+               if (what & POLLRDHUP)
+                       res |= EV_CLOSED;
                if (res == 0)
                        continue;
 
@@ -222,7 +235,7 @@ poll_add(struct event_base *base, int fd, short old, short events, void *idx_)
        int i;
 
        EVUTIL_ASSERT((events & EV_SIGNAL) == 0);
-       if (!(events & (EV_READ|EV_WRITE)))
+       if (!(events & (EV_READ|EV_WRITE|EV_CLOSED)))
                return (0);
 
        poll_check_ok(pop);
@@ -265,6 +278,8 @@ poll_add(struct event_base *base, int fd, short old, short events, void *idx_)
                pfd->events |= POLLOUT;
        if (events & EV_READ)
                pfd->events |= POLLIN;
+       if (events & EV_CLOSED)
+               pfd->events |= POLLRDHUP;
        poll_check_ok(pop);
 
        return (0);
@@ -283,7 +298,7 @@ poll_del(struct event_base *base, int fd, short old, short events, void *idx_)
        int i;
 
        EVUTIL_ASSERT((events & EV_SIGNAL) == 0);
-       if (!(events & (EV_READ|EV_WRITE)))
+       if (!(events & (EV_READ|EV_WRITE|EV_CLOSED)))
                return (0);
 
        poll_check_ok(pop);
@@ -297,6 +312,8 @@ poll_del(struct event_base *base, int fd, short old, short events, void *idx_)
                pfd->events &= ~POLLIN;
        if (events & EV_WRITE)
                pfd->events &= ~POLLOUT;
+       if (events & EV_CLOSED)
+               pfd->events &= ~POLLRDHUP;
        poll_check_ok(pop);
        if (pfd->events)
                /* Another event cares about that fd. */