timeout: do not handle timeouts while scheduling

To handle all pending timeouts in the context of scheduling a timeout
was only necessary because the Timeout framework once made use of the
Alarm framework. The method Alarm_scheduler::schedule_absolute took an
absolute deadline as argument and we couldn't change this beause the
Alarm framework was also used without the Timeout framework. We had to
calculate this absolute deadline with the now time of the Timeout
framework but the Alarm framework has its own now time that is always a
bit behind the one of the Timeout framework. This lead to bad decisisons
when finding the right position for the new timeout. Now, we can call
schedule_absolute with a relative duration and thereby fix the problem.

When we schedule an absolute timeout without considering the small time
difference, the end-time for the timeout that is calculated using the
local time value is also smaller than the expected end-time. This can
also lead to directly triggering timeouts that should have triggered
with a certain delay.

As it is not trivial to update the local time value while scheduling a
timeout _without_ calling other timeout handlers, we simply raise the
duration of the new timeout by the age of the local time value.

Issue #2704
This commit is contained in:
Martin Stein 2018-03-21 14:56:09 +01:00 committed by Christian Helmuth
parent f152e3e9d0
commit 93a0c66589

View File

@ -138,13 +138,19 @@ void Alarm_timeout_scheduler::_enable()
void Alarm_timeout_scheduler::_schedule_one_shot(Timeout &timeout,
Microseconds duration)
{
unsigned long const curr_time_us =
_time_source.curr_time().trunc_to_plain_us().value;
/* raise timeout duration by the age of the local time value */
unsigned long us = _time_source.curr_time().trunc_to_plain_us().value;
if (us >= _now) {
us = duration.value + (us - _now); }
else {
us = duration.value + (~0UL - _now) + us; }
if (us >= duration.value) {
duration.value = us; }
/* ensure that the schedulers time is up-to-date before adding a timeout */
_alarm_handle(curr_time_us);
/* insert timeout into scheduling queue */
_alarm_schedule_absolute(&timeout._alarm, duration.value);
/* if new timeout is the closest to now, update the time-source timeout */
if (_alarm_head_timeout(&timeout._alarm)) {
_time_source.schedule_timeout(Microseconds(0), *this); }
}
@ -153,8 +159,6 @@ void Alarm_timeout_scheduler::_schedule_one_shot(Timeout &timeout,
void Alarm_timeout_scheduler::_schedule_periodic(Timeout &timeout,
Microseconds duration)
{
/* ensure that the schedulers time is up-to-date before adding a timeout */
_alarm_handle(_time_source.curr_time().trunc_to_plain_us().value);
_alarm_schedule(&timeout._alarm, duration.value);
if (_alarm_head_timeout(&timeout._alarm)) {