mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-24 07:46:42 +00:00
alarm: reposition reprogrammed alarms in queue
The alarm library failed to handle the case properly where an already scheduled alarm gets rescheduled before it triggered. Even though the attempt to reschedule the alarm (twice insertion into alarm queue) was detected, this condition resulted in the mere modification of the alarm's parameters while keeping the alarm's queue position unchanged. This, in turn, may violate the invariant that all enqueued alarm objects are strictly ordered by their deadlines. The patch handles the case by dequeuing the alarm object before reinserting it into the queue at the right position. Fixes #1646
This commit is contained in:
parent
e410ecc995
commit
26524edbf4
@ -92,6 +92,11 @@ class Genode::Alarm_scheduler
|
||||
*/
|
||||
Alarm *_get_pending_alarm();
|
||||
|
||||
/**
|
||||
* Assign timeout values to alarm object and add it to the schedule
|
||||
*/
|
||||
void _setup_alarm(Alarm &alarm, Alarm::Time period, Alarm::Time deadline);
|
||||
|
||||
public:
|
||||
|
||||
Alarm_scheduler() : _head(0), _now(0) { }
|
||||
|
@ -19,9 +19,10 @@ using namespace Genode;
|
||||
|
||||
void Alarm_scheduler::_unsynchronized_enqueue(Alarm *alarm)
|
||||
{
|
||||
/* do not enqueue twice */
|
||||
if (alarm->_active)
|
||||
if (alarm->_active) {
|
||||
PERR("trying to insert the same alarm twice!");
|
||||
return;
|
||||
}
|
||||
|
||||
alarm->_active++;
|
||||
|
||||
@ -146,12 +147,27 @@ void Alarm_scheduler::handle(Alarm::Time curr_time)
|
||||
}
|
||||
|
||||
|
||||
void Alarm_scheduler::_setup_alarm(Alarm &alarm, Alarm::Time period, Alarm::Time deadline)
|
||||
{
|
||||
/*
|
||||
* If the alarm is already present in the queue, re-consider its queue
|
||||
* position because its deadline might have changed. I.e., if an alarm is
|
||||
* rescheduled with a new timeout before the original timeout triggered.
|
||||
*/
|
||||
if (alarm._active)
|
||||
_unsynchronized_dequeue(&alarm);
|
||||
|
||||
alarm._assign(period, deadline, this);
|
||||
|
||||
_unsynchronized_enqueue(&alarm);
|
||||
}
|
||||
|
||||
|
||||
void Alarm_scheduler::schedule_absolute(Alarm *alarm, Alarm::Time timeout)
|
||||
{
|
||||
Lock::Guard alarm_list_lock_guard(_lock);
|
||||
|
||||
alarm->_assign(0, timeout, this);
|
||||
_unsynchronized_enqueue(alarm);
|
||||
_setup_alarm(*alarm, 0, timeout);
|
||||
}
|
||||
|
||||
|
||||
@ -159,9 +175,19 @@ void Alarm_scheduler::schedule(Alarm *alarm, Alarm::Time period)
|
||||
{
|
||||
Lock::Guard alarm_list_lock_guard(_lock);
|
||||
|
||||
/*
|
||||
* Refuse to schedule a periodic timeout of 0 because it would trigger
|
||||
* infinitely in the 'handle' function. To account for the case where the
|
||||
* alarm object was already scheduled, we make sure to remove it from the
|
||||
* queue.
|
||||
*/
|
||||
if (period == 0) {
|
||||
_unsynchronized_dequeue(alarm);
|
||||
return;
|
||||
}
|
||||
|
||||
/* first deadline is overdue */
|
||||
alarm->_assign(period, _now, this);
|
||||
_unsynchronized_enqueue(alarm);
|
||||
_setup_alarm(*alarm, period, _now);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user