timeout: become independent of the Alarm framework
Integrate the code of the Alarm framework directly into the Timeout framework. The former Alarm-framework methods are all private to the corresponding classes of the Timeout framework and get prefixed with '_alarm__'. The latter avoids name clashes and makes it easier to simplify the code later. Issue #2704
This commit is contained in:
parent
8c7bbdecdf
commit
38dbd59d8a
|
@ -201,6 +201,9 @@ _ZN6Genode23Alarm_timeout_scheduler18_schedule_periodicERNS_7TimeoutENS_12Micros
|
||||||
_ZN6Genode23Alarm_timeout_scheduler7_enableEv T
|
_ZN6Genode23Alarm_timeout_scheduler7_enableEv T
|
||||||
_ZN6Genode23Alarm_timeout_schedulerC1ERNS_11Time_sourceENS_12MicrosecondsE T
|
_ZN6Genode23Alarm_timeout_schedulerC1ERNS_11Time_sourceENS_12MicrosecondsE T
|
||||||
_ZN6Genode23Alarm_timeout_schedulerC2ERNS_11Time_sourceENS_12MicrosecondsE T
|
_ZN6Genode23Alarm_timeout_schedulerC2ERNS_11Time_sourceENS_12MicrosecondsE T
|
||||||
|
_ZN6Genode23Alarm_timeout_schedulerD0Ev T
|
||||||
|
_ZN6Genode23Alarm_timeout_schedulerD1Ev T
|
||||||
|
_ZN6Genode23Alarm_timeout_schedulerD2Ev T
|
||||||
_ZN6Genode25env_stack_area_region_mapE B 8
|
_ZN6Genode25env_stack_area_region_mapE B 8
|
||||||
_ZN6Genode28env_stack_area_ram_allocatorE B 8
|
_ZN6Genode28env_stack_area_ram_allocatorE B 8
|
||||||
_ZN6Genode3Log3logEv T
|
_ZN6Genode3Log3logEv T
|
||||||
|
@ -317,6 +320,9 @@ _ZN6Genode7Console7vprintfEPKcPv T
|
||||||
_ZN6Genode7Console7vprintfEPKcSt9__va_list T
|
_ZN6Genode7Console7vprintfEPKcSt9__va_list T
|
||||||
_ZN6Genode7Timeout17schedule_one_shotENS_12MicrosecondsERNS0_7HandlerE T
|
_ZN6Genode7Timeout17schedule_one_shotENS_12MicrosecondsERNS0_7HandlerE T
|
||||||
_ZN6Genode7Timeout17schedule_periodicENS_12MicrosecondsERNS0_7HandlerE T
|
_ZN6Genode7Timeout17schedule_periodicENS_12MicrosecondsERNS0_7HandlerE T
|
||||||
|
_ZN6Genode7Timeout5AlarmD0Ev T
|
||||||
|
_ZN6Genode7Timeout5AlarmD1Ev T
|
||||||
|
_ZN6Genode7Timeout5AlarmD2Ev T
|
||||||
_ZN6Genode7Timeout7discardEv T
|
_ZN6Genode7Timeout7discardEv T
|
||||||
_ZN6Genode7cap_mapEv T
|
_ZN6Genode7cap_mapEv T
|
||||||
_ZN6Genode7vprintfEPKcP13__va_list_tag T
|
_ZN6Genode7vprintfEPKcP13__va_list_tag T
|
||||||
|
@ -396,7 +402,7 @@ _ZTIN6Genode5ChildE D 72
|
||||||
_ZTIN6Genode6OutputE D 24
|
_ZTIN6Genode6OutputE D 24
|
||||||
_ZTIN6Genode6ThreadE D 16
|
_ZTIN6Genode6ThreadE D 16
|
||||||
_ZTIN6Genode7ConsoleE D 16
|
_ZTIN6Genode7ConsoleE D 16
|
||||||
_ZTIN6Genode7Timeout5AlarmE D 24
|
_ZTIN6Genode7Timeout5AlarmE D 16
|
||||||
_ZTIPDd D 32
|
_ZTIPDd D 32
|
||||||
_ZTIPDe D 32
|
_ZTIPDe D 32
|
||||||
_ZTIPDf D 32
|
_ZTIPDf D 32
|
||||||
|
@ -555,7 +561,7 @@ _ZTVN6Genode5ChildE D 408
|
||||||
_ZTVN6Genode6OutputE D 48
|
_ZTVN6Genode6OutputE D 48
|
||||||
_ZTVN6Genode6ThreadE D 48
|
_ZTVN6Genode6ThreadE D 48
|
||||||
_ZTVN6Genode7ConsoleE D 48
|
_ZTVN6Genode7ConsoleE D 48
|
||||||
_ZTVN6Genode7Timeout5AlarmE D 40
|
_ZTVN6Genode7Timeout5AlarmE D 32
|
||||||
_ZTVSt10bad_typeid D 40
|
_ZTVSt10bad_typeid D 40
|
||||||
_ZTVSt13bad_exception D 40
|
_ZTVSt13bad_exception D 40
|
||||||
_ZTVSt16bad_array_length D 40
|
_ZTVSt16bad_array_length D 40
|
||||||
|
@ -578,6 +584,8 @@ _ZThn296_N5Timer10Connection8_discardERN6Genode7TimeoutE T
|
||||||
_ZThn296_N5Timer10Connection9curr_timeEv T
|
_ZThn296_N5Timer10Connection9curr_timeEv T
|
||||||
_ZThn4_N6Genode23Alarm_timeout_scheduler14handle_timeoutENS_8DurationE T
|
_ZThn4_N6Genode23Alarm_timeout_scheduler14handle_timeoutENS_8DurationE T
|
||||||
_ZThn8_N6Genode23Alarm_timeout_scheduler14handle_timeoutENS_8DurationE T
|
_ZThn8_N6Genode23Alarm_timeout_scheduler14handle_timeoutENS_8DurationE T
|
||||||
|
_ZThn8_N6Genode23Alarm_timeout_schedulerD0Ev T
|
||||||
|
_ZThn8_N6Genode23Alarm_timeout_schedulerD1Ev T
|
||||||
_ZdlPv W
|
_ZdlPv W
|
||||||
_ZdlPvPN6Genode11DeallocatorE T
|
_ZdlPvPN6Genode11DeallocatorE T
|
||||||
_ZdlPvPN6Genode9AllocatorE W
|
_ZdlPvPN6Genode9AllocatorE W
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
/* Genode includes */
|
/* Genode includes */
|
||||||
#include <util/noncopyable.h>
|
#include <util/noncopyable.h>
|
||||||
#include <os/alarm.h>
|
#include <base/lock.h>
|
||||||
#include <base/log.h>
|
#include <base/log.h>
|
||||||
#include <os/duration.h>
|
#include <os/duration.h>
|
||||||
|
|
||||||
|
@ -152,13 +152,44 @@ class Genode::Timeout : private Noncopyable
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
class Alarm : public Genode::Alarm
|
class Alarm
|
||||||
{
|
{
|
||||||
|
friend class Alarm_timeout_scheduler;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/*
|
typedef unsigned long Time;
|
||||||
* Noncopyable
|
|
||||||
*/
|
struct Raw
|
||||||
|
{
|
||||||
|
Time deadline;
|
||||||
|
bool deadline_period;
|
||||||
|
Time period;
|
||||||
|
|
||||||
|
bool is_pending_at(unsigned long time, bool time_period) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
Lock _dispatch_lock { };
|
||||||
|
Raw _raw { };
|
||||||
|
int _active { 0 };
|
||||||
|
Alarm *_next { nullptr };
|
||||||
|
Alarm_timeout_scheduler *_scheduler { nullptr };
|
||||||
|
|
||||||
|
void _alarm_assign(Time period,
|
||||||
|
Time deadline,
|
||||||
|
bool deadline_period,
|
||||||
|
Alarm_timeout_scheduler *scheduler)
|
||||||
|
{
|
||||||
|
_raw.period = period;
|
||||||
|
_raw.deadline_period = deadline_period;
|
||||||
|
_raw.deadline = deadline;
|
||||||
|
_scheduler = scheduler;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _alarm_reset() { _alarm_assign(0, 0, false, 0), _active = 0, _next = 0; }
|
||||||
|
|
||||||
|
bool _on_alarm(unsigned);
|
||||||
|
|
||||||
Alarm(Alarm const &);
|
Alarm(Alarm const &);
|
||||||
Alarm &operator = (Alarm const &);
|
Alarm &operator = (Alarm const &);
|
||||||
|
|
||||||
|
@ -169,14 +200,9 @@ class Genode::Timeout : private Noncopyable
|
||||||
bool periodic = false;
|
bool periodic = false;
|
||||||
|
|
||||||
Alarm(Timeout_scheduler &timeout_scheduler)
|
Alarm(Timeout_scheduler &timeout_scheduler)
|
||||||
: timeout_scheduler(timeout_scheduler) { }
|
: timeout_scheduler(timeout_scheduler) { _alarm_reset(); }
|
||||||
|
|
||||||
|
virtual ~Alarm();
|
||||||
/*******************
|
|
||||||
** Genode::Alarm **
|
|
||||||
*******************/
|
|
||||||
|
|
||||||
bool on_alarm(unsigned) override;
|
|
||||||
|
|
||||||
} _alarm;
|
} _alarm;
|
||||||
|
|
||||||
|
@ -206,11 +232,26 @@ class Genode::Alarm_timeout_scheduler : private Noncopyable,
|
||||||
{
|
{
|
||||||
friend class Timer::Connection;
|
friend class Timer::Connection;
|
||||||
friend class Timer::Root_component;
|
friend class Timer::Root_component;
|
||||||
|
friend class Timeout::Alarm;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
using Alarm = Timeout::Alarm;
|
||||||
|
|
||||||
Time_source &_time_source;
|
Time_source &_time_source;
|
||||||
Alarm_scheduler _alarm_scheduler;
|
Lock _lock { };
|
||||||
|
Alarm *_head { nullptr };
|
||||||
|
Alarm::Time _now { 0UL };
|
||||||
|
bool _now_period { false };
|
||||||
|
Alarm::Raw _min_handle_period { };
|
||||||
|
|
||||||
|
void _alarm_unsynchronized_enqueue(Alarm *alarm);
|
||||||
|
|
||||||
|
void _alarm_unsynchronized_dequeue(Alarm *alarm);
|
||||||
|
|
||||||
|
Alarm *_alarm_get_pending_alarm();
|
||||||
|
|
||||||
|
void _alarm_setup_alarm(Alarm &alarm, Alarm::Time period, Alarm::Time deadline);
|
||||||
|
|
||||||
void _enable();
|
void _enable();
|
||||||
|
|
||||||
|
@ -230,13 +271,30 @@ class Genode::Alarm_timeout_scheduler : private Noncopyable,
|
||||||
void _schedule_periodic(Timeout &timeout, Microseconds duration) override;
|
void _schedule_periodic(Timeout &timeout, Microseconds duration) override;
|
||||||
|
|
||||||
void _discard(Timeout &timeout) override {
|
void _discard(Timeout &timeout) override {
|
||||||
_alarm_scheduler.discard(&timeout._alarm); }
|
_alarm_discard(&timeout._alarm); }
|
||||||
|
|
||||||
|
void _alarm_discard(Alarm *alarm);
|
||||||
|
|
||||||
|
void _alarm_schedule_absolute(Alarm *alarm, Alarm::Time timeout);
|
||||||
|
|
||||||
|
void _alarm_schedule(Alarm *alarm, Alarm::Time period);
|
||||||
|
|
||||||
|
void _alarm_handle(Alarm::Time now);
|
||||||
|
|
||||||
|
bool _alarm_next_deadline(Alarm::Time *deadline);
|
||||||
|
|
||||||
|
bool _alarm_head_timeout(const Alarm * alarm) { return _head == alarm; }
|
||||||
|
|
||||||
|
Alarm_timeout_scheduler(Alarm_timeout_scheduler const &);
|
||||||
|
Alarm_timeout_scheduler &operator = (Alarm_timeout_scheduler const &);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Alarm_timeout_scheduler(Time_source &time_source,
|
Alarm_timeout_scheduler(Time_source &time_source,
|
||||||
Microseconds min_handle_period = Microseconds(1));
|
Microseconds min_handle_period = Microseconds(1));
|
||||||
|
|
||||||
|
~Alarm_timeout_scheduler();
|
||||||
|
|
||||||
|
|
||||||
/***********************
|
/***********************
|
||||||
** Timeout_scheduler **
|
** Timeout_scheduler **
|
||||||
|
|
|
@ -48,7 +48,7 @@ void Timeout::discard()
|
||||||
** Timeout::Alarm **
|
** Timeout::Alarm **
|
||||||
********************/
|
********************/
|
||||||
|
|
||||||
bool Timeout::Alarm::on_alarm(unsigned)
|
bool Timeout::Alarm::_on_alarm(unsigned)
|
||||||
{
|
{
|
||||||
if (handler) {
|
if (handler) {
|
||||||
Handler *current = handler;
|
Handler *current = handler;
|
||||||
|
@ -61,6 +61,22 @@ bool Timeout::Alarm::on_alarm(unsigned)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Timeout::Alarm::~Alarm()
|
||||||
|
{
|
||||||
|
if (_scheduler)
|
||||||
|
_scheduler->_alarm_discard(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Timeout::Alarm::Raw::is_pending_at(unsigned long time, bool time_period) const
|
||||||
|
{
|
||||||
|
return (time_period == deadline_period &&
|
||||||
|
time >= deadline) ||
|
||||||
|
(time_period != deadline_period &&
|
||||||
|
time < deadline);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*****************************
|
/*****************************
|
||||||
** Alarm_timeout_scheduler **
|
** Alarm_timeout_scheduler **
|
||||||
*****************************/
|
*****************************/
|
||||||
|
@ -69,12 +85,12 @@ void Alarm_timeout_scheduler::handle_timeout(Duration duration)
|
||||||
{
|
{
|
||||||
unsigned long const curr_time_us = duration.trunc_to_plain_us().value;
|
unsigned long const curr_time_us = duration.trunc_to_plain_us().value;
|
||||||
|
|
||||||
_alarm_scheduler.handle(curr_time_us);
|
_alarm_handle(curr_time_us);
|
||||||
|
|
||||||
/* sleep time is either until the next deadline or the maximum timout */
|
/* sleep time is either until the next deadline or the maximum timout */
|
||||||
unsigned long sleep_time_us;
|
unsigned long sleep_time_us;
|
||||||
Alarm::Time deadline_us;
|
Alarm::Time deadline_us;
|
||||||
if (_alarm_scheduler.next_deadline(&deadline_us)) {
|
if (_alarm_next_deadline(&deadline_us)) {
|
||||||
sleep_time_us = deadline_us - curr_time_us;
|
sleep_time_us = deadline_us - curr_time_us;
|
||||||
} else {
|
} else {
|
||||||
sleep_time_us = _time_source.max_timeout().value; }
|
sleep_time_us = _time_source.max_timeout().value; }
|
||||||
|
@ -92,8 +108,25 @@ void Alarm_timeout_scheduler::handle_timeout(Duration duration)
|
||||||
Alarm_timeout_scheduler::Alarm_timeout_scheduler(Time_source &time_source,
|
Alarm_timeout_scheduler::Alarm_timeout_scheduler(Time_source &time_source,
|
||||||
Microseconds min_handle_period)
|
Microseconds min_handle_period)
|
||||||
:
|
:
|
||||||
_time_source(time_source), _alarm_scheduler(min_handle_period.value)
|
_time_source(time_source)
|
||||||
{ }
|
{
|
||||||
|
Alarm::Time const deadline = _now + min_handle_period.value;
|
||||||
|
_min_handle_period.period = min_handle_period.value;
|
||||||
|
_min_handle_period.deadline = deadline;
|
||||||
|
_min_handle_period.deadline_period = _now > deadline ?
|
||||||
|
!_now_period : _now_period;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Alarm_timeout_scheduler::~Alarm_timeout_scheduler()
|
||||||
|
{
|
||||||
|
Lock::Guard lock_guard(_lock);
|
||||||
|
while (_head) {
|
||||||
|
Alarm *next = _head->_next;
|
||||||
|
_head->_alarm_reset();
|
||||||
|
_head = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Alarm_timeout_scheduler::_enable()
|
void Alarm_timeout_scheduler::_enable()
|
||||||
|
@ -109,11 +142,11 @@ void Alarm_timeout_scheduler::_schedule_one_shot(Timeout &timeout,
|
||||||
_time_source.curr_time().trunc_to_plain_us().value;
|
_time_source.curr_time().trunc_to_plain_us().value;
|
||||||
|
|
||||||
/* ensure that the schedulers time is up-to-date before adding a timeout */
|
/* ensure that the schedulers time is up-to-date before adding a timeout */
|
||||||
_alarm_scheduler.handle(curr_time_us);
|
_alarm_handle(curr_time_us);
|
||||||
_alarm_scheduler.schedule_absolute(&timeout._alarm,
|
_alarm_schedule_absolute(&timeout._alarm,
|
||||||
curr_time_us + duration.value);
|
curr_time_us + duration.value);
|
||||||
|
|
||||||
if (_alarm_scheduler.head_timeout(&timeout._alarm)) {
|
if (_alarm_head_timeout(&timeout._alarm)) {
|
||||||
_time_source.schedule_timeout(Microseconds(0), *this); }
|
_time_source.schedule_timeout(Microseconds(0), *this); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,9 +155,251 @@ void Alarm_timeout_scheduler::_schedule_periodic(Timeout &timeout,
|
||||||
Microseconds duration)
|
Microseconds duration)
|
||||||
{
|
{
|
||||||
/* ensure that the schedulers time is up-to-date before adding a timeout */
|
/* ensure that the schedulers time is up-to-date before adding a timeout */
|
||||||
_alarm_scheduler.handle(_time_source.curr_time().trunc_to_plain_us().value);
|
_alarm_handle(_time_source.curr_time().trunc_to_plain_us().value);
|
||||||
_alarm_scheduler.schedule(&timeout._alarm, duration.value);
|
_alarm_schedule(&timeout._alarm, duration.value);
|
||||||
|
|
||||||
if (_alarm_scheduler.head_timeout(&timeout._alarm)) {
|
if (_alarm_head_timeout(&timeout._alarm)) {
|
||||||
_time_source.schedule_timeout(Microseconds(0), *this); }
|
_time_source.schedule_timeout(Microseconds(0), *this); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Alarm_timeout_scheduler::_alarm_unsynchronized_enqueue(Alarm *alarm)
|
||||||
|
{
|
||||||
|
if (alarm->_active) {
|
||||||
|
error("trying to insert the same alarm twice!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
alarm->_active++;
|
||||||
|
|
||||||
|
/* if alarmlist is empty add first element */
|
||||||
|
if (!_head) {
|
||||||
|
alarm->_next = 0;
|
||||||
|
_head = alarm;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if deadline is smaller than any other deadline, put it on the head */
|
||||||
|
if (alarm->_raw.is_pending_at(_head->_raw.deadline, _head->_raw.deadline_period)) {
|
||||||
|
alarm->_next = _head;
|
||||||
|
_head = alarm;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* find list element with a higher deadline */
|
||||||
|
Alarm *curr = _head;
|
||||||
|
while (curr->_next &&
|
||||||
|
curr->_next->_raw.is_pending_at(alarm->_raw.deadline, alarm->_raw.deadline_period))
|
||||||
|
{
|
||||||
|
curr = curr->_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if end of list is reached, append new element */
|
||||||
|
if (curr->_next == 0) {
|
||||||
|
curr->_next = alarm;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* insert element in middle of list */
|
||||||
|
alarm->_next = curr->_next;
|
||||||
|
curr->_next = alarm;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Alarm_timeout_scheduler::_alarm_unsynchronized_dequeue(Alarm *alarm)
|
||||||
|
{
|
||||||
|
if (!_head) return;
|
||||||
|
|
||||||
|
if (_head == alarm) {
|
||||||
|
_head = alarm->_next;
|
||||||
|
alarm->_alarm_reset();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* find predecessor in alarm queue */
|
||||||
|
Alarm *curr;
|
||||||
|
for (curr = _head; curr && (curr->_next != alarm); curr = curr->_next);
|
||||||
|
|
||||||
|
/* alarm is not enqueued */
|
||||||
|
if (!curr) return;
|
||||||
|
|
||||||
|
/* remove alarm from alarm queue */
|
||||||
|
curr->_next = alarm->_next;
|
||||||
|
alarm->_alarm_reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Timeout::Alarm *Alarm_timeout_scheduler::_alarm_get_pending_alarm()
|
||||||
|
{
|
||||||
|
Lock::Guard lock_guard(_lock);
|
||||||
|
|
||||||
|
if (!_head || !_head->_raw.is_pending_at(_now, _now_period)) {
|
||||||
|
return nullptr; }
|
||||||
|
|
||||||
|
/* remove alarm from head of the list */
|
||||||
|
Alarm *pending_alarm = _head;
|
||||||
|
_head = _head->_next;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Acquire dispatch lock to defer destruction until the call of '_on_alarm'
|
||||||
|
* is finished
|
||||||
|
*/
|
||||||
|
pending_alarm->_dispatch_lock.lock();
|
||||||
|
|
||||||
|
/* reset alarm object */
|
||||||
|
pending_alarm->_next = nullptr;
|
||||||
|
pending_alarm->_active--;
|
||||||
|
|
||||||
|
return pending_alarm;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Alarm_timeout_scheduler::_alarm_handle(Alarm::Time curr_time)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Raise the time counter and if it wraps, update also in which
|
||||||
|
* period of the time counter we are.
|
||||||
|
*/
|
||||||
|
if (_now > curr_time) {
|
||||||
|
_now_period = !_now_period;
|
||||||
|
}
|
||||||
|
_now = curr_time;
|
||||||
|
|
||||||
|
if (!_min_handle_period.is_pending_at(_now, _now_period)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Alarm::Time const deadline = _now + _min_handle_period.period;
|
||||||
|
_min_handle_period.deadline = deadline;
|
||||||
|
_min_handle_period.deadline_period = _now > deadline ?
|
||||||
|
!_now_period : _now_period;
|
||||||
|
|
||||||
|
Alarm *curr;
|
||||||
|
while ((curr = _alarm_get_pending_alarm())) {
|
||||||
|
|
||||||
|
unsigned long triggered = 1;
|
||||||
|
|
||||||
|
if (curr->_raw.period) {
|
||||||
|
Alarm::Time deadline = curr->_raw.deadline;
|
||||||
|
|
||||||
|
/* schedule next event */
|
||||||
|
if (deadline == 0)
|
||||||
|
deadline = curr_time;
|
||||||
|
|
||||||
|
triggered += (curr_time - deadline) / curr->_raw.period;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* do not reschedule if alarm function returns 0 */
|
||||||
|
bool reschedule = curr->_on_alarm(triggered);
|
||||||
|
|
||||||
|
if (reschedule) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* At this point, the alarm deadline normally is somewhere near
|
||||||
|
* the current time but If the alarm had no deadline by now,
|
||||||
|
* initialize it with the current time.
|
||||||
|
*/
|
||||||
|
if (curr->_raw.deadline == 0) {
|
||||||
|
curr->_raw.deadline = _now;
|
||||||
|
curr->_raw.deadline_period = _now_period;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Raise the deadline value by one period of the alarm and
|
||||||
|
* if the deadline value wraps thereby, update also in which
|
||||||
|
* period it is located.
|
||||||
|
*/
|
||||||
|
Alarm::Time const deadline = curr->_raw.deadline +
|
||||||
|
triggered * curr->_raw.period;
|
||||||
|
if (curr->_raw.deadline > deadline) {
|
||||||
|
curr->_raw.deadline_period = !curr->_raw.deadline_period;
|
||||||
|
}
|
||||||
|
curr->_raw.deadline = deadline;
|
||||||
|
|
||||||
|
/* synchronize enqueue operation */
|
||||||
|
Lock::Guard lock_guard(_lock);
|
||||||
|
_alarm_unsynchronized_enqueue(curr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* release alarm, resume concurrent destructor operation */
|
||||||
|
curr->_dispatch_lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Alarm_timeout_scheduler::_alarm_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)
|
||||||
|
_alarm_unsynchronized_dequeue(&alarm);
|
||||||
|
|
||||||
|
alarm._alarm_assign(period, deadline, _now > deadline ? !_now_period : _now_period, this);
|
||||||
|
|
||||||
|
_alarm_unsynchronized_enqueue(&alarm);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Alarm_timeout_scheduler::_alarm_schedule_absolute(Alarm *alarm, Alarm::Time timeout)
|
||||||
|
{
|
||||||
|
Lock::Guard alarm_list_lock_guard(_lock);
|
||||||
|
|
||||||
|
_alarm_setup_alarm(*alarm, 0, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Alarm_timeout_scheduler::_alarm_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) {
|
||||||
|
_alarm_unsynchronized_dequeue(alarm);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* first deadline is overdue */
|
||||||
|
_alarm_setup_alarm(*alarm, period, _now);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Alarm_timeout_scheduler::_alarm_discard(Alarm *alarm)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Make sure that nobody is inside the '_alarm_get_pending_alarm' when
|
||||||
|
* grabbing the '_dispatch_lock'. This is important when this function
|
||||||
|
* is called from the 'Alarm' destructor. Without the '_dispatch_lock',
|
||||||
|
* we could take the lock and proceed with destruction just before
|
||||||
|
* '_alarm_get_pending_alarm' tries to grab the lock. When the destructor is
|
||||||
|
* finished, '_alarm_get_pending_alarm' would proceed with operating on a
|
||||||
|
* dangling pointer.
|
||||||
|
*/
|
||||||
|
Lock::Guard alarm_list_lock_guard(_lock);
|
||||||
|
|
||||||
|
if (alarm) {
|
||||||
|
Lock::Guard alarm_lock_guard(alarm->_dispatch_lock);
|
||||||
|
_alarm_unsynchronized_dequeue(alarm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Alarm_timeout_scheduler::_alarm_next_deadline(Alarm::Time *deadline)
|
||||||
|
{
|
||||||
|
Lock::Guard alarm_list_lock_guard(_lock);
|
||||||
|
|
||||||
|
if (!_head) return false;
|
||||||
|
|
||||||
|
if (deadline)
|
||||||
|
*deadline = _head->_raw.deadline;
|
||||||
|
|
||||||
|
if (*deadline < _min_handle_period.deadline) {
|
||||||
|
*deadline = _min_handle_period.deadline;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue