summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--changelist-internal.h1
-rw-r--r--epoll.c1149
-rw-r--r--event.c34
-rw-r--r--evmap.c46
-rw-r--r--include/event2/event.h10
-rwxr-xr-xmake_epoll_table.py66
-rw-r--r--test/Makefile.nmake6
-rw-r--r--test/include.am3
-rw-r--r--test/test-closed.c117
-rwxr-xr-xtest/test.sh2
10 files changed, 1297 insertions, 137 deletions
diff --git a/changelist-internal.h b/changelist-internal.h
index 0ec2eeaf..98fc52ae 100644
--- a/changelist-internal.h
+++ b/changelist-internal.h
@@ -62,6 +62,7 @@ struct event_change {
* and write_change is unused. */
ev_uint8_t read_change;
ev_uint8_t write_change;
+ ev_uint8_t close_change;
};
/* Flags for read_change and write_change. */
diff --git a/epoll.c b/epoll.c
index 2d07ff62..bd425ed5 100644
--- a/epoll.c
+++ b/epoll.c
@@ -71,6 +71,13 @@
#define USING_TIMERFD
#endif
+/* Since Linux 2.6.17, epoll is able to report about peer half-closed connection
+ using special EPOLLRDHUP flag on a read event.
+*/
+#if !defined(EPOLLRDHUP)
+#define EPOLLRDHUP 0
+#endif
+
struct epollop {
struct epoll_event *events;
int nevents;
@@ -92,7 +99,7 @@ static const struct eventop epollops_changelist = {
epoll_dispatch,
epoll_dealloc,
1, /* need reinit */
- EV_FEATURE_ET|EV_FEATURE_O1,
+ EV_FEATURE_ET|EV_FEATURE_O1|EV_FEATURE_EARLY_CLOSE,
EVENT_CHANGELIST_FDINFO_SIZE
};
@@ -110,7 +117,7 @@ const struct eventop epollops = {
epoll_dispatch,
epoll_dealloc,
1, /* need reinit */
- EV_FEATURE_ET|EV_FEATURE_O1,
+ EV_FEATURE_ET|EV_FEATURE_O1|EV_FEATURE_EARLY_CLOSE,
0
};
@@ -241,7 +248,7 @@ epoll_op_to_string(int op)
Note also that this table is a little sparse, since ADD+DEL is
nonsensical ("xxx" in the list below.)
- Note also also that we are shifting old_events by only 3 bits, since
+ Note also also that we are shifting old_events by only 5 bits, since
EV_READ is 2 and EV_WRITE is 4.
The table was auto-generated with a python script, according to this
@@ -312,18 +319,26 @@ epoll_op_to_string(int op)
EV_CHANGE_DEL==2
EV_READ ==2
EV_WRITE ==4
- Bit 0: read change is add
- Bit 1: read change is del
- Bit 2: write change is add
- Bit 3: write change is del
- Bit 4: old events had EV_READ
- Bit 5: old events had EV_WRITE
+ EV_CLOSED ==0x80
+
+ Bit 0: close change is add
+ Bit 1: close change is del
+ Bit 2: read change is add
+ Bit 3: read change is del
+ Bit 4: write change is add
+ Bit 5: write change is del
+ Bit 6: old events had EV_READ
+ Bit 7: old events had EV_WRITE
+ Bit 8: old events had EV_CLOSED
*/
#define INDEX(c) \
- ( (((c)->read_change&(EV_CHANGE_ADD|EV_CHANGE_DEL))) | \
- (((c)->write_change&(EV_CHANGE_ADD|EV_CHANGE_DEL)) << 2) | \
- (((c)->old_events&(EV_READ|EV_WRITE)) << 3) )
+ ( (((c)->close_change&(EV_CHANGE_ADD|EV_CHANGE_DEL))) | \
+ (((c)->read_change&(EV_CHANGE_ADD|EV_CHANGE_DEL)) << 2) | \
+ (((c)->write_change&(EV_CHANGE_ADD|EV_CHANGE_DEL)) << 4) | \
+ (((c)->old_events&(EV_READ|EV_WRITE)) << 5) | \
+ (((c)->old_events&(EV_CLOSED)) << 1) \
+ )
#if EV_READ != 2 || EV_WRITE != 4 || EV_CHANGE_ADD != 1 || EV_CHANGE_DEL != 2
#error "Libevent's internals changed! Regenerate the op_table in epoll.c"
@@ -333,70 +348,1030 @@ static const struct operation {
int events;
int op;
} op_table[] = {
- { 0, 0 }, /* old= 0, write: 0, read: 0 */
- { EPOLLIN, EPOLL_CTL_ADD }, /* old= 0, write: 0, read:add */
- { EPOLLIN, EPOLL_CTL_DEL }, /* old= 0, write: 0, read:del */
- { 0, -1 }, /* old= 0, write: 0, read:xxx */
- { EPOLLOUT, EPOLL_CTL_ADD }, /* old= 0, write:add, read: 0 */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_ADD },/* old= 0, write:add, read:add */
- { EPOLLOUT, EPOLL_CTL_ADD }, /* old= 0, write:add, read:del */
- { 0, -1 }, /* old= 0, write:add, read:xxx */
- { EPOLLOUT, EPOLL_CTL_DEL }, /* old= 0, write:del, read: 0 */
- { EPOLLIN, EPOLL_CTL_ADD }, /* old= 0, write:del, read:add */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_DEL },/* old= 0, write:del, read:del */
- { 0, -1 }, /* old= 0, write:del, read:xxx */
- { 0, -1 }, /* old= 0, write:xxx, read: 0 */
- { 0, -1 }, /* old= 0, write:xxx, read:add */
- { 0, -1 }, /* old= 0, write:xxx, read:del */
- { 0, -1 }, /* old= 0, write:xxx, read:xxx */
- { 0, 0 }, /* old= r, write: 0, read: 0 */
- { EPOLLIN, EPOLL_CTL_MOD }, /* old= r, write: 0, read:add */
- { EPOLLIN, EPOLL_CTL_DEL }, /* old= r, write: 0, read:del */
- { 0, -1 }, /* old= r, write: 0, read:xxx */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },/* old= r, write:add, read: 0 */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },/* old= r, write:add, read:add */
- { EPOLLOUT, EPOLL_CTL_MOD }, /* old= r, write:add, read:del */
- { 0, -1 }, /* old= r, write:add, read:xxx */
- { EPOLLIN, EPOLL_CTL_MOD }, /* old= r, write:del, read: 0 */
- { EPOLLIN, EPOLL_CTL_MOD }, /* old= r, write:del, read:add */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_DEL },/* old= r, write:del, read:del */
- { 0, -1 }, /* old= r, write:del, read:xxx */
- { 0, -1 }, /* old= r, write:xxx, read: 0 */
- { 0, -1 }, /* old= r, write:xxx, read:add */
- { 0, -1 }, /* old= r, write:xxx, read:del */
- { 0, -1 }, /* old= r, write:xxx, read:xxx */
- { 0, 0 }, /* old= w, write: 0, read: 0 */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },/* old= w, write: 0, read:add */
- { EPOLLOUT, EPOLL_CTL_MOD }, /* old= w, write: 0, read:del */
- { 0, -1 }, /* old= w, write: 0, read:xxx */
- { EPOLLOUT, EPOLL_CTL_MOD }, /* old= w, write:add, read: 0 */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },/* old= w, write:add, read:add */
- { EPOLLOUT, EPOLL_CTL_MOD }, /* old= w, write:add, read:del */
- { 0, -1 }, /* old= w, write:add, read:xxx */
- { EPOLLOUT, EPOLL_CTL_DEL }, /* old= w, write:del, read: 0 */
- { EPOLLIN, EPOLL_CTL_MOD }, /* old= w, write:del, read:add */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_DEL },/* old= w, write:del, read:del */
- { 0, -1 }, /* old= w, write:del, read:xxx */
- { 0, -1 }, /* old= w, write:xxx, read: 0 */
- { 0, -1 }, /* old= w, write:xxx, read:add */
- { 0, -1 }, /* old= w, write:xxx, read:del */
- { 0, -1 }, /* old= w, write:xxx, read:xxx */
- { 0, 0 }, /* old=rw, write: 0, read: 0 */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },/* old=rw, write: 0, read:add */
- { EPOLLOUT, EPOLL_CTL_MOD }, /* old=rw, write: 0, read:del */
- { 0, -1 }, /* old=rw, write: 0, read:xxx */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },/* old=rw, write:add, read: 0 */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },/* old=rw, write:add, read:add */
- { EPOLLOUT, EPOLL_CTL_MOD }, /* old=rw, write:add, read:del */
- { 0, -1 }, /* old=rw, write:add, read:xxx */
- { EPOLLIN, EPOLL_CTL_MOD }, /* old=rw, write:del, read: 0 */
- { EPOLLIN, EPOLL_CTL_MOD }, /* old=rw, write:del, read:add */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_DEL },/* old=rw, write:del, read:del */
- { 0, -1 }, /* old=rw, write:del, read:xxx */
- { 0, -1 }, /* old=rw, write:xxx, read: 0 */
- { 0, -1 }, /* old=rw, write:xxx, read:add */
- { 0, -1 }, /* old=rw, write:xxx, read:del */
- { 0, -1 }, /* old=rw, write:xxx, read:xxx */
+ /* old= 0, write: 0, read: 0, close: 0 */
+ { 0, 0 },
+ /* old= 0, write: 0, read: 0, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_ADD },
+ /* old= 0, write: 0, read: 0, close:del */
+ { EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= 0, write: 0, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= 0, write: 0, read:add, close: 0 */
+ { EPOLLIN, EPOLL_CTL_ADD },
+ /* old= 0, write: 0, read:add, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_ADD },
+ /* old= 0, write: 0, read:add, close:del */
+ { EPOLLIN, EPOLL_CTL_ADD },
+ /* old= 0, write: 0, read:add, close:xxx */
+ { 0, 255 },
+ /* old= 0, write: 0, read:del, close: 0 */
+ { EPOLLIN, EPOLL_CTL_DEL },
+ /* old= 0, write: 0, read:del, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_ADD },
+ /* old= 0, write: 0, read:del, close:del */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= 0, write: 0, read:del, close:xxx */
+ { 0, 255 },
+ /* old= 0, write: 0, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= 0, write: 0, read:xxx, close:add */
+ { 0, 255 },
+ /* old= 0, write: 0, read:xxx, close:del */
+ { 0, 255 },
+ /* old= 0, write: 0, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= 0, write:add, read: 0, close: 0 */
+ { EPOLLOUT, EPOLL_CTL_ADD },
+ /* old= 0, write:add, read: 0, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_ADD },
+ /* old= 0, write:add, read: 0, close:del */
+ { EPOLLOUT, EPOLL_CTL_ADD },
+ /* old= 0, write:add, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= 0, write:add, read:add, close: 0 */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_ADD },
+ /* old= 0, write:add, read:add, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_ADD },
+ /* old= 0, write:add, read:add, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_ADD },
+ /* old= 0, write:add, read:add, close:xxx */
+ { 0, 255 },
+ /* old= 0, write:add, read:del, close: 0 */
+ { EPOLLOUT, EPOLL_CTL_ADD },
+ /* old= 0, write:add, read:del, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_ADD },
+ /* old= 0, write:add, read:del, close:del */
+ { EPOLLOUT, EPOLL_CTL_ADD },
+ /* old= 0, write:add, read:del, close:xxx */
+ { 0, 255 },
+ /* old= 0, write:add, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= 0, write:add, read:xxx, close:add */
+ { 0, 255 },
+ /* old= 0, write:add, read:xxx, close:del */
+ { 0, 255 },
+ /* old= 0, write:add, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= 0, write:del, read: 0, close: 0 */
+ { EPOLLOUT, EPOLL_CTL_DEL },
+ /* old= 0, write:del, read: 0, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_ADD },
+ /* old= 0, write:del, read: 0, close:del */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= 0, write:del, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= 0, write:del, read:add, close: 0 */
+ { EPOLLIN, EPOLL_CTL_ADD },
+ /* old= 0, write:del, read:add, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_ADD },
+ /* old= 0, write:del, read:add, close:del */
+ { EPOLLIN, EPOLL_CTL_ADD },
+ /* old= 0, write:del, read:add, close:xxx */
+ { 0, 255 },
+ /* old= 0, write:del, read:del, close: 0 */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_DEL },
+ /* old= 0, write:del, read:del, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_ADD },
+ /* old= 0, write:del, read:del, close:del */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= 0, write:del, read:del, close:xxx */
+ { 0, 255 },
+ /* old= 0, write:del, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= 0, write:del, read:xxx, close:add */
+ { 0, 255 },
+ /* old= 0, write:del, read:xxx, close:del */
+ { 0, 255 },
+ /* old= 0, write:del, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= 0, write:xxx, read: 0, close: 0 */
+ { 0, 255 },
+ /* old= 0, write:xxx, read: 0, close:add */
+ { 0, 255 },
+ /* old= 0, write:xxx, read: 0, close:del */
+ { 0, 255 },
+ /* old= 0, write:xxx, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= 0, write:xxx, read:add, close: 0 */
+ { 0, 255 },
+ /* old= 0, write:xxx, read:add, close:add */
+ { 0, 255 },
+ /* old= 0, write:xxx, read:add, close:del */
+ { 0, 255 },
+ /* old= 0, write:xxx, read:add, close:xxx */
+ { 0, 255 },
+ /* old= 0, write:xxx, read:del, close: 0 */
+ { 0, 255 },
+ /* old= 0, write:xxx, read:del, close:add */
+ { 0, 255 },
+ /* old= 0, write:xxx, read:del, close:del */
+ { 0, 255 },
+ /* old= 0, write:xxx, read:del, close:xxx */
+ { 0, 255 },
+ /* old= 0, write:xxx, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= 0, write:xxx, read:xxx, close:add */
+ { 0, 255 },
+ /* old= 0, write:xxx, read:xxx, close:del */
+ { 0, 255 },
+ /* old= 0, write:xxx, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= r, write: 0, read: 0, close: 0 */
+ { 0, 0 },
+ /* old= r, write: 0, read: 0, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= r, write: 0, read: 0, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= r, write: 0, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= r, write: 0, read:add, close: 0 */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= r, write: 0, read:add, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= r, write: 0, read:add, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= r, write: 0, read:add, close:xxx */
+ { 0, 255 },
+ /* old= r, write: 0, read:del, close: 0 */
+ { EPOLLIN, EPOLL_CTL_DEL },
+ /* old= r, write: 0, read:del, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= r, write: 0, read:del, close:del */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= r, write: 0, read:del, close:xxx */
+ { 0, 255 },
+ /* old= r, write: 0, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= r, write: 0, read:xxx, close:add */
+ { 0, 255 },
+ /* old= r, write: 0, read:xxx, close:del */
+ { 0, 255 },
+ /* old= r, write: 0, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= r, write:add, read: 0, close: 0 */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= r, write:add, read: 0, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= r, write:add, read: 0, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= r, write:add, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= r, write:add, read:add, close: 0 */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= r, write:add, read:add, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= r, write:add, read:add, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= r, write:add, read:add, close:xxx */
+ { 0, 255 },
+ /* old= r, write:add, read:del, close: 0 */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= r, write:add, read:del, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= r, write:add, read:del, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= r, write:add, read:del, close:xxx */
+ { 0, 255 },
+ /* old= r, write:add, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= r, write:add, read:xxx, close:add */
+ { 0, 255 },
+ /* old= r, write:add, read:xxx, close:del */
+ { 0, 255 },
+ /* old= r, write:add, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= r, write:del, read: 0, close: 0 */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= r, write:del, read: 0, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= r, write:del, read: 0, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= r, write:del, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= r, write:del, read:add, close: 0 */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= r, write:del, read:add, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= r, write:del, read:add, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= r, write:del, read:add, close:xxx */
+ { 0, 255 },
+ /* old= r, write:del, read:del, close: 0 */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_DEL },
+ /* old= r, write:del, read:del, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= r, write:del, read:del, close:del */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= r, write:del, read:del, close:xxx */
+ { 0, 255 },
+ /* old= r, write:del, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= r, write:del, read:xxx, close:add */
+ { 0, 255 },
+ /* old= r, write:del, read:xxx, close:del */
+ { 0, 255 },
+ /* old= r, write:del, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= r, write:xxx, read: 0, close: 0 */
+ { 0, 255 },
+ /* old= r, write:xxx, read: 0, close:add */
+ { 0, 255 },
+ /* old= r, write:xxx, read: 0, close:del */
+ { 0, 255 },
+ /* old= r, write:xxx, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= r, write:xxx, read:add, close: 0 */
+ { 0, 255 },
+ /* old= r, write:xxx, read:add, close:add */
+ { 0, 255 },
+ /* old= r, write:xxx, read:add, close:del */
+ { 0, 255 },
+ /* old= r, write:xxx, read:add, close:xxx */
+ { 0, 255 },
+ /* old= r, write:xxx, read:del, close: 0 */
+ { 0, 255 },
+ /* old= r, write:xxx, read:del, close:add */
+ { 0, 255 },
+ /* old= r, write:xxx, read:del, close:del */
+ { 0, 255 },
+ /* old= r, write:xxx, read:del, close:xxx */
+ { 0, 255 },
+ /* old= r, write:xxx, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= r, write:xxx, read:xxx, close:add */
+ { 0, 255 },
+ /* old= r, write:xxx, read:xxx, close:del */
+ { 0, 255 },
+ /* old= r, write:xxx, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= w, write: 0, read: 0, close: 0 */
+ { 0, 0 },
+ /* old= w, write: 0, read: 0, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= w, write: 0, read: 0, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= w, write: 0, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= w, write: 0, read:add, close: 0 */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= w, write: 0, read:add, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= w, write: 0, read:add, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= w, write: 0, read:add, close:xxx */
+ { 0, 255 },
+ /* old= w, write: 0, read:del, close: 0 */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= w, write: 0, read:del, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= w, write: 0, read:del, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= w, write: 0, read:del, close:xxx */
+ { 0, 255 },
+ /* old= w, write: 0, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= w, write: 0, read:xxx, close:add */
+ { 0, 255 },
+ /* old= w, write: 0, read:xxx, close:del */
+ { 0, 255 },
+ /* old= w, write: 0, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= w, write:add, read: 0, close: 0 */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= w, write:add, read: 0, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= w, write:add, read: 0, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= w, write:add, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= w, write:add, read:add, close: 0 */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= w, write:add, read:add, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= w, write:add, read:add, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= w, write:add, read:add, close:xxx */
+ { 0, 255 },
+ /* old= w, write:add, read:del, close: 0 */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= w, write:add, read:del, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= w, write:add, read:del, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= w, write:add, read:del, close:xxx */
+ { 0, 255 },
+ /* old= w, write:add, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= w, write:add, read:xxx, close:add */
+ { 0, 255 },
+ /* old= w, write:add, read:xxx, close:del */
+ { 0, 255 },
+ /* old= w, write:add, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= w, write:del, read: 0, close: 0 */
+ { EPOLLOUT, EPOLL_CTL_DEL },
+ /* old= w, write:del, read: 0, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= w, write:del, read: 0, close:del */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= w, write:del, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= w, write:del, read:add, close: 0 */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= w, write:del, read:add, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= w, write:del, read:add, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= w, write:del, read:add, close:xxx */
+ { 0, 255 },
+ /* old= w, write:del, read:del, close: 0 */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_DEL },
+ /* old= w, write:del, read:del, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= w, write:del, read:del, close:del */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= w, write:del, read:del, close:xxx */
+ { 0, 255 },
+ /* old= w, write:del, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= w, write:del, read:xxx, close:add */
+ { 0, 255 },
+ /* old= w, write:del, read:xxx, close:del */
+ { 0, 255 },
+ /* old= w, write:del, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= w, write:xxx, read: 0, close: 0 */
+ { 0, 255 },
+ /* old= w, write:xxx, read: 0, close:add */
+ { 0, 255 },
+ /* old= w, write:xxx, read: 0, close:del */
+ { 0, 255 },
+ /* old= w, write:xxx, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= w, write:xxx, read:add, close: 0 */
+ { 0, 255 },
+ /* old= w, write:xxx, read:add, close:add */
+ { 0, 255 },
+ /* old= w, write:xxx, read:add, close:del */
+ { 0, 255 },
+ /* old= w, write:xxx, read:add, close:xxx */
+ { 0, 255 },
+ /* old= w, write:xxx, read:del, close: 0 */
+ { 0, 255 },
+ /* old= w, write:xxx, read:del, close:add */
+ { 0, 255 },
+ /* old= w, write:xxx, read:del, close:del */
+ { 0, 255 },
+ /* old= w, write:xxx, read:del, close:xxx */
+ { 0, 255 },
+ /* old= w, write:xxx, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= w, write:xxx, read:xxx, close:add */
+ { 0, 255 },
+ /* old= w, write:xxx, read:xxx, close:del */
+ { 0, 255 },
+ /* old= w, write:xxx, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= rw, write: 0, read: 0, close: 0 */
+ { 0, 0 },
+ /* old= rw, write: 0, read: 0, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= rw, write: 0, read: 0, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= rw, write: 0, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= rw, write: 0, read:add, close: 0 */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= rw, write: 0, read:add, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= rw, write: 0, read:add, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= rw, write: 0, read:add, close:xxx */
+ { 0, 255 },
+ /* old= rw, write: 0, read:del, close: 0 */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= rw, write: 0, read:del, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= rw, write: 0, read:del, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= rw, write: 0, read:del, close:xxx */
+ { 0, 255 },
+ /* old= rw, write: 0, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= rw, write: 0, read:xxx, close:add */
+ { 0, 255 },
+ /* old= rw, write: 0, read:xxx, close:del */
+ { 0, 255 },
+ /* old= rw, write: 0, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= rw, write:add, read: 0, close: 0 */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= rw, write:add, read: 0, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= rw, write:add, read: 0, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= rw, write:add, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= rw, write:add, read:add, close: 0 */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= rw, write:add, read:add, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= rw, write:add, read:add, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= rw, write:add, read:add, close:xxx */
+ { 0, 255 },
+ /* old= rw, write:add, read:del, close: 0 */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= rw, write:add, read:del, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= rw, write:add, read:del, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= rw, write:add, read:del, close:xxx */
+ { 0, 255 },
+ /* old= rw, write:add, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= rw, write:add, read:xxx, close:add */
+ { 0, 255 },
+ /* old= rw, write:add, read:xxx, close:del */
+ { 0, 255 },
+ /* old= rw, write:add, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= rw, write:del, read: 0, close: 0 */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= rw, write:del, read: 0, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= rw, write:del, read: 0, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= rw, write:del, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= rw, write:del, read:add, close: 0 */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= rw, write:del, read:add, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= rw, write:del, read:add, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= rw, write:del, read:add, close:xxx */
+ { 0, 255 },
+ /* old= rw, write:del, read:del, close: 0 */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_DEL },
+ /* old= rw, write:del, read:del, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= rw, write:del, read:del, close:del */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= rw, write:del, read:del, close:xxx */
+ { 0, 255 },
+ /* old= rw, write:del, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= rw, write:del, read:xxx, close:add */
+ { 0, 255 },
+ /* old= rw, write:del, read:xxx, close:del */
+ { 0, 255 },
+ /* old= rw, write:del, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= rw, write:xxx, read: 0, close: 0 */
+ { 0, 255 },
+ /* old= rw, write:xxx, read: 0, close:add */
+ { 0, 255 },
+ /* old= rw, write:xxx, read: 0, close:del */
+ { 0, 255 },
+ /* old= rw, write:xxx, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= rw, write:xxx, read:add, close: 0 */
+ { 0, 255 },
+ /* old= rw, write:xxx, read:add, close:add */
+ { 0, 255 },
+ /* old= rw, write:xxx, read:add, close:del */
+ { 0, 255 },
+ /* old= rw, write:xxx, read:add, close:xxx */
+ { 0, 255 },
+ /* old= rw, write:xxx, read:del, close: 0 */
+ { 0, 255 },
+ /* old= rw, write:xxx, read:del, close:add */
+ { 0, 255 },
+ /* old= rw, write:xxx, read:del, close:del */
+ { 0, 255 },
+ /* old= rw, write:xxx, read:del, close:xxx */
+ { 0, 255 },
+ /* old= rw, write:xxx, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= rw, write:xxx, read:xxx, close:add */
+ { 0, 255 },
+ /* old= rw, write:xxx, read:xxx, close:del */
+ { 0, 255 },
+ /* old= rw, write:xxx, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= c, write: 0, read: 0, close: 0 */
+ { 0, 0 },
+ /* old= c, write: 0, read: 0, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write: 0, read: 0, close:del */
+ { EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= c, write: 0, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= c, write: 0, read:add, close: 0 */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write: 0, read:add, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write: 0, read:add, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= c, write: 0, read:add, close:xxx */
+ { 0, 255 },
+ /* old= c, write: 0, read:del, close: 0 */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write: 0, read:del, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write: 0, read:del, close:del */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= c, write: 0, read:del, close:xxx */
+ { 0, 255 },
+ /* old= c, write: 0, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= c, write: 0, read:xxx, close:add */
+ { 0, 255 },
+ /* old= c, write: 0, read:xxx, close:del */
+ { 0, 255 },
+ /* old= c, write: 0, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= c, write:add, read: 0, close: 0 */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write:add, read: 0, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write:add, read: 0, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= c, write:add, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= c, write:add, read:add, close: 0 */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write:add, read:add, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write:add, read:add, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= c, write:add, read:add, close:xxx */
+ { 0, 255 },
+ /* old= c, write:add, read:del, close: 0 */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write:add, read:del, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write:add, read:del, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= c, write:add, read:del, close:xxx */
+ { 0, 255 },
+ /* old= c, write:add, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= c, write:add, read:xxx, close:add */
+ { 0, 255 },
+ /* old= c, write:add, read:xxx, close:del */
+ { 0, 255 },
+ /* old= c, write:add, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= c, write:del, read: 0, close: 0 */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write:del, read: 0, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write:del, read: 0, close:del */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= c, write:del, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= c, write:del, read:add, close: 0 */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write:del, read:add, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write:del, read:add, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= c, write:del, read:add, close:xxx */
+ { 0, 255 },
+ /* old= c, write:del, read:del, close: 0 */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write:del, read:del, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write:del, read:del, close:del */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= c, write:del, read:del, close:xxx */
+ { 0, 255 },
+ /* old= c, write:del, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= c, write:del, read:xxx, close:add */
+ { 0, 255 },
+ /* old= c, write:del, read:xxx, close:del */
+ { 0, 255 },
+ /* old= c, write:del, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= c, write:xxx, read: 0, close: 0 */
+ { 0, 255 },
+ /* old= c, write:xxx, read: 0, close:add */
+ { 0, 255 },
+ /* old= c, write:xxx, read: 0, close:del */
+ { 0, 255 },
+ /* old= c, write:xxx, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= c, write:xxx, read:add, close: 0 */
+ { 0, 255 },
+ /* old= c, write:xxx, read:add, close:add */
+ { 0, 255 },
+ /* old= c, write:xxx, read:add, close:del */
+ { 0, 255 },
+ /* old= c, write:xxx, read:add, close:xxx */
+ { 0, 255 },
+ /* old= c, write:xxx, read:del, close: 0 */
+ { 0, 255 },
+ /* old= c, write:xxx, read:del, close:add */
+ { 0, 255 },
+ /* old= c, write:xxx, read:del, close:del */
+ { 0, 255 },
+ /* old= c, write:xxx, read:del, close:xxx */
+ { 0, 255 },
+ /* old= c, write:xxx, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= c, write:xxx, read:xxx, close:add */
+ { 0, 255 },
+ /* old= c, write:xxx, read:xxx, close:del */
+ { 0, 255 },
+ /* old= c, write:xxx, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= cr, write: 0, read: 0, close: 0 */
+ { 0, 0 },
+ /* old= cr, write: 0, read: 0, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write: 0, read: 0, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= cr, write: 0, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= cr, write: 0, read:add, close: 0 */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write: 0, read:add, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write: 0, read:add, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= cr, write: 0, read:add, close:xxx */
+ { 0, 255 },
+ /* old= cr, write: 0, read:del, close: 0 */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write: 0, read:del, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write: 0, read:del, close:del */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= cr, write: 0, read:del, close:xxx */
+ { 0, 255 },
+ /* old= cr, write: 0, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= cr, write: 0, read:xxx, close:add */
+ { 0, 255 },
+ /* old= cr, write: 0, read:xxx, close:del */
+ { 0, 255 },
+ /* old= cr, write: 0, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= cr, write:add, read: 0, close: 0 */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write:add, read: 0, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write:add, read: 0, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= cr, write:add, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= cr, write:add, read:add, close: 0 */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write:add, read:add, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write:add, read:add, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= cr, write:add, read:add, close:xxx */
+ { 0, 255 },
+ /* old= cr, write:add, read:del, close: 0 */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write:add, read:del, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write:add, read:del, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= cr, write:add, read:del, close:xxx */
+ { 0, 255 },
+ /* old= cr, write:add, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= cr, write:add, read:xxx, close:add */
+ { 0, 255 },
+ /* old= cr, write:add, read:xxx, close:del */
+ { 0, 255 },
+ /* old= cr, write:add, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= cr, write:del, read: 0, close: 0 */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write:del, read: 0, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write:del, read: 0, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= cr, write:del, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= cr, write:del, read:add, close: 0 */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write:del, read:add, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write:del, read:add, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= cr, write:del, read:add, close:xxx */
+ { 0, 255 },
+ /* old= cr, write:del, read:del, close: 0 */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write:del, read:del, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write:del, read:del, close:del */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= cr, write:del, read:del, close:xxx */
+ { 0, 255 },
+ /* old= cr, write:del, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= cr, write:del, read:xxx, close:add */
+ { 0, 255 },
+ /* old= cr, write:del, read:xxx, close:del */
+ { 0, 255 },
+ /* old= cr, write:del, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= cr, write:xxx, read: 0, close: 0 */
+ { 0, 255 },
+ /* old= cr, write:xxx, read: 0, close:add */
+ { 0, 255 },
+ /* old= cr, write:xxx, read: 0, close:del */
+ { 0, 255 },
+ /* old= cr, write:xxx, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= cr, write:xxx, read:add, close: 0 */
+ { 0, 255 },
+ /* old= cr, write:xxx, read:add, close:add */
+ { 0, 255 },
+ /* old= cr, write:xxx, read:add, close:del */
+ { 0, 255 },
+ /* old= cr, write:xxx, read:add, close:xxx */
+ { 0, 255 },
+ /* old= cr, write:xxx, read:del, close: 0 */
+ { 0, 255 },
+ /* old= cr, write:xxx, read:del, close:add */
+ { 0, 255 },
+ /* old= cr, write:xxx, read:del, close:del */
+ { 0, 255 },
+ /* old= cr, write:xxx, read:del, close:xxx */
+ { 0, 255 },
+ /* old= cr, write:xxx, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= cr, write:xxx, read:xxx, close:add */
+ { 0, 255 },
+ /* old= cr, write:xxx, read:xxx, close:del */
+ { 0, 255 },
+ /* old= cr, write:xxx, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= cw, write: 0, read: 0, close: 0 */
+ { 0, 0 },
+ /* old= cw, write: 0, read: 0, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write: 0, read: 0, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= cw, write: 0, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= cw, write: 0, read:add, close: 0 */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write: 0, read:add, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write: 0, read:add, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= cw, write: 0, read:add, close:xxx */
+ { 0, 255 },
+ /* old= cw, write: 0, read:del, close: 0 */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write: 0, read:del, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write: 0, read:del, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= cw, write: 0, read:del, close:xxx */
+ { 0, 255 },
+ /* old= cw, write: 0, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= cw, write: 0, read:xxx, close:add */
+ { 0, 255 },
+ /* old= cw, write: 0, read:xxx, close:del */
+ { 0, 255 },
+ /* old= cw, write: 0, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= cw, write:add, read: 0, close: 0 */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write:add, read: 0, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write:add, read: 0, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= cw, write:add, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= cw, write:add, read:add, close: 0 */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write:add, read:add, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write:add, read:add, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= cw, write:add, read:add, close:xxx */
+ { 0, 255 },
+ /* old= cw, write:add, read:del, close: 0 */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write:add, read:del, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write:add, read:del, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= cw, write:add, read:del, close:xxx */
+ { 0, 255 },
+ /* old= cw, write:add, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= cw, write:add, read:xxx, close:add */
+ { 0, 255 },
+ /* old= cw, write:add, read:xxx, close:del */
+ { 0, 255 },
+ /* old= cw, write:add, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= cw, write:del, read: 0, close: 0 */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write:del, read: 0, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write:del, read: 0, close:del */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= cw, write:del, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= cw, write:del, read:add, close: 0 */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write:del, read:add, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write:del, read:add, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= cw, write:del, read:add, close:xxx */
+ { 0, 255 },
+ /* old= cw, write:del, read:del, close: 0 */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write:del, read:del, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write:del, read:del, close:del */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= cw, write:del, read:del, close:xxx */
+ { 0, 255 },
+ /* old= cw, write:del, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= cw, write:del, read:xxx, close:add */
+ { 0, 255 },
+ /* old= cw, write:del, read:xxx, close:del */
+ { 0, 255 },
+ /* old= cw, write:del, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= cw, write:xxx, read: 0, close: 0 */
+ { 0, 255 },
+ /* old= cw, write:xxx, read: 0, close:add */
+ { 0, 255 },
+ /* old= cw, write:xxx, read: 0, close:del */
+ { 0, 255 },
+ /* old= cw, write:xxx, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= cw, write:xxx, read:add, close: 0 */
+ { 0, 255 },
+ /* old= cw, write:xxx, read:add, close:add */
+ { 0, 255 },
+ /* old= cw, write:xxx, read:add, close:del */
+ { 0, 255 },
+ /* old= cw, write:xxx, read:add, close:xxx */
+ { 0, 255 },
+ /* old= cw, write:xxx, read:del, close: 0 */
+ { 0, 255 },
+ /* old= cw, write:xxx, read:del, close:add */
+ { 0, 255 },
+ /* old= cw, write:xxx, read:del, close:del */
+ { 0, 255 },
+ /* old= cw, write:xxx, read:del, close:xxx */
+ { 0, 255 },
+ /* old= cw, write:xxx, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= cw, write:xxx, read:xxx, close:add */
+ { 0, 255 },
+ /* old= cw, write:xxx, read:xxx, close:del */
+ { 0, 255 },
+ /* old= cw, write:xxx, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old=crw, write: 0, read: 0, close: 0 */
+ { 0, 0 },
+ /* old=crw, write: 0, read: 0, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write: 0, read: 0, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old=crw, write: 0, read: 0, close:xxx */
+ { 0, 255 },
+ /* old=crw, write: 0, read:add, close: 0 */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write: 0, read:add, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write: 0, read:add, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old=crw, write: 0, read:add, close:xxx */
+ { 0, 255 },
+ /* old=crw, write: 0, read:del, close: 0 */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write: 0, read:del, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write: 0, read:del, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old=crw, write: 0, read:del, close:xxx */
+ { 0, 255 },
+ /* old=crw, write: 0, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old=crw, write: 0, read:xxx, close:add */
+ { 0, 255 },
+ /* old=crw, write: 0, read:xxx, close:del */
+ { 0, 255 },
+ /* old=crw, write: 0, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old=crw, write:add, read: 0, close: 0 */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write:add, read: 0, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write:add, read: 0, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old=crw, write:add, read: 0, close:xxx */
+ { 0, 255 },
+ /* old=crw, write:add, read:add, close: 0 */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write:add, read:add, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write:add, read:add, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old=crw, write:add, read:add, close:xxx */
+ { 0, 255 },
+ /* old=crw, write:add, read:del, close: 0 */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write:add, read:del, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write:add, read:del, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old=crw, write:add, read:del, close:xxx */
+ { 0, 255 },
+ /* old=crw, write:add, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old=crw, write:add, read:xxx, close:add */
+ { 0, 255 },
+ /* old=crw, write:add, read:xxx, close:del */
+ { 0, 255 },
+ /* old=crw, write:add, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old=crw, write:del, read: 0, close: 0 */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write:del, read: 0, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write:del, read: 0, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old=crw, write:del, read: 0, close:xxx */
+ { 0, 255 },
+ /* old=crw, write:del, read:add, close: 0 */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write:del, read:add, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write:del, read:add, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old=crw, write:del, read:add, close:xxx */
+ { 0, 255 },
+ /* old=crw, write:del, read:del, close: 0 */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write:del, read:del, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write:del, read:del, close:del */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old=crw, write:del, read:del, close:xxx */
+ { 0, 255 },
+ /* old=crw, write:del, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old=crw, write:del, read:xxx, close:add */
+ { 0, 255 },
+ /* old=crw, write:del, read:xxx, close:del */
+ { 0, 255 },
+ /* old=crw, write:del, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old=crw, write:xxx, read: 0, close: 0 */
+ { 0, 255 },
+ /* old=crw, write:xxx, read: 0, close:add */
+ { 0, 255 },
+ /* old=crw, write:xxx, read: 0, close:del */
+ { 0, 255 },
+ /* old=crw, write:xxx, read: 0, close:xxx */
+ { 0, 255 },
+ /* old=crw, write:xxx, read:add, close: 0 */
+ { 0, 255 },
+ /* old=crw, write:xxx, read:add, close:add */
+ { 0, 255 },
+ /* old=crw, write:xxx, read:add, close:del */
+ { 0, 255 },
+ /* old=crw, write:xxx, read:add, close:xxx */
+ { 0, 255 },
+ /* old=crw, write:xxx, read:del, close: 0 */
+ { 0, 255 },
+ /* old=crw, write:xxx, read:del, close:add */
+ { 0, 255 },
+ /* old=crw, write:xxx, read:del, close:del */
+ { 0, 255 },
+ /* old=crw, write:xxx, read:del, close:xxx */
+ { 0, 255 },
+ /* old=crw, write:xxx, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old=crw, write:xxx, read:xxx, close:add */
+ { 0, 255 },
+ /* old=crw, write:xxx, read:xxx, close:del */
+ { 0, 255 },
+ /* old=crw, write:xxx, read:xxx, close:xxx */
+ { 0, 255 },
};
static int
@@ -424,13 +1399,14 @@ epoll_apply_one_change(struct event_base *base,
epev.data.fd = ch->fd;
epev.events = events;
if (epoll_ctl(epollop->epfd, op, ch->fd, &epev) == 0) {
- event_debug(("Epoll %s(%d) on fd %d okay. [old events were %d; read change was %d; write change was %d]",
+ event_debug(("Epoll %s(%d) on fd %d okay. [old events were %d; read change was %d; write change was %d; close change was %d]",
epoll_op_to_string(op),
(int)epev.events,
(int)ch->fd,
ch->old_events,
ch->read_change,
- ch->write_change));
+ ch->write_change,
+ ch->close_change));
return 0;
}
@@ -490,7 +1466,7 @@ epoll_apply_one_change(struct event_base *base,
break;
}
- event_warn("Epoll %s(%d) on fd %d failed. Old events were %d; read change was %d (%s); write change was %d (%s)",
+ event_warn("Epoll %s(%d) on fd %d failed. Old events were %d; read change was %d (%s); write change was %d (%s); close change was %d (%s)",
epoll_op_to_string(op),
(int)epev.events,
ch->fd,
@@ -498,7 +1474,9 @@ epoll_apply_one_change(struct event_base *base,
ch->read_change,
change_to_string(ch->read_change),
ch->write_change,
- change_to_string(ch->write_change));
+ change_to_string(ch->write_change),
+ ch->close_change,
+ change_to_string(ch->close_change));
return -1;
}
@@ -529,13 +1507,16 @@ epoll_nochangelist_add(struct event_base *base, evutil_socket_t fd,
struct event_change ch;
ch.fd = fd;
ch.old_events = old;
- ch.read_change = ch.write_change = 0;
+ ch.read_change = ch.write_change = ch.close_change = 0;
if (events & EV_WRITE)
ch.write_change = EV_CHANGE_ADD |
(events & EV_ET);
if (events & EV_READ)
ch.read_change = EV_CHANGE_ADD |
(events & EV_ET);
+ if (events & EV_CLOSED)
+ ch.close_change = EV_CHANGE_ADD |
+ (events & EV_ET);
return epoll_apply_one_change(base, base->evbase, &ch);
}
@@ -547,11 +1528,13 @@ epoll_nochangelist_del(struct event_base *base, evutil_socket_t fd,
struct event_change ch;
ch.fd = fd;
ch.old_events = old;
- ch.read_change = ch.write_change = 0;
+ ch.read_change = ch.write_change = ch.close_change = 0;
if (events & EV_WRITE)
ch.write_change = EV_CHANGE_DEL;
if (events & EV_READ)
ch.read_change = EV_CHANGE_DEL;
+ if (events & EV_CLOSED)
+ ch.close_change = EV_CHANGE_DEL;
return epoll_apply_one_change(base, base->evbase, &ch);
}
@@ -636,6 +1619,8 @@ epoll_dispatch(struct event_base *base, struct timeval *tv)
ev |= EV_READ;
if (what & EPOLLOUT)
ev |= EV_WRITE;
+ if (what & EPOLLRDHUP)
+ ev |= EV_CLOSED;
}
if (!ev)
diff --git a/event.c b/event.c
index eea2c0fc..c946cbf9 100644
--- a/event.c
+++ b/event.c
@@ -1526,10 +1526,11 @@ event_process_active_single_queue(struct event_base *base,
else
event_del_nolock_(ev, EVENT_DEL_NOBLOCK);
event_debug((
- "event_process_active: event: %p, %s%scall %p",
+ "event_process_active: event: %p, %s%s%scall %p",
ev,
ev->ev_res & EV_READ ? "EV_READ " : " ",
ev->ev_res & EV_WRITE ? "EV_WRITE " : " ",
+ ev->ev_res & EV_CLOSED ? "EV_CLOSED " : " ",
ev->ev_callback));
} else {
event_queue_remove_active(base, evcb);
@@ -1931,7 +1932,7 @@ event_base_once(struct event_base *base, evutil_socket_t fd, short events,
eonce->cb = callback;
eonce->arg = arg;
- if ((events & (EV_TIMEOUT|EV_SIGNAL|EV_READ|EV_WRITE)) == EV_TIMEOUT) {
+ if ((events & (EV_TIMEOUT|EV_SIGNAL|EV_READ|EV_WRITE|EV_CLOSED)) == EV_TIMEOUT) {
evtimer_assign(&eonce->ev, base, event_once_cb, eonce);
if (tv == NULL || ! evutil_timerisset(tv)) {
@@ -1941,8 +1942,8 @@ event_base_once(struct event_base *base, evutil_socket_t fd, short events,
* it fast (and order-preserving). */
activate = 1;
}
- } else if (events & (EV_READ|EV_WRITE)) {
- events &= EV_READ|EV_WRITE;
+ } else if (events & (EV_READ|EV_WRITE|EV_CLOSED)) {
+ events &= EV_READ|EV_WRITE|EV_CLOSED;
event_assign(&eonce->ev, base, fd, events, event_once_cb, eonce);
} else {
@@ -1992,9 +1993,9 @@ event_assign(struct event *ev, struct event_base *base, evutil_socket_t fd, shor
ev->ev_pncalls = NULL;
if (events & EV_SIGNAL) {
- if ((events & (EV_READ|EV_WRITE)) != 0) {
+ if ((events & (EV_READ|EV_WRITE|EV_CLOSED)) != 0) {
event_warnx("%s: EV_SIGNAL is not compatible with "
- "EV_READ or EV_WRITE", __func__);
+ "EV_READ, EV_WRITE or EV_CLOSED", __func__);
return -1;
}
ev->ev_closure = EV_CLOSURE_EVENT_SIGNAL;
@@ -2244,13 +2245,13 @@ event_pending(const struct event *ev, short event, struct timeval *tv)
event_debug_assert_is_setup_(ev);
if (ev->ev_flags & EVLIST_INSERTED)
- flags |= (ev->ev_events & (EV_READ|EV_WRITE|EV_SIGNAL));
+ flags |= (ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED|EV_SIGNAL));
if (ev->ev_flags & (EVLIST_ACTIVE|EVLIST_ACTIVE_LATER))
flags |= ev->ev_res;
if (ev->ev_flags & EVLIST_TIMEOUT)
flags |= EV_TIMEOUT;
- event &= (EV_TIMEOUT|EV_READ|EV_WRITE|EV_SIGNAL);
+ event &= (EV_TIMEOUT|EV_READ|EV_WRITE|EV_CLOSED|EV_SIGNAL);
/* See if there is a timeout that we should report */
if (tv != NULL && (flags & event & EV_TIMEOUT)) {
@@ -2464,11 +2465,12 @@ event_add_nolock_(struct event *ev, const struct timeval *tv,
event_debug_assert_is_setup_(ev);
event_debug((
- "event_add: event: %p (fd "EV_SOCK_FMT"), %s%s%scall %p",
+ "event_add: event: %p (fd "EV_SOCK_FMT"), %s%s%s%scall %p",
ev,
EV_SOCK_ARG(ev->ev_fd),
ev->ev_events & EV_READ ? "EV_READ " : " ",
ev->ev_events & EV_WRITE ? "EV_WRITE " : " ",
+ ev->ev_events & EV_CLOSED ? "EV_CLOSED " : " ",
tv ? "EV_TIMEOUT " : " ",
ev->ev_callback));
@@ -2502,9 +2504,9 @@ event_add_nolock_(struct event *ev, const struct timeval *tv,
}
#endif
- if ((ev->ev_events & (EV_READ|EV_WRITE|EV_SIGNAL)) &&
+ if ((ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED|EV_SIGNAL)) &&
!(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE|EVLIST_ACTIVE_LATER))) {
- if (ev->ev_events & (EV_READ|EV_WRITE))
+ if (ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED))
res = evmap_io_add_(base, ev->ev_fd, ev);
else if (ev->ev_events & EV_SIGNAL)
res = evmap_signal_add_(base, (int)ev->ev_fd, ev);
@@ -2731,7 +2733,7 @@ event_del_nolock_(struct event *ev, int blocking)
if (ev->ev_flags & EVLIST_INSERTED) {
event_queue_remove_inserted(base, ev);
- if (ev->ev_events & (EV_READ|EV_WRITE))
+ if (ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED))
res = evmap_io_del_(base, ev->ev_fd, ev);
else
res = evmap_signal_del_(base, (int)ev->ev_fd, ev);
@@ -3602,10 +3604,11 @@ dump_inserted_event_fn(const struct event_base *base, const struct event *e, voi
if (! (e->ev_flags & (EVLIST_INSERTED|EVLIST_TIMEOUT)))
return 0;
- fprintf(output, " %p [%s "EV_SOCK_FMT"]%s%s%s%s%s",
+ fprintf(output, " %p [%s "EV_SOCK_FMT"]%s%s%s%s%s%s",
(void*)e, gloss, EV_SOCK_ARG(e->ev_fd),
(e->ev_events&EV_READ)?" Read":"",
(e->ev_events&EV_WRITE)?" Write":"",
+ (e->ev_events&EV_CLOSED)?" EOF":"",
(e->ev_events&EV_SIGNAL)?" Signal":"",
(e->ev_events&EV_PERSIST)?" Persist":"",
(e->ev_flags&EVLIST_INTERNAL)?" Internal":"");
@@ -3634,10 +3637,11 @@ dump_active_event_fn(const struct event_base *base, const struct event *e, void
if (! (e->ev_flags & (EVLIST_ACTIVE|EVLIST_ACTIVE_LATER)))
return 0;
- fprintf(output, " %p [%s "EV_SOCK_FMT", priority=%d]%s%s%s%s active%s%s\n",
+ fprintf(output, " %p [%s "EV_SOCK_FMT", priority=%d]%s%s%s%s%s active%s%s\n",
(void*)e, gloss, EV_SOCK_ARG(e->ev_fd), e->ev_pri,
(e->ev_res&EV_READ)?" Read":"",
(e->ev_res&EV_WRITE)?" Write":"",
+ (e->ev_res&EV_CLOSED)?" EOF":"",
(e->ev_res&EV_SIGNAL)?" Signal":"",
(e->ev_res&EV_TIMEOUT)?" Timeout":"",
(e->ev_flags&EVLIST_INTERNAL)?" [Internal]":"",
@@ -3677,7 +3681,7 @@ void
event_base_active_by_fd(struct event_base *base, evutil_socket_t fd, short events)
{
EVBASE_ACQUIRE_LOCK(base, th_base_lock);
- evmap_io_active_(base, fd, events & (EV_READ|EV_WRITE));
+ evmap_io_active_(base, fd, events & (EV_READ|EV_WRITE|EV_CLOSED));
EVBASE_RELEASE_LOCK(base, th_base_lock);
}
diff --git a/evmap.c b/evmap.c
index 26044b41..3f76dd0a 100644
--- a/evmap.c
+++ b/evmap.c
@@ -59,6 +59,7 @@ struct evmap_io {
struct event_dlist events;
ev_uint16_t nread;
ev_uint16_t nwrite;
+ ev_uint16_t nclose;
};
/* An entry for an evmap_signal list: notes all the events that want to know
@@ -255,6 +256,7 @@ evmap_io_init(struct evmap_io *entry)
LIST_INIT(&entry->events);
entry->nread = 0;
entry->nwrite = 0;
+ entry->nclose = 0;
}
@@ -266,7 +268,7 @@ evmap_io_add_(struct event_base *base, evutil_socket_t fd, struct event *ev)
const struct eventop *evsel = base->evsel;
struct event_io_map *io = &base->io;
struct evmap_io *ctx = NULL;
- int nread, nwrite, retval = 0;
+ int nread, nwrite, nclose, retval = 0;
short res = 0, old = 0;
struct event *old_ev;
@@ -286,11 +288,14 @@ evmap_io_add_(struct event_base *base, evutil_socket_t fd, struct event *ev)
nread = ctx->nread;
nwrite = ctx->nwrite;
+ nclose = ctx->nclose;
if (nread)
old |= EV_READ;
if (nwrite)
old |= EV_WRITE;
+ if (nclose)
+ old |= EV_CLOSED;
if (ev->ev_events & EV_READ) {
if (++nread == 1)
@@ -300,7 +305,11 @@ evmap_io_add_(struct event_base *base, evutil_socket_t fd, struct event *ev)
if (++nwrite == 1)
res |= EV_WRITE;
}
- if (EVUTIL_UNLIKELY(nread > 0xffff || nwrite > 0xffff)) {
+ if (ev->ev_events & EV_CLOSED) {
+ if (++nclose == 1)
+ res |= EV_CLOSED;
+ }
+ if (EVUTIL_UNLIKELY(nread > 0xffff || nwrite > 0xffff || nclose > 0xffff)) {
event_warnx("Too many events reading or writing on fd %d",
(int)fd);
return -1;
@@ -326,6 +335,7 @@ evmap_io_add_(struct event_base *base, evutil_socket_t fd, struct event *ev)
ctx->nread = (ev_uint16_t) nread;
ctx->nwrite = (ev_uint16_t) nwrite;
+ ctx->nclose = (ev_uint16_t) nclose;
LIST_INSERT_HEAD(&ctx->events, ev, ev_io_next);
return (retval);
@@ -339,7 +349,7 @@ evmap_io_del_(struct event_base *base, evutil_socket_t fd, struct event *ev)
const struct eventop *evsel = base->evsel;
struct event_io_map *io = &base->io;
struct evmap_io *ctx;
- int nread, nwrite, retval = 0;
+ int nread, nwrite, nclose, retval = 0;
short res = 0, old = 0;
if (fd < 0)
@@ -356,11 +366,14 @@ evmap_io_del_(struct event_base *base, evutil_socket_t fd, struct event *ev)
nread = ctx->nread;
nwrite = ctx->nwrite;
+ nclose = ctx->nclose;
if (nread)
old |= EV_READ;
if (nwrite)
old |= EV_WRITE;
+ if (nclose)
+ old |= EV_CLOSED;
if (ev->ev_events & EV_READ) {
if (--nread == 0)
@@ -372,6 +385,11 @@ evmap_io_del_(struct event_base *base, evutil_socket_t fd, struct event *ev)
res |= EV_WRITE;
EVUTIL_ASSERT(nwrite >= 0);
}
+ if (ev->ev_events & EV_CLOSED) {
+ if (--nclose == 0)
+ res |= EV_CLOSED;
+ EVUTIL_ASSERT(nclose >= 0);
+ }
if (res) {
void *extra = ((char*)ctx) + sizeof(struct evmap_io);
@@ -384,6 +402,7 @@ evmap_io_del_(struct event_base *base, evutil_socket_t fd, struct event *ev)
ctx->nread = nread;
ctx->nwrite = nwrite;
+ ctx->nclose = nclose;
LIST_REMOVE(ev, ev_io_next);
return (retval);
@@ -589,6 +608,8 @@ evmap_io_reinit_iter_fn(struct event_base *base, evutil_socket_t fd,
events |= EV_READ;
if (ctx->nwrite)
events |= EV_WRITE;
+ if (ctx->nclose)
+ events |= EV_CLOSED;
if (evsel->fdinfo_len)
memset(extra, 0, evsel->fdinfo_len);
if (events &&
@@ -856,6 +877,10 @@ event_changelist_add_(struct event_base *base, evutil_socket_t fd, short old, sh
change->write_change = EV_CHANGE_ADD |
(events & (EV_ET|EV_PERSIST|EV_SIGNAL));
}
+ if (events & EV_CLOSED) {
+ change->close_change = EV_CHANGE_ADD |
+ (events & (EV_ET|EV_PERSIST|EV_SIGNAL));
+ }
event_changelist_check(base);
return (0);
@@ -902,6 +927,12 @@ event_changelist_del_(struct event_base *base, evutil_socket_t fd, short old, sh
else
change->write_change = EV_CHANGE_DEL;
}
+ if (events & EV_CLOSED) {
+ if (!(change->old_events & EV_CLOSED))
+ change->close_change = 0;
+ else
+ change->close_change = EV_CHANGE_DEL;
+ }
event_changelist_check(base);
return (0);
@@ -915,7 +946,7 @@ evmap_io_check_integrity_fn(struct event_base *base, evutil_socket_t fd,
struct evmap_io *io_info, void *arg)
{
struct event *ev;
- int n_read = 0, n_write = 0;
+ int n_read = 0, n_write = 0, n_close = 0;
/* First, make sure the list itself isn't corrupt. Otherwise,
* running LIST_FOREACH could be an exciting adventure. */
@@ -925,15 +956,18 @@ evmap_io_check_integrity_fn(struct event_base *base, evutil_socket_t fd,
EVUTIL_ASSERT(ev->ev_flags & EVLIST_INSERTED);
EVUTIL_ASSERT(ev->ev_fd == fd);
EVUTIL_ASSERT(!(ev->ev_events & EV_SIGNAL));
- EVUTIL_ASSERT((ev->ev_events & (EV_READ|EV_WRITE)));
+ EVUTIL_ASSERT((ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED)));
if (ev->ev_events & EV_READ)
++n_read;
if (ev->ev_events & EV_WRITE)
++n_write;
+ if (ev->ev_events & EV_CLOSED)
+ ++n_close;
}
EVUTIL_ASSERT(n_read == io_info->nread);
EVUTIL_ASSERT(n_write == io_info->nwrite);
+ EVUTIL_ASSERT(n_close == io_info->nclose);
return 0;
}
@@ -952,7 +986,7 @@ evmap_signal_check_integrity_fn(struct event_base *base,
EVUTIL_ASSERT(ev->ev_flags & EVLIST_INSERTED);
EVUTIL_ASSERT(ev->ev_fd == signum);
EVUTIL_ASSERT((ev->ev_events & EV_SIGNAL));
- EVUTIL_ASSERT(!(ev->ev_events & (EV_READ|EV_WRITE)));
+ EVUTIL_ASSERT(!(ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED)));
}
return 0;
}
diff --git a/include/event2/event.h b/include/event2/event.h
index 0c94e146..7632c0ee 100644
--- a/include/event2/event.h
+++ b/include/event2/event.h
@@ -488,7 +488,10 @@ enum event_method_feature {
EV_FEATURE_O1 = 0x02,
/** Require an event method that allows file descriptors as well as
* sockets. */
- EV_FEATURE_FDS = 0x04
+ EV_FEATURE_FDS = 0x04,
+ /** Require an event method that detects premature connection close by
+ * clients without the necessity of reading all the pending data. */
+ EV_FEATURE_EARLY_CLOSE = 0x08
};
/**
@@ -904,6 +907,11 @@ int event_base_got_break(struct event_base *);
* BECOMES STABLE.
**/
#define EV_FINALIZE 0x40
+/**
+ * Detects premature connection close by clients without the necessity of
+ * reading all the pending data, if supported by the backend.
+ **/
+#define EV_CLOSED 0x80
/**@}*/
/**
diff --git a/make_epoll_table.py b/make_epoll_table.py
index 37d6df1e..1b15a91a 100755
--- a/make_epoll_table.py
+++ b/make_epoll_table.py
@@ -1,15 +1,17 @@
#!/usr/bin/python2
-def get(old,wc,rc):
- if ('xxx' in (rc, wc)):
- return "0",-1
+def get(old,wc,rc,cc):
+ if ('xxx' in (rc, wc, cc)):
+ return "0",255
- if ('add' in (rc, wc)):
+ if ('add' in (rc, wc, cc)):
events = []
if rc == 'add' or (rc != 'del' and 'r' in old):
events.append("EPOLLIN")
if wc == 'add' or (wc != 'del' and 'w' in old):
events.append("EPOLLOUT")
+ if cc == 'add' or (cc != 'del' and 'c' in old):
+ events.append("EPOLLRDHUP")
if old == "0":
op = "EPOLL_CTL_ADD"
@@ -17,41 +19,45 @@ def get(old,wc,rc):
op = "EPOLL_CTL_MOD"
return "|".join(events), op
- if ('del' in (rc, wc)):
+ if ('del' in (rc, wc, cc)):
+ delevents = []
+ modevents = []
op = "EPOLL_CTL_DEL"
- if rc == 'del':
- if wc == 'del':
- events = "EPOLLIN|EPOLLOUT"
- elif 'w' in old:
- events = "EPOLLOUT"
- op = "EPOLL_CTL_MOD"
- else:
- events = "EPOLLIN"
+
+ if 'r' in old:
+ modevents.append("EPOLLIN")
+ if 'w' in old:
+ modevents.append("EPOLLOUT")
+ if 'c' in old:
+ modevents.append("EPOLLRDHUP")
+
+ for item, event in [(rc,"EPOLLIN"),
+ (wc,"EPOLLOUT"),
+ (cc,"EPOLLRDHUP")]:
+ if item == 'del':
+ delevents.append(event)
+ if event in modevents:
+ modevents.remove(event)
+
+ if modevents:
+ return "|".join(modevents), "EPOLL_CTL_MOD"
else:
- assert wc == 'del'
- if 'r' in old:
- events = "EPOLLIN"
- op = "EPOLL_CTL_MOD"
- else:
- events = "EPOLLOUT"
- return events, op
+ return "|".join(delevents), "EPOLL_CTL_DEL"
return 0, 0
-def fmt(op, ev, old, wc, rc):
+def fmt(op, ev, old, wc, rc, cc):
entry = "{ %s, %s },"%(op, ev)
- assert len(entry)<=36
- sp = " "*(36-len(entry))
- print "\t%s%s/* old=%2s, write:%3s, read:%3s */" % (
- entry, sp, old, wc, rc)
-
+ print "\t/* old=%3s, write:%3s, read:%3s, close:%3s */\n\t%s" % (
+ old, wc, rc, cc, entry)
+ return len(entry)
-for old in ('0','r','w','rw'):
+for old in ('0','r','w','rw','c','cr','cw','crw'):
for wc in ('0', 'add', 'del', 'xxx'):
for rc in ('0', 'add', 'del', 'xxx'):
+ for cc in ('0', 'add', 'del', 'xxx'):
- op,ev = get(old,wc,rc)
-
- fmt(op, ev, old, wc, rc)
+ op,ev = get(old,wc,rc,cc)
+ fmt(op, ev, old, wc, rc, cc)
diff --git a/test/Makefile.nmake b/test/Makefile.nmake
index 92244ad7..a4609ac2 100644
--- a/test/Makefile.nmake
+++ b/test/Makefile.nmake
@@ -22,13 +22,13 @@ REGRESS_OBJS=regress.obj regress_buffer.obj regress_http.obj regress_dns.obj \
regress_main.obj regress_minheap.obj regress_iocp.obj \
regress_thread.obj regress_finalize.obj $(SSL_OBJS)
-OTHER_OBJS=test-init.obj test-eof.obj test-weof.obj test-time.obj \
+OTHER_OBJS=test-init.obj test-eof.obj test-closed.obj test-weof.obj test-time.obj \
bench.obj bench_cascade.obj bench_http.obj bench_httpclient.obj \
test-changelist.obj \
print-winsock-errors.obj
PROGRAMS=regress.exe \
- test-init.exe test-eof.exe test-weof.exe test-time.exe \
+ test-init.exe test-eof.exe test-closed.exe test-weof.exe test-time.exe \
test-changelist.exe \
print-winsock-errors.exe
@@ -47,6 +47,8 @@ test-init.exe: test-init.obj
$(CC) $(CFLAGS) $(LIBS) test-init.obj
test-eof.exe: test-eof.obj
$(CC) $(CFLAGS) $(LIBS) test-eof.obj
+test-closed.exe: test-closed.obj
+ $(CC) $(CFLAGS) $(LIBS) test-closed.obj
test-changelist.exe: test-changelist.obj
$(CC) $(CFLAGS) $(LIBS) test-changelist.obj
test-weof.exe: test-weof.obj
diff --git a/test/include.am b/test/include.am
index 930d8422..629e9d27 100644
--- a/test/include.am
+++ b/test/include.am
@@ -22,6 +22,7 @@ TESTPROGRAMS = \
test/test-changelist \
test/test-dumpevents \
test/test-eof \
+ test/test-closed \
test/test-fdleak \
test/test-init \
test/test-ratelim \
@@ -60,6 +61,8 @@ test_test_dumpevents_SOURCES = test/test-dumpevents.c
test_test_dumpevents_LDADD = libevent_core.la
test_test_eof_SOURCES = test/test-eof.c
test_test_eof_LDADD = libevent_core.la
+test_test_closed_SOURCES = test/test-closed.c
+test_test_closed_LDADD = libevent_core.la
test_test_changelist_SOURCES = test/test-changelist.c
test_test_changelist_LDADD = libevent_core.la
test_test_weof_SOURCES = test/test-weof.c
diff --git a/test/test-closed.c b/test/test-closed.c
new file mode 100644
index 00000000..5b04f354
--- /dev/null
+++ b/test/test-closed.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2002-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2013 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "event2/event-config.h"
+
+#ifdef _WIN32
+#include <winsock2.h>
+#else
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef EVENT__HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <event.h>
+#include <evutil.h>
+
+#ifdef EVENT____func__
+#define __func__ EVENT____func__
+#endif
+
+struct timeval timeout = {3, 0};
+
+static void
+closed_cb(evutil_socket_t fd, short event, void *arg)
+{
+ if (EV_TIMEOUT & event) {
+ printf("%s: Timeout!\n", __func__);
+ exit(1);
+ }
+
+ if (EV_CLOSED & event) {
+ printf("%s: detected socket close with success\n", __func__);
+ return;
+ }
+
+ printf("%s: unable to detect socket close\n", __func__);
+ exit(1);
+}
+
+#ifndef SHUT_WR
+#define SHUT_WR 1
+#endif
+
+int
+main(int argc, char **argv)
+{
+ struct event_base *base;
+ struct event_config *cfg;
+ struct event *ev;
+ const char *test = "test string";
+ evutil_socket_t pair[2];
+
+ /* Initialize the library and check if the backend
+ supports EV_FEATURE_EARLY_CLOSE
+ */
+ cfg = event_config_new();
+ event_config_require_features(cfg, EV_FEATURE_EARLY_CLOSE);
+ base = event_base_new_with_config(cfg);
+ event_config_free(cfg);
+ if (!base) {
+ /* Backend doesn't support EV_FEATURE_EARLY_CLOSE */
+ return 0;
+ }
+
+ /* Create a pair of sockets */
+ if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1)
+ return (1);
+
+ /* Send some data on socket 0 and immediately close it */
+ if (send(pair[0], test, (int)strlen(test)+1, 0) < 0)
+ return (1);
+ shutdown(pair[0], SHUT_WR);
+
+ /* Dispatch */
+ ev = event_new(base, pair[1], EV_CLOSED | EV_TIMEOUT, closed_cb, event_self_cbarg());
+ event_add(ev, &timeout);
+ event_base_dispatch(base);
+
+ /* Finalize library */
+ event_base_free(base);
+ return 0;
+}
+
diff --git a/test/test.sh b/test/test.sh
index d16fcde3..2b083ac7 100755
--- a/test/test.sh
+++ b/test/test.sh
@@ -1,7 +1,7 @@
#!/bin/sh
BACKENDS="EVPORT KQUEUE EPOLL DEVPOLL POLL SELECT WIN32"
-TESTS="test-eof test-weof test-time test-changelist test-fdleak"
+TESTS="test-eof test-closed test-weof test-time test-changelist test-fdleak"
FAILED=no
TEST_OUTPUT_FILE=${TEST_OUTPUT_FILE:-/dev/null}
REGRESS_ARGS=${REGRESS_ARGS:-}