]> granicus.if.org Git - libevent/commitdiff
make event_add not change any state if it fails; repoted by Ian Bell
authorNiels Provos <provos@gmail.com>
Fri, 25 Jul 2008 01:29:54 +0000 (01:29 +0000)
committerNiels Provos <provos@gmail.com>
Fri, 25 Jul 2008 01:29:54 +0000 (01:29 +0000)
svn:r923

ChangeLog
event.c

index e9b61f48d051c15bff7011360d087dbea87a4489..2038a76186500a6d0a38e4f37e873e4d84485758 100644 (file)
--- 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 e7ed52363485fce54aeafa0508bdff4297008abd..77d2f1dec53076258ec359efc540d1639187d6b9 100644 (file)
--- 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);