genode/os/src/drivers/timer/include/timer_session_component.h

270 lines
6.0 KiB
C++

/*
* \brief Instance of the timer session interface
* \author Norman Feske
* \author Markus Partheymueller
* \date 2006-08-15
*/
/*
* Copyright (C) 2006-2013 Genode Labs GmbH
* Copyright (C) 2012 Intel Corporation
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _TIMER_SESSION_COMPONENT_
#define _TIMER_SESSION_COMPONENT_
/* Genode includes */
#include <util/list.h>
#include <os/alarm.h>
#include <base/rpc_server.h>
#include <timer_session/timer_session.h>
/* local includes */
#include "platform_timer.h"
namespace Timer {
enum { STACK_SIZE = 32*1024 };
struct Irq_dispatcher {
GENODE_RPC(Rpc_do_dispatch, void, do_dispatch);
GENODE_RPC_INTERFACE(Rpc_do_dispatch);
};
/**
* Timer interrupt handler
*
* This class represents a RPC object that gets locally called for each
* timer interrupt. It is managed by the same entrypoint as all timer
* client components. Because the 'do_dispatch' function is executed in
* the same thread context as the dispatch functions of client requests,
* we are able to answer those requests from here (by calling the
* 'handle()' function of the alarm scheduler).
*/
class Irq_dispatcher_component : public Rpc_object<Irq_dispatcher,
Irq_dispatcher_component>
{
private:
Genode::Alarm_scheduler *_alarm_scheduler;
Platform_timer *_platform_timer;
public:
/**
* Constructor
*/
Irq_dispatcher_component(Genode::Alarm_scheduler *as,
Platform_timer *pt)
: _alarm_scheduler(as), _platform_timer(pt) { }
/******************************
** Irq_dispatcher interface **
******************************/
void do_dispatch()
{
using namespace Genode;
Alarm::Time now = _platform_timer->curr_time();
Alarm::Time sleep_time;
/* trigger timeout alarms */
_alarm_scheduler->handle(now);
/* determine duration for next one-shot timer event */
Alarm::Time deadline;
if (_alarm_scheduler->next_deadline(&deadline))
sleep_time = deadline - now;
else
sleep_time = _platform_timer->max_timeout();
if (sleep_time == 0)
sleep_time = 1;
_platform_timer->schedule_timeout(sleep_time);
}
};
/**
* Alarm for answering an oneshot timeout request
*/
class Wake_up_alarm : public Genode::Alarm
{
private:
Signal_context_capability _sigh;
bool _periodic;
public:
Wake_up_alarm() : _periodic(false) { }
void sigh(Signal_context_capability sigh) { _sigh = sigh; }
void periodic(bool periodic) { _periodic = periodic; }
/*********************
** Alarm interface **
*********************/
/**
* Dispatch a wakeup alarm
*
* This function gets called by the 'Alarm_scheduler' thread.
*/
bool on_alarm()
{
Signal_transmitter(_sigh).submit();
return _periodic;
}
};
class Timeout_scheduler : public Genode::Alarm_scheduler,
Genode::Thread<STACK_SIZE>
{
private:
typedef Genode::Capability<Irq_dispatcher>
Irq_dispatcher_capability;
Platform_timer *_platform_timer;
Irq_dispatcher_component _irq_dispatcher_component;
Irq_dispatcher_capability _irq_dispatcher_cap;
/**
* Timer-interrupt thread
*
* This thread blocks for the timer interrupt. For each occuring
* interrupt, it performs an local RPC call to the server
* activation, which, in turn, processes the scheduled timeouts and
* reprograms the platform timer.
*/
void entry()
{
while (true) {
_platform_timer->wait_for_timeout(this);
/*
* Call timer irq handler to trigger timeout alarms and
* reprogram the platform timer.
*/
_irq_dispatcher_cap.call<Irq_dispatcher::Rpc_do_dispatch>();
}
}
public:
/**
* Constructor
*/
Timeout_scheduler(Platform_timer *pt, Genode::Rpc_entrypoint *ep)
:
_platform_timer(pt),
_irq_dispatcher_component(this, pt),
_irq_dispatcher_cap(ep->manage(&_irq_dispatcher_component))
{
_platform_timer->schedule_timeout(0);
start();
}
/**
* Called from the '_trigger' function executed by the server activation
*/
void schedule_timeout(Genode::Alarm *alarm, Genode::Alarm::Time timeout)
{
Alarm::Time now = _platform_timer->curr_time();
schedule_absolute(alarm, now + timeout);
/* interrupt current 'wait_for_timeout' */
_platform_timer->schedule_timeout(0);
}
unsigned long curr_time() const
{
return _platform_timer->curr_time();
}
};
/**
* Timer session
*/
class Session_component : public Rpc_object<Session>,
public List<Session_component>::Element
{
private:
Timeout_scheduler &_timeout_scheduler;
Wake_up_alarm _wake_up_alarm;
unsigned long const _initial_time;
void _trigger(unsigned us, bool periodic)
{
_wake_up_alarm.periodic(periodic);
_timeout_scheduler.schedule_timeout(&_wake_up_alarm, us);
}
public:
/**
* Constructor
*/
Session_component(Timeout_scheduler &ts)
:
_timeout_scheduler(ts),
_initial_time(_timeout_scheduler.curr_time())
{ }
/**
* Destructor
*/
~Session_component()
{
_timeout_scheduler.discard(&_wake_up_alarm);
}
/*****************************
** Timer session interface **
*****************************/
void trigger_once(unsigned us)
{
_trigger(us, false);
}
void trigger_periodic(unsigned us)
{
_trigger(us, true);
}
void sigh(Signal_context_capability sigh)
{
_wake_up_alarm.sigh(sigh);
}
unsigned long elapsed_ms() const
{
unsigned long const now = _timeout_scheduler.curr_time();
return now - _initial_time;
}
void msleep(unsigned) { /* never called at the server side */ }
void usleep(unsigned) { /* never called at the server side */ }
};
}
#endif