]> granicus.if.org Git - libevent/commitdiff
Double-check next timeout when adding events
authorNate Rosenblum <nater@maginatics.com>
Tue, 5 Mar 2013 19:29:33 +0000 (11:29 -0800)
committerNate Rosenblum <nater@maginatics.com>
Tue, 5 Mar 2013 19:29:33 +0000 (11:29 -0800)
When resuming the system from a suspended state, the ev_timeout field
of a scheduled timer event may be in the past. This leads to
unexpected behavior when scheduling a short-duration timer event
immediately after returning from suspension, because the new event
does not land on top of the timeout minheap and so the event loop
(blocked on a possibly long-duration timeout) is not notified.

This patch checks for this condition and, if it obtains, notifies the
event loop.

event.c

diff --git a/event.c b/event.c
index 51e34a99b6a20166eb98fbe9ec57943be203fb43..9286c36fba4d62dfb07ed7d5c38680a0260dd43a 100644 (file)
--- a/event.c
+++ b/event.c
@@ -2378,12 +2378,18 @@ event_add_nolock_(struct event *ev, const struct timeval *tv,
                                common_timeout_schedule(ctl, &now, ev);
                        }
                } else {
+                       struct event* top = NULL;
                        /* See if the earliest timeout is now earlier than it
                         * was before: if so, we will need to tell the main
-                        * thread to wake up earlier than it would
-                        * otherwise. */
+                        * thread to wake up earlier than it would otherwise.
+                        * We double check the timeout of the top element to
+                        * handle time distortions due to system suspension.
+                        */
                        if (min_heap_elt_is_top_(ev))
                                notify = 1;
+                       else if ((top = min_heap_top_(&base->timeheap)) != NULL &&
+                                        evutil_timercmp(&top->ev_timeout, &now, <))
+                               notify = 1;
                }
        }