Skip to content

Commit c7ec2db

Browse files
committed
Track armed events in muxnotes closely
This fixes issues around resuming or re-registering file-descriptors with a previously triggered EPOLLONESHOT event. Signed-off-by: Pierre Habouzit <phabouzit@apple.com> Fixes: SR-5759
1 parent 0fd5a69 commit c7ec2db

File tree

1 file changed

+68
-32
lines changed

1 file changed

+68
-32
lines changed

src/event/event_epoll.c

Lines changed: 68 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,13 @@ typedef struct dispatch_muxnote_s {
4747
TAILQ_ENTRY(dispatch_muxnote_s) dmn_list;
4848
TAILQ_HEAD(, dispatch_unote_linkage_s) dmn_readers_head;
4949
TAILQ_HEAD(, dispatch_unote_linkage_s) dmn_writers_head;
50-
int dmn_fd;
51-
uint32_t dmn_ident;
52-
uint32_t dmn_events;
53-
int16_t dmn_filter;
54-
bool dmn_skip_outq_ioctl;
55-
bool dmn_skip_inq_ioctl;
50+
int dmn_fd;
51+
uint32_t dmn_ident;
52+
uint32_t dmn_events;
53+
uint16_t dmn_disarmed_events;
54+
int8_t dmn_filter;
55+
bool dmn_skip_outq_ioctl : 1;
56+
bool dmn_skip_inq_ioctl : 1;
5657
} *dispatch_muxnote_t;
5758

