Support EV_CLOSED on linux for poll(2)

Refs: #984
(cherry picked from commit 4c13afaeec2d35df2580dfbc49391d0524101248)
This commit is contained in:
Azat Khuzhin 2020-05-05 01:13:49 +03:00
parent 1df324d4c4
commit 2530e7c630

23
poll.c
View File

@ -53,6 +53,17 @@
#include "evthread-internal.h" #include "evthread-internal.h"
#include "time-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 { struct pollidx {
int idxplus1; int idxplus1;
}; };
@ -80,7 +91,7 @@ const struct eventop pollops = {
poll_dispatch, poll_dispatch,
poll_dealloc, poll_dealloc,
0, /* doesn't need_reinit */ 0, /* doesn't need_reinit */
EV_FEATURE_FDS, EV_FEATURE_FDS|EARLY_CLOSE_IF_HAVE_RDHUP,
sizeof(struct pollidx), sizeof(struct pollidx),
}; };
@ -204,6 +215,8 @@ poll_dispatch(struct event_base *base, struct timeval *tv)
res |= EV_READ; res |= EV_READ;
if (what & POLLOUT) if (what & POLLOUT)
res |= EV_WRITE; res |= EV_WRITE;
if (what & POLLRDHUP)
res |= EV_CLOSED;
if (res == 0) if (res == 0)
continue; continue;
@ -222,7 +235,7 @@ poll_add(struct event_base *base, int fd, short old, short events, void *idx_)
int i; int i;
EVUTIL_ASSERT((events & EV_SIGNAL) == 0); EVUTIL_ASSERT((events & EV_SIGNAL) == 0);
if (!(events & (EV_READ|EV_WRITE))) if (!(events & (EV_READ|EV_WRITE|EV_CLOSED)))
return (0); return (0);
poll_check_ok(pop); 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; pfd->events |= POLLOUT;
if (events & EV_READ) if (events & EV_READ)
pfd->events |= POLLIN; pfd->events |= POLLIN;
if (events & EV_CLOSED)
pfd->events |= POLLRDHUP;
poll_check_ok(pop); poll_check_ok(pop);
return (0); return (0);
@ -283,7 +298,7 @@ poll_del(struct event_base *base, int fd, short old, short events, void *idx_)
int i; int i;
EVUTIL_ASSERT((events & EV_SIGNAL) == 0); EVUTIL_ASSERT((events & EV_SIGNAL) == 0);
if (!(events & (EV_READ|EV_WRITE))) if (!(events & (EV_READ|EV_WRITE|EV_CLOSED)))
return (0); return (0);
poll_check_ok(pop); 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; pfd->events &= ~POLLIN;
if (events & EV_WRITE) if (events & EV_WRITE)
pfd->events &= ~POLLOUT; pfd->events &= ~POLLOUT;
if (events & EV_CLOSED)
pfd->events &= ~POLLRDHUP;
poll_check_ok(pop); poll_check_ok(pop);
if (pfd->events) if (pfd->events)
/* Another event cares about that fd. */ /* Another event cares about that fd. */