From 77c25aa7e676e4eb8c099940ca8c4b872b64415c Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Fri, 8 Aug 2014 11:59:39 +0200 Subject: [PATCH] Handle io_t's being deleted out of order while going through loop->ios. --- src/event.c | 20 ++++++++++++++++++-- src/event.h | 1 + 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/event.c b/src/event.c index d1a0e256..b6def622 100644 --- a/src/event.c +++ b/src/event.c @@ -81,6 +81,8 @@ void io_del(event_loop_t *loop, io_t *io) { if(!io->cb) return; + loop->deletion = true; + io_set(loop, io, 0); splay_unlink_node(&loop->ios, &io->node); @@ -115,6 +117,8 @@ void timeout_del(event_loop_t *loop, timeout_t *timeout) { if(!timeout->cb) return; + loop->deletion = true; + splay_unlink_node(&loop->timeouts, &timeout->node); timeout->cb = 0; timeout->tv = (struct timeval){0, 0}; @@ -167,6 +171,8 @@ void signal_del(event_loop_t *loop, signal_t *sig) { if(!sig->cb) return; + loop->deletion = true; + splay_unlink_node(&loop->signals, &sig->node); sig->cb = NULL; } @@ -217,11 +223,21 @@ bool event_loop_run(event_loop_t *loop) { if(!n) continue; + // Normally, splay_each allows the current node to be deleted. However, + // it can be that one io callback triggers the deletion of another io, + // so we have to detect this and break the loop. + + loop->deletion = false; + for splay_each(io_t, io, &loop->ios) { - if(FD_ISSET(io->fd, &writable)) + if(FD_ISSET(io->fd, &writable) && io->cb) io->cb(loop, io->data, IO_WRITE); - else if(FD_ISSET(io->fd, &readable)) + if(loop->deletion) + break; + if(FD_ISSET(io->fd, &readable) && io->cb) io->cb(loop, io->data, IO_READ); + if(loop->deletion) + break; } } diff --git a/src/event.h b/src/event.h index c90e5067..6e77fbdf 100644 --- a/src/event.h +++ b/src/event.h @@ -60,6 +60,7 @@ struct event_loop_t { volatile bool running; struct timeval now; + bool deletion; splay_tree_t ios; splay_tree_t timeouts; -- 2.39.5