mirror of
https://github.com/cuberite/libevent.git
synced 2025-09-14 14:54:49 -04:00
If time has jumped so we'd reschedule a periodic event in the past, schedule it for the future instead
Fixes an issue reported on libevent-users in the thread "a dead looping bug when changing system time backward". Previously, if time jumped forward 1 hour[*] and we had a one-second periodic timer event, that event would get invoked 3600 times. That's almost certainly not what anybody wants. In a future version of Libevent, we should expose the amount of time that the callbac kwould have been invoked somehow. [*] Forward time jumps can happen with nonmonotonic clocks, or with clocks that jump on suspend/resume. It can also happen from Libevent's point of view if the user exits from event_base_loop() and doesn't call it again for a while.
This commit is contained in:
parent
bec22b4176
commit
dfd808cbad
10
event.c
10
event.c
@ -1280,9 +1280,17 @@ event_persist_closure(struct event_base *base, struct event *ev)
|
|||||||
} else {
|
} else {
|
||||||
relative_to = now;
|
relative_to = now;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
evutil_timeradd(&relative_to, &delay, &run_at);
|
evutil_timeradd(&relative_to, &delay, &run_at);
|
||||||
|
if (evutil_timercmp(&run_at, &now, <)) {
|
||||||
|
/* Looks like we missed at least one invocation due to
|
||||||
|
* a clock jump, not running the event loop for a
|
||||||
|
* while, really slow callbacks, or
|
||||||
|
* something. Reschedule relative to now.
|
||||||
|
*/
|
||||||
|
evutil_timeradd(&now, &delay, &run_at);
|
||||||
|
}
|
||||||
|
run_at.tv_usec |= usec_mask;
|
||||||
event_add_internal(ev, &run_at, 1);
|
event_add_internal(ev, &run_at, 1);
|
||||||
}
|
}
|
||||||
EVBASE_RELEASE_LOCK(base, th_base_lock);
|
EVBASE_RELEASE_LOCK(base, th_base_lock);
|
||||||
|
@ -627,6 +627,27 @@ test_persistent_timeout(void)
|
|||||||
event_del(&ev);
|
event_del(&ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_persistent_timeout_jump(void *ptr)
|
||||||
|
{
|
||||||
|
struct basic_test_data *data = ptr;
|
||||||
|
struct event ev;
|
||||||
|
int count = 0;
|
||||||
|
struct timeval msec100 = { 0, 100 * 1000 };
|
||||||
|
struct timeval msec50 = { 0, 50 * 1000 };
|
||||||
|
|
||||||
|
event_assign(&ev, data->base, -1, EV_PERSIST, periodic_timeout_cb, &count);
|
||||||
|
event_add(&ev, &msec100);
|
||||||
|
/* Wait for a bit */
|
||||||
|
sleep(1);
|
||||||
|
event_base_loopexit(data->base, &msec50);
|
||||||
|
event_base_dispatch(data->base);
|
||||||
|
tt_int_op(count, ==, 1);
|
||||||
|
|
||||||
|
end:
|
||||||
|
event_del(&ev);
|
||||||
|
}
|
||||||
|
|
||||||
struct persist_active_timeout_called {
|
struct persist_active_timeout_called {
|
||||||
int n;
|
int n;
|
||||||
short events[16];
|
short events[16];
|
||||||
@ -2338,8 +2359,8 @@ struct testcase_t main_testcases[] = {
|
|||||||
BASIC(bad_assign, TT_FORK|TT_NEED_BASE|TT_NO_LOGS),
|
BASIC(bad_assign, TT_FORK|TT_NEED_BASE|TT_NO_LOGS),
|
||||||
BASIC(bad_reentrant, TT_FORK|TT_NEED_BASE|TT_NO_LOGS),
|
BASIC(bad_reentrant, TT_FORK|TT_NEED_BASE|TT_NO_LOGS),
|
||||||
|
|
||||||
/* These are still using the old API */
|
|
||||||
LEGACY(persistent_timeout, TT_FORK|TT_NEED_BASE),
|
LEGACY(persistent_timeout, TT_FORK|TT_NEED_BASE),
|
||||||
|
{ "persistent_timeout_jump", test_persistent_timeout_jump, TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
|
||||||
{ "persistent_active_timeout", test_persistent_active_timeout,
|
{ "persistent_active_timeout", test_persistent_active_timeout,
|
||||||
TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
|
TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
|
||||||
LEGACY(priorities, TT_FORK|TT_NEED_BASE),
|
LEGACY(priorities, TT_FORK|TT_NEED_BASE),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user