From cca2f8fa0eee370e1b75de198dc755c9a4a23bf2 Mon Sep 17 00:00:00 2001 From: Niels Provos Date: Fri, 25 Jul 2008 01:29:54 +0000 Subject: [PATCH] make event_add not change any state if it fails; repoted by Ian Bell svn:r923 --- ChangeLog | 1 + event.c | 37 ++++++++++++++++++++++++++----------- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/ChangeLog b/ChangeLog index e9b61f48..2038a761 100644 --- a/ChangeLog +++ b/ChangeLog @@ -120,6 +120,7 @@ Changes in current version: o Support multiple events listening on the same signal; make signals regular events that go on the same event queue; problem report by Alexander Drozdov. o Fix a problem with epoll() and reinit; problem report by Alexander Drozdov. o Fix off-by-one errors in devpoll; from Ian Bell + o Make event_add not change any state if it fails; reported by Ian Bell. Changes in 1.4.0: o allow \r or \n individually to separate HTTP headers instead of the standard "\r\n"; from Charles Kerr. diff --git a/event.c b/event.c index e7ed5236..77d2f1de 100644 --- a/event.c +++ b/event.c @@ -1027,14 +1027,36 @@ event_add_internal(struct event *ev, const struct timeval *tv) assert(!(ev->ev_flags & ~EVLIST_ALL)); - if (tv != NULL) { + /* + * prepare for timeout insertion further below, if we get a + * failure on any step, we should not change any state. + */ + if (tv != NULL && !(ev->ev_flags & EVLIST_TIMEOUT)) { + if (min_heap_reserve(&base->timeheap, + 1 + min_heap_size(&base->timeheap)) == -1) + return (-1); /* ENOMEM == errno */ + } + + if ((ev->ev_events & (EV_READ|EV_WRITE|EV_SIGNAL)) && + !(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) { + res = evsel->add(evbase, ev); + if (res != -1) + event_queue_insert(base, ev, EVLIST_INSERTED); + } + + /* + * we should change the timout state only if the previous event + * addition succeeded. + */ + if (res != -1 && tv != NULL) { struct timeval now; + /* + * we already reserved memory above for the case where we + * are not replacing an exisiting timeout. + */ if (ev->ev_flags & EVLIST_TIMEOUT) event_queue_remove(base, ev, EVLIST_TIMEOUT); - else if (min_heap_reserve(&base->timeheap, - 1 + min_heap_size(&base->timeheap)) == -1) - return (-1); /* ENOMEM == errno */ /* Check if it is active due to a timeout. Rescheduling * this timeout before the callback can be executed @@ -1064,13 +1086,6 @@ event_add_internal(struct event *ev, const struct timeval *tv) event_queue_insert(base, ev, EVLIST_TIMEOUT); } - if ((ev->ev_events & (EV_READ|EV_WRITE|EV_SIGNAL)) && - !(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) { - res = evsel->add(evbase, ev); - if (res != -1) - event_queue_insert(base, ev, EVLIST_INSERTED); - } - /* if we are not in the right thread, we need to wake up the loop */ if (res != -1 && !EVTHREAD_IN_THREAD(base)) send(base->th_notify_fd[1], "", 1, 0);