205 lines
4.2 KiB
C++
205 lines
4.2 KiB
C++
/*
|
|
* \brief Instance of the timer session interface
|
|
* \author Norman Feske
|
|
* \author Markus Partheymueller
|
|
* \date 2010-01-30
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2010-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 <os/alarm.h>
|
|
#include <base/rpc_server.h>
|
|
#include <timer_session/capability.h>
|
|
|
|
/* local includes */
|
|
#include "platform_timer.h"
|
|
|
|
|
|
namespace Timer {
|
|
|
|
enum { STACK_SIZE = sizeof(Genode::addr_t) * 1024 };
|
|
|
|
class Wake_up_alarm : public Genode::Alarm
|
|
{
|
|
private:
|
|
|
|
Genode::Cancelable_lock *_barrier;
|
|
|
|
public:
|
|
|
|
Wake_up_alarm(Genode::Cancelable_lock *barrier)
|
|
: _barrier(barrier) { }
|
|
|
|
|
|
/*********************
|
|
** Alarm interface **
|
|
*********************/
|
|
|
|
/**
|
|
* Dispatch a wakeup alarm
|
|
*
|
|
* This function gets called by the 'Alarm_scheduler' thread.
|
|
*/
|
|
bool on_alarm()
|
|
{
|
|
_barrier->unlock();
|
|
|
|
/* do not re-schedule */
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
|
|
class Timeout_scheduler : public Genode::Alarm_scheduler, Genode::Thread<STACK_SIZE>
|
|
{
|
|
private:
|
|
|
|
Platform_timer *_platform_timer;
|
|
|
|
/**
|
|
* Timer-interrupt thread
|
|
*/
|
|
void entry()
|
|
{
|
|
using namespace Genode;
|
|
|
|
while (true) {
|
|
|
|
_platform_timer->wait_for_timeout(this);
|
|
|
|
Alarm::Time now = _platform_timer->curr_time();
|
|
Alarm::Time sleep_time;
|
|
|
|
/* trigger timeout alarms */
|
|
handle(now);
|
|
|
|
/* determine duration for next one-shot timer event */
|
|
Alarm::Time deadline;
|
|
if (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);
|
|
}
|
|
}
|
|
|
|
public:
|
|
|
|
/**
|
|
* Constructor
|
|
*/
|
|
Timeout_scheduler(Platform_timer *pt, Genode::Rpc_entrypoint *ep)
|
|
: Genode::Thread<STACK_SIZE>("irq"), _platform_timer(pt)
|
|
{
|
|
_platform_timer->schedule_timeout(0);
|
|
PDBG("starting timeout scheduler");
|
|
start();
|
|
}
|
|
|
|
/**
|
|
* Called from the 'msleep' function executed by the server activation
|
|
*/
|
|
void schedule_timeout(Genode::Alarm *alarm, Genode::Alarm::Time timeout)
|
|
{
|
|
Genode::Alarm::Time now = _platform_timer->curr_time();
|
|
schedule_absolute(alarm, now + timeout);
|
|
|
|
/* interrupt current 'wait_for_timeout' */
|
|
_platform_timer->schedule_timeout(0);
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* Timer session
|
|
*/
|
|
class Session_component : public Genode::Rpc_object<Session>,
|
|
public Genode::List<Session_component>::Element
|
|
{
|
|
private:
|
|
|
|
Timeout_scheduler *_timeout_scheduler;
|
|
Genode::Rpc_entrypoint _entrypoint;
|
|
Session_capability _session_cap;
|
|
Genode::Cancelable_lock _barrier;
|
|
Wake_up_alarm _wake_up_alarm;
|
|
|
|
public:
|
|
|
|
/**
|
|
* Constructor
|
|
*/
|
|
Session_component(Timeout_scheduler *ts,
|
|
Genode::Cap_session *cap)
|
|
:
|
|
_timeout_scheduler(ts),
|
|
_entrypoint(cap, STACK_SIZE, "timer_session_ep"),
|
|
_session_cap(_entrypoint.manage(this)),
|
|
_barrier(Genode::Cancelable_lock::LOCKED),
|
|
_wake_up_alarm(&_barrier)
|
|
{ }
|
|
|
|
/**
|
|
* Destructor
|
|
*/
|
|
~Session_component()
|
|
{
|
|
_entrypoint.dissolve(this);
|
|
_timeout_scheduler->discard(&_wake_up_alarm);
|
|
}
|
|
|
|
/**
|
|
* Return true if capability belongs to session object
|
|
*/
|
|
bool belongs_to(Genode::Session_capability cap)
|
|
{
|
|
Genode::Object_pool<Session_component>::Guard
|
|
lcap(_entrypoint.lookup_and_lock(cap));
|
|
return lcap == this;
|
|
}
|
|
|
|
/**
|
|
* Return session capability
|
|
*/
|
|
Session_capability cap() { return _session_cap; }
|
|
|
|
|
|
/*****************************
|
|
** Timer session interface **
|
|
*****************************/
|
|
|
|
void msleep(unsigned ms)
|
|
{
|
|
usleep(1000*ms);
|
|
}
|
|
|
|
void usleep(unsigned us)
|
|
{
|
|
_timeout_scheduler->schedule_timeout(&_wake_up_alarm, us);
|
|
|
|
/*
|
|
* Prevent the server activation from immediately answering the
|
|
* current call. We will block until the timeout alarm triggers
|
|
* and unblocks the semaphore.
|
|
*/
|
|
_barrier.lock();
|
|
}
|
|
};
|
|
}
|
|
|
|
#endif
|