Double-check next timeout when adding events

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.
This commit is contained in:
Nate Rosenblum 2013-03-05 11:29:33 -08:00
parent 13676535c8
commit 9443868d55

10
event.c
View File

@ -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;
}
}