From 5914f8fd92434d201be4bfa1325c00130ebc9e45 Mon Sep 17 00:00:00 2001 From: Aaron Dierking Date: Fri, 3 May 2019 15:42:20 -0700 Subject: [PATCH] SR-9033: handle EPOLLHUP on Linux If epoll_wait() reports EPOLLHUP, we must respond immediately and unregister the event or else Dispatch will go into a spinloop. This makes dispatch_io_pipe_close (#476) pass on Linux with identical output to Darwin. --- src/event/event_epoll.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/event/event_epoll.c b/src/event/event_epoll.c index 7c746c0f2..8210b923b 100644 --- a/src/event/event_epoll.c +++ b/src/event/event_epoll.c @@ -549,6 +549,20 @@ _dispatch_get_buffer_size(dispatch_muxnote_t dmn, bool writer) return (uintptr_t)n; } +static void +_dispatch_event_merge_hangup(dispatch_unote_t du) +{ + // consumed by dux_merge_evt() + _dispatch_retain_unote_owner(du); + dispatch_unote_state_t du_state = _dispatch_unote_state(du); + du_state |= DU_STATE_NEEDS_DELETE; + du_state &= ~DU_STATE_ARMED; + _dispatch_unote_state_set(du, du_state); + uintptr_t data = 0; // EOF + os_atomic_store2o(du._dr, ds_pending_data, ~data, relaxed); + dux_merge_evt(du._du, EV_DELETE|EV_DISPATCH, data, 0); +} + static void _dispatch_event_merge_fd(dispatch_muxnote_t dmn, uint32_t events) { @@ -583,6 +597,20 @@ _dispatch_event_merge_fd(dispatch_muxnote_t dmn, uint32_t events) } } + // SR-9033: EPOLLHUP is an unmaskable event which we must respond to + if (events & EPOLLHUP) { + LIST_FOREACH_SAFE(dul, &dmn->dmn_readers_head, du_link, dul_next) { + dispatch_unote_t du = _dispatch_unote_linkage_get_unote(dul); + _dispatch_event_merge_hangup(du); + } + LIST_FOREACH_SAFE(dul, &dmn->dmn_writers_head, du_link, dul_next) { + dispatch_unote_t du = _dispatch_unote_linkage_get_unote(dul); + _dispatch_event_merge_hangup(du); + } + epoll_ctl(_dispatch_epfd, EPOLL_CTL_DEL, dmn->dmn_fd, NULL); + return; + } + events = _dispatch_muxnote_armed_events(dmn); if (events) _dispatch_epoll_update(dmn, events, EPOLL_CTL_MOD); }