diff --git a/repos/os/include/os/alarm.h b/repos/os/include/os/alarm.h index 0bfcf1aa09..717d6e9e22 100644 --- a/repos/os/include/os/alarm.h +++ b/repos/os/include/os/alarm.h @@ -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) { } diff --git a/repos/os/src/lib/alarm/alarm.cc b/repos/os/src/lib/alarm/alarm.cc index c8f2b64e98..ef4c7364c2 100644 --- a/repos/os/src/lib/alarm/alarm.cc +++ b/repos/os/src/lib/alarm/alarm.cc @@ -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); }