genode/repos/os/include/os/timeout.h
2017-01-13 13:05:45 +01:00

279 lines
6.2 KiB
C++

/*
* \brief Multiplexing one time source amongst different timeouts
* \author Martin Stein
* \date 2016-11-04
*/
/*
* Copyright (C) 2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _OS__TIMEOUT_H_
#define _OS__TIMEOUT_H_
/* Genode includes */
#include <util/noncopyable.h>
#include <os/time_source.h>
#include <os/alarm.h>
namespace Genode {
class Timeout_scheduler;
class Timeout;
class Alarm_timeout_scheduler;
template <typename> class Periodic_timeout;
template <typename> class One_shot_timeout;
}
/**
* Interface of a time-source multiplexer
*
* Beside 'curr_time()', this abstract interface is used by the Timeout
* implementation only. Users of the timeout framework must schedule and
* discard timeouts via methods of the timeout.
*/
class Genode::Timeout_scheduler
{
public:
using Microseconds = Time_source::Microseconds;
private:
friend Timeout;
/**
* Add a one-shot timeout to the schedule
*
* \param timeout timeout callback object
* \param duration timeout trigger delay
*/
virtual void _schedule_one_shot(Timeout &timeout, Microseconds duration) = 0;
/**
* Add a periodic timeout to the schedule
*
* \param timeout timeout callback object
* \param duration timeout trigger period
*/
virtual void _schedule_periodic(Timeout &timeout, Microseconds duration) = 0;
/**
* Remove timeout from the scheduler
*
* \param timeout corresponding timeout callback object
*/
virtual void _discard(Timeout &timeout) = 0;
public:
/**
* Read out the now time of the scheduler
*/
virtual Microseconds curr_time() const = 0;
};
/**
* Timeout callback that can be used for both one-shot and periodic timeouts
*
* This class should be used only if it is necessary to use one timeout
* callback for both periodic and one-shot timeouts. This is the case, for
* example, in a Timer-session server. If this is not the case, the classes
* Periodic_timeout and One_shot_timeout are the better choice.
*/
class Genode::Timeout : private Noncopyable
{
friend class Alarm_timeout_scheduler;
public:
/**
* Interface of a timeout handler
*/
struct Handler
{
using Microseconds = Time_source::Microseconds;
virtual void handle_timeout(Microseconds curr_time) = 0;
};
private:
using Microseconds = Time_source::Microseconds;
struct Alarm : Genode::Alarm
{
Timeout_scheduler &timeout_scheduler;
Handler *handler = nullptr;
bool periodic;
Alarm(Timeout_scheduler &timeout_scheduler)
: timeout_scheduler(timeout_scheduler) { }
/*******************
** Genode::Alarm **
*******************/
bool on_alarm(unsigned) override;
} _alarm;
public:
Timeout(Timeout_scheduler &timeout_scheduler)
: _alarm(timeout_scheduler) { }
~Timeout() { discard(); }
void schedule_periodic(Microseconds duration, Handler &handler);
void schedule_one_shot(Microseconds duration, Handler &handler);
void discard();
};
/**
* Periodic timeout that is linked to a custom handler, starts when constructed
*/
template <typename HANDLER>
struct Genode::Periodic_timeout : private Noncopyable
{
public:
using Microseconds = Timeout_scheduler::Microseconds;
private:
typedef void (HANDLER::*Handler_method)(Microseconds);
Timeout _timeout;
struct Handler : Timeout::Handler
{
HANDLER &object;
Handler_method const method;
Handler(HANDLER &object, Handler_method method)
: object(object), method(method) { }
/**********************
** Timeout::Handler **
**********************/
void handle_timeout(Microseconds curr_time) override {
(object.*method)(curr_time); }
} _handler;
public:
Periodic_timeout(Timeout_scheduler &timeout_scheduler,
HANDLER &object,
Handler_method method,
Microseconds duration)
:
_timeout(timeout_scheduler), _handler(object, method)
{
_timeout.schedule_periodic(duration, _handler);
}
};
/**
* One-shot timeout that is linked to a custom handler, started manually
*/
template <typename HANDLER>
class Genode::One_shot_timeout : private Noncopyable
{
private:
using Microseconds = Timeout_scheduler::Microseconds;
typedef void (HANDLER::*Handler_method)(Microseconds);
Timeout _timeout;
struct Handler : Timeout::Handler
{
HANDLER &object;
Handler_method const method;
Handler(HANDLER &object, Handler_method method)
: object(object), method(method) { }
/**********************
** Timeout::Handler **
**********************/
void handle_timeout(Microseconds curr_time) override {
(object.*method)(curr_time); }
} _handler;
public:
One_shot_timeout(Timeout_scheduler &timeout_scheduler,
HANDLER &object,
Handler_method method)
: _timeout(timeout_scheduler), _handler(object, method) { }
void start(Microseconds duration) {
_timeout.schedule_one_shot(duration, _handler); }
};
/**
* Timeout-scheduler implementation using the Alarm framework
*/
class Genode::Alarm_timeout_scheduler : private Noncopyable,
public Timeout_scheduler,
public Time_source::Timeout_handler
{
private:
Time_source &_time_source;
Alarm_scheduler _alarm_scheduler;
/**********************************
** Time_source::Timeout_handler **
**********************************/
void handle_timeout(Microseconds curr_time) override;
/***********************
** Timeout_scheduler **
***********************/
void _schedule_one_shot(Timeout &timeout, Microseconds duration) override;
void _schedule_periodic(Timeout &timeout, Microseconds duration) override;
void _discard(Timeout &timeout) override {
_alarm_scheduler.discard(&timeout._alarm); }
public:
Alarm_timeout_scheduler(Time_source &time_source);
/***********************
** Timeout_scheduler **
***********************/
Microseconds curr_time() const override {
return _time_source.curr_time(); }
};
#endif /* _OS__TIMEOUT_H_ */