genode/repos/os/src/lib/timeout/timeout.cc

122 lines
2.9 KiB
C++

/*
* \brief Multiplexing one time source amongst different timeout subjects
* \author Martin Stein
* \date 2016-11-04
*/
/*
* Copyright (C) 2016-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* Genode includes */
#include <timer/timeout.h>
using namespace Genode;
/*************
** Timeout **
*************/
void Timeout::schedule_periodic(Microseconds duration, Handler &handler)
{
_alarm.handler = &handler;
_alarm.periodic = true;
_alarm.timeout_scheduler._schedule_periodic(*this, duration);
}
void Timeout::schedule_one_shot(Microseconds duration, Handler &handler)
{
_alarm.handler = &handler;
_alarm.periodic = false;
_alarm.timeout_scheduler._schedule_one_shot(*this, duration);
}
void Timeout::discard()
{
_alarm.timeout_scheduler._discard(*this);
_alarm.handler = nullptr;
}
/********************
** Timeout::Alarm **
********************/
bool Timeout::Alarm::on_alarm(unsigned)
{
if (handler) {
Handler *current = handler;
if (!periodic) {
handler = nullptr;
}
current->handle_timeout(timeout_scheduler.curr_time());
}
return periodic;
}
/*****************************
** Alarm_timeout_scheduler **
*****************************/
void Alarm_timeout_scheduler::handle_timeout(Duration curr_time)
{
unsigned long const curr_time_us = curr_time.trunc_to_plain_us().value;
_alarm_scheduler.handle(curr_time_us);
unsigned long sleep_time_us;
Alarm::Time deadline_us;
if (_alarm_scheduler.next_deadline(&deadline_us)) {
sleep_time_us = deadline_us - curr_time_us;
} else {
sleep_time_us = _time_source.max_timeout().value; }
/* limit max timeout to a more reasonable value, e.g. 60s */
if (sleep_time_us > 60000000) {
sleep_time_us = 60000000;
} else if (sleep_time_us == 0) {
sleep_time_us = 1; }
_time_source.schedule_timeout(Microseconds(sleep_time_us), *this);
}
Alarm_timeout_scheduler::Alarm_timeout_scheduler(Time_source &time_source)
:
_time_source(time_source)
{ }
void Alarm_timeout_scheduler::_enable()
{
_time_source.schedule_timeout(Microseconds(0), *this);
}
void Alarm_timeout_scheduler::_schedule_one_shot(Timeout &timeout,
Microseconds duration)
{
_alarm_scheduler.schedule_absolute(
&timeout._alarm,
_time_source.curr_time().trunc_to_plain_us().value + duration.value);
if (_alarm_scheduler.head_timeout(&timeout._alarm)) {
_time_source.schedule_timeout(Microseconds(0), *this); }
}
void Alarm_timeout_scheduler::_schedule_periodic(Timeout &timeout,
Microseconds duration)
{
_alarm_scheduler.handle(_time_source.curr_time().trunc_to_plain_us().value);
_alarm_scheduler.schedule(&timeout._alarm, duration.value);
if (_alarm_scheduler.head_timeout(&timeout._alarm)) {
_time_source.schedule_timeout(Microseconds(0), *this); }
}