Change remove_event logic

We defer the removal of entries until after the poll loop has finished.
Otherwise we may end up adjusting the poll array while we're still
reading from it, causing us to skip events.
This commit is contained in:
Scott Anderson 2018-04-21 14:38:34 +12:00
parent e0107c4dd7
commit 9a3fb33e33

View file

@ -72,25 +72,19 @@ void add_event(int fd, short mask,
} }
bool remove_event(int fd) { bool remove_event(int fd) {
int index = -1; /*
* Instead of removing events immediately, we mark them for deletion
* and clean them up later. This is so we can call remove_event inside
* an event callback safely.
*/
for (int i = 0; i < event_loop.fds.length; ++i) { for (int i = 0; i < event_loop.fds.length; ++i) {
if (event_loop.fds.items[i].fd == fd) { if (event_loop.fds.items[i].fd == fd) {
index = i; event_loop.fds.items[i].fd = -1;
}
}
if (index != -1) {
free(event_loop.items->items[index]);
--event_loop.fds.length;
memmove(&event_loop.fds.items[index], &event_loop.fds.items[index + 1],
sizeof(struct pollfd) * event_loop.fds.length - index);
list_del(event_loop.items, index);
return true; return true;
} else {
return false;
} }
} }
return false;
}
static int timer_item_timer_cmp(const void *_timer_item, const void *_timer) { static int timer_item_timer_cmp(const void *_timer_item, const void *_timer) {
const struct timer_item *timer_item = _timer_item; const struct timer_item *timer_item = _timer_item;
@ -126,6 +120,21 @@ void event_loop_poll() {
} }
} }
// Cleanup removed events
int end = 0;
int length = event_loop.fds.length;
for (int i = 0; i < length; ++i) {
if (event_loop.fds.items[i].fd == -1) {
free(event_loop.items->items[i]);
list_del(event_loop.items, i);
--event_loop.fds.length;
} else if (end != i) {
event_loop.fds.items[end++] = event_loop.fds.items[i];
} else {
end = i + 1;
}
}
// check timers // check timers
// not tested, but seems to work // not tested, but seems to work
for (int i = 0; i < event_loop.timers->length; ++i) { for (int i = 0; i < event_loop.timers->length; ++i) {