5859
typedef struct dispatch_epoll_timeout_s {
@@ -83,6 +84,13 @@ static struct dispatch_epoll_timeout_s _dispatch_epoll_timeout[] = {
8384

8485
#pragma mark dispatch_muxnote_t
8586

87+
DISPATCH_ALWAYS_INLINE
88+
static inline uint32_t
89+
_dispatch_muxnote_armed_events(dispatch_muxnote_t dmn)
90+
{
91+
return dmn->dmn_events & ~dmn->dmn_disarmed_events;
92+
}
93+
8694
DISPATCH_ALWAYS_INLINE
8795
static inline struct dispatch_muxnote_bucket_s *
8896
_dispatch_muxnote_bucket(uint32_t ident)
@@ -207,33 +215,27 @@ _dispatch_muxnote_create(dispatch_unote_t du, uint32_t events)
207215
#pragma mark dispatch_unote_t
208216

209217
static int
210-
_dispatch_epoll_update(dispatch_muxnote_t dmn, int op)
218+
_dispatch_epoll_update(dispatch_muxnote_t dmn, uint32_t events, int op)
211219
{
212220
dispatch_once_f(&epoll_init_pred, NULL, _dispatch_epoll_init);
213221
struct epoll_event ev = {
214-
.events = dmn->dmn_events,
222+
.events = events,
215223
.data = { .ptr = dmn },
216224
};
217225
return epoll_ctl(_dispatch_epfd, op, dmn->dmn_fd, &ev);
218226
}
219227

220-
bool
221-
_dispatch_unote_register(dispatch_unote_t du,
222-
DISPATCH_UNUSED dispatch_wlh_t wlh, dispatch_priority_t pri)
228+
DISPATCH_ALWAYS_INLINE
229+
static inline uint32_t
230+
_dispatch_unote_required_events(dispatch_unote_t du)
223231
{
224-
struct dispatch_muxnote_bucket_s *dmb;
225-
dispatch_muxnote_t dmn;
226232
uint32_t events = EPOLLFREE;
227233

228-
dispatch_assert(!_dispatch_unote_registered(du));
229-
du._du->du_priority = pri;
230-
231234
switch (du._du->du_filter) {
232235
case DISPATCH_EVFILT_CUSTOM_ADD:
233236
case DISPATCH_EVFILT_CUSTOM_OR:
234237
case DISPATCH_EVFILT_CUSTOM_REPLACE:
235-
du._du->du_wlh = DISPATCH_WLH_ANON;
236-
return true;
238+
return 0;
237239
case EVFILT_WRITE:
238240
events |= EPOLLOUT;
239241
break;
@@ -246,20 +248,35 @@ _dispatch_unote_register(dispatch_unote_t du,
246248
events |= EPOLLONESHOT;
247249
}
248250

251+
return events;
252+
}
253+
254+
bool
255+
_dispatch_unote_register(dispatch_unote_t du,
256+
DISPATCH_UNUSED dispatch_wlh_t wlh, dispatch_priority_t pri)
257+
{
258+
struct dispatch_muxnote_bucket_s *dmb;
259+
dispatch_muxnote_t dmn;
260+
uint32_t events = _dispatch_unote_required_events(du);
261+
262+
dispatch_assert(!_dispatch_unote_registered(du));
263+
du._du->du_priority = pri;
264+
249265
dmb = _dispatch_unote_muxnote_bucket(du);
250266
dmn = _dispatch_unote_muxnote_find(dmb, du);
251267
if (dmn) {
252-
events &= ~dmn->dmn_events;
253-
if (events) {
254-
dmn->dmn_events |= events;
255-
if (_dispatch_epoll_update(dmn, EPOLL_CTL_MOD) < 0) {
256-
dmn->dmn_events &= ~events;
268+
if (events & ~_dispatch_muxnote_armed_events(dmn)) {
269+
events |= _dispatch_muxnote_armed_events(dmn);
270+
if (_dispatch_epoll_update(dmn, events, EPOLL_CTL_MOD) < 0) {
257271
dmn = NULL;
272+
} else {
273+
dmn->dmn_events = events;
274+
dmn->dmn_disarmed_events &= ~events;
258275
}
259276
}
260277
} else {
261278
dmn = _dispatch_muxnote_create(du, events);
262-
if (_dispatch_epoll_update(dmn, EPOLL_CTL_ADD) < 0) {
279+
if (_dispatch_epoll_update(dmn, events, EPOLL_CTL_ADD) < 0) {
263280
_dispatch_muxnote_dispose(dmn);
264281
dmn = NULL;
265282
} else {
@@ -286,8 +303,13 @@ _dispatch_unote_resume(dispatch_unote_t du)
286303
{
287304
dispatch_muxnote_t dmn = _dispatch_unote_get_linkage(du)->du_muxnote;
288305
dispatch_assert(_dispatch_unote_registered(du));
306+
uint32_t events = _dispatch_unote_required_events(du);
289307

290-
_dispatch_epoll_update(dmn, EPOLL_CTL_MOD);
308+
if (events & dmn->dmn_disarmed_events) {
309+
dmn->dmn_disarmed_events &= ~events;
310+
events = _dispatch_muxnote_armed_events(dmn);
311+
_dispatch_epoll_update(dmn, events, EPOLL_CTL_MOD);
312+
}
291313
}
292314

293315
bool
@@ -314,17 +336,26 @@ _dispatch_unote_unregister(dispatch_unote_t du, DISPATCH_UNUSED uint32_t flags)
314336
dul->du_muxnote = NULL;
315337

316338
if (TAILQ_EMPTY(&dmn->dmn_readers_head)) {
317-
events &= (uint32_t)(~EPOLLIN);
339+
events &= (uint32_t)~EPOLLIN;
340+
if (dmn->dmn_disarmed_events & EPOLLIN) {
341+
dmn->dmn_disarmed_events &= (uint16_t)~EPOLLIN;
342+
dmn->dmn_events &= (uint32_t)~EPOLLIN;
343+
}
318344
}
319345
if (TAILQ_EMPTY(&dmn->dmn_writers_head)) {
320-
events &= (uint32_t)(~EPOLLOUT);
346+
events &= (uint32_t)~EPOLLOUT;
347+
if (dmn->dmn_disarmed_events & EPOLLOUT) {
348+
dmn->dmn_disarmed_events &= (uint16_t)~EPOLLOUT;
349+
dmn->dmn_events &= (uint32_t)~EPOLLOUT;
350+
}
321351
}
322352

323-
if (events == dmn->dmn_events) {
324-
// nothing to do
325-
} else if (events & (EPOLLIN | EPOLLOUT)) {
326-
dmn->dmn_events = events;
327-
_dispatch_epoll_update(dmn, EPOLL_CTL_MOD);
353+
if (events & (EPOLLIN | EPOLLOUT)) {
354+
if (events != _dispatch_muxnote_armed_events(dmn)) {
355+
dmn->dmn_events = events;
356+
events = _dispatch_muxnote_armed_events(dmn);
357+
_dispatch_epoll_update(dmn, events, EPOLL_CTL_MOD);
358+
}
328359
} else {
329360
epoll_ctl(_dispatch_epfd, EPOLL_CTL_DEL, dmn->dmn_fd, NULL);
330361
TAILQ_REMOVE(_dispatch_unote_muxnote_bucket(du), dmn, dmn_list);
@@ -533,6 +564,8 @@ _dispatch_event_merge_fd(dispatch_muxnote_t dmn, uint32_t events)
533564
dispatch_unote_linkage_t dul, dul_next;
534565
uintptr_t data;
535566

567+
dmn->dmn_disarmed_events |= (events & (EPOLLIN | EPOLLOUT));
568+
536569
if (events & EPOLLIN) {
537570
data = _dispatch_get_buffer_size(dmn, false);
538571
TAILQ_FOREACH_SAFE(dul, &dmn->dmn_readers_head, du_link, dul_next) {
@@ -548,6 +581,9 @@ _dispatch_event_merge_fd(dispatch_muxnote_t dmn, uint32_t events)
548581
dux_merge_evt(du._du, EV_ADD|EV_ENABLE|EV_DISPATCH, ~data, 0, 0);
549582
}
550583
}
584+
585+
events = _dispatch_muxnote_armed_events(dmn);
586+
if (events) _dispatch_epoll_update(dmn, events, EPOLL_CTL_MOD);
551587
}
552588

553589
DISPATCH_NOINLINE

0 commit comments

Comments
 (0)