Turn 'Timer::Session' into asynchronous interface

The 'Timer::Session::msleep' function is one of the last occurrences of
long-blocking RPC calls. Synchronous blocking RPC interfaces turned out
to be constant source of trouble and code complexity. I.e., a timer
client that also wants to respond to non-timer events was forced to be a
multi-threaded process. This patch replaces the blocking 'msleep' call
by a mechanism for programming timeouts and receiving wakeup signals in
an asynchronous fashion. Thereby signals originating from the timer can
be handled along with signals from other signal sources by a single
thread.

The changed interface has been tested on Linux, L4/Fiasco, OKL4, NOVA,
L4ka::Pistachio, Codezero, Fiasco.OC, and hw_pbxa9. Furthermore, this
patch adds the timer test to autopilot.

Fixes #1
This commit is contained in:
Norman Feske 2012-10-29 21:05:32 +01:00
parent 0ed8797df2
commit 3049c1004c
39 changed files with 210 additions and 748 deletions

View File

@ -1,4 +1,4 @@
LIBS = child
LIBS = child signal
SRC_CC = launchpad.cc
vpath launchpad.cc $(REP_DIR)/src/lib/launchpad

View File

@ -1,5 +1,5 @@
TARGET = liquid_fb
LIBS = scout_widgets
LIBS = scout_widgets signal
SRC_CC = main.cc services.cc
INC_DIR += $(REP_DIR)/src/app/scout/include \
$(REP_DIR)/src/app/scout/include/genode \

View File

@ -1,5 +1,5 @@
TARGET = nitlog
LIBS = cxx env server blit
LIBS = cxx env server blit signal
SRC_CC = main.cc
SRC_BIN = mono.tff
INC_DIR = $(REP_DIR)/src/server/nitpicker/include

View File

@ -26,9 +26,11 @@ namespace Timer {
explicit Session_client(Session_capability session)
: Genode::Rpc_client<Session>(session) { }
void msleep(unsigned ms) { call<Rpc_msleep>(ms); }
void trigger_once(unsigned us) { call<Rpc_trigger_once>(us); }
void usleep(unsigned us) { call<Rpc_usleep>(us); }
void trigger_periodic(unsigned us) { call<Rpc_trigger_periodic>(us); }
void sigh(Signal_context_capability sigh) { call<Rpc_sigh>(sigh); }
unsigned long elapsed_ms() const { return call<Rpc_elapsed_ms>(); }
};

View File

@ -19,20 +19,61 @@
namespace Timer {
struct Connection : Genode::Connection<Session>, Session_client
class Connection : public Genode::Connection<Session>, public Session_client
{
Connection()
:
/*
* Because the timer service uses one thread per timer session,
* we donate two pages. One of them is used as stack for the
* timer thread and the other page holds the session meta data.
*/
Genode::Connection<Session>(session("ram_quota=%zd",
sizeof(Genode::addr_t)*2048)),
private:
Session_client(cap())
{ }
Lock _lock;
Signal_receiver _sig_rec;
Signal_context _default_sigh_ctx;
Signal_context_capability _default_sigh_cap;
Signal_context_capability _custom_sigh_cap;
public:
Connection()
:
Genode::Connection<Session>(session("ram_quota=8K")),
Session_client(cap()),
_default_sigh_cap(_sig_rec.manage(&_default_sigh_ctx))
{
/* register default signal handler */
sigh(_default_sigh_cap);
}
~Connection() { _sig_rec.dissolve(&_default_sigh_ctx); }
/*
* Intercept 'sigh' to keep track of customized signal handlers
*/
void sigh(Signal_context_capability sigh)
{
_custom_sigh_cap = sigh;
Session_client::sigh(_custom_sigh_cap);
}
void usleep(unsigned us)
{
/* serialize sleep calls issued by different threads */
Lock::Guard guard(_lock);
/* temporarily install to the default signal handler */
if (_custom_sigh_cap.valid())
sigh(_default_sigh_cap);
/* trigger timeout at default signal handler */
trigger_once(us);
_sig_rec.wait_for_signal();
/* revert custom signal handler if registered */
if (_custom_sigh_cap.valid())
sigh(_custom_sigh_cap);
}
void msleep(unsigned ms)
{
usleep(1000*ms);
}
};
}

View File

@ -1,25 +0,0 @@
/*
* \brief Server-side timer session interface
* \author Norman Feske
* \date 2006-08-15
*/
/*
* Copyright (C) 2006-2013 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 _INCLUDE__TIMER_SESSION__SERVER_H_
#define _INCLUDE__TIMER_SESSION__SERVER_H_
#include <timer_session/timer_session.h>
#include <base/rpc_server.h>
namespace Timer {
struct Session_server : Genode::Rpc_object<Session> { };
}
#endif /* _INCLUDE__TIMER_SESSION__SERVER_H_ */

View File

@ -16,10 +16,13 @@
#ifndef _INCLUDE__TIMER_SESSION__TIMER_SESSION_H_
#define _INCLUDE__TIMER_SESSION__TIMER_SESSION_H_
#include <base/signal.h>
#include <session/session.h>
namespace Timer {
using namespace Genode;
struct Session : Genode::Session
{
static const char *service_name() { return "Timer"; }
@ -27,36 +30,49 @@ namespace Timer {
virtual ~Session() { }
/**
* Sleep number of milliseconds
* Program single timeout (in microseconds)
*/
virtual void msleep(unsigned ms) = 0;
virtual void trigger_once(unsigned us) = 0;
/**
* Sleep number of microseconds
* Program periodic timeout (in microseconds)
*/
virtual void usleep(unsigned us) = 0;
virtual void trigger_periodic(unsigned us) = 0;
/**
* Register timeout signal handler
*/
virtual void sigh(Signal_context_capability sigh) = 0;
/**
* Return number of elapsed milliseconds since session creation
*/
virtual unsigned long elapsed_ms() const
{
/*
* XXX Remove default implementation by implementing the
* interface in all timer variants.
*/
return 0; }
virtual unsigned long elapsed_ms() const = 0;
/**
* Client-side convenience function for sleeping the specified number
* of milliseconds
*/
virtual void msleep(unsigned ms) = 0;
/**
* Client-side convenience function for sleeping the specified number
* of microseconds
*/
virtual void usleep(unsigned us) = 0;
/*********************
** RPC declaration **
*********************/
GENODE_RPC(Rpc_msleep, void, msleep, unsigned);
GENODE_RPC(Rpc_usleep, void, usleep, unsigned);
GENODE_RPC(Rpc_trigger_once, void, trigger_once, unsigned);
GENODE_RPC(Rpc_trigger_periodic, void, trigger_periodic, unsigned);
GENODE_RPC(Rpc_sigh, void, sigh, Genode::Signal_context_capability);
GENODE_RPC(Rpc_elapsed_ms, unsigned long, elapsed_ms);
GENODE_RPC_INTERFACE(Rpc_msleep, Rpc_usleep, Rpc_elapsed_ms);
GENODE_RPC_INTERFACE(Rpc_trigger_once, Rpc_trigger_periodic,
Rpc_sigh, Rpc_elapsed_ms);
};
}

View File

@ -24,6 +24,7 @@ install_config {
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
<service name="SIGNAL"/>
</parent-provides>
<default-route>
<any-service><parent/><any-child/></any-service>

View File

@ -1,7 +1,7 @@
TARGET = pl11x_drv
REQUIRES = pl11x platform_pbxa9
SRC_CC = main.cc video_memory.cc
LIBS = cxx env server
LIBS = cxx env server signal
INC_DIR += $(PRG_DIR)/..
vpath %.cc $(PRG_DIR)/..

View File

@ -1,7 +1,7 @@
TARGET = pl11x_drv
REQUIRES = pl11x platform_vea9x4
SRC_CC = main.cc video_memory.cc
LIBS = cxx env server
LIBS = cxx env server signal
INC_DIR += $(PRG_DIR)/..
vpath main.cc $(PRG_DIR)/..

View File

@ -1,7 +1,7 @@
TARGET = pl11x_drv
REQUIRES = pl11x platform_vpb926
SRC_CC = main.cc video_memory.cc
LIBS = cxx env server
LIBS = cxx env server signal
INC_DIR += $(PRG_DIR)/..
vpath %.cc $(PRG_DIR)/..

View File

@ -26,7 +26,7 @@ using namespace Codezero;
unsigned long Platform_timer::max_timeout() { return 1000; }
unsigned long Platform_timer::curr_time()
unsigned long Platform_timer::curr_time() const
{
Genode::Lock::Guard lock_guard(_lock);
return _curr_time_usec;

View File

@ -1,7 +1,7 @@
TARGET = timer
SRC_CC = main.cc platform_timer.cc
REQUIRES = codezero
LIBS = cxx server env alarm
LIBS = cxx server env alarm signal
INC_DIR += $(PRG_DIR)/../include $(PRG_DIR)/../include_periodic

View File

@ -58,7 +58,7 @@ unsigned long Platform_timer::max_timeout()
}
unsigned long Platform_timer::curr_time()
unsigned long Platform_timer::curr_time() const
{
Genode::Lock::Guard lock_guard(_lock);
return _curr_time_usec;

View File

@ -1,7 +1,7 @@
TARGET = timer
SRC_CC = main.cc platform_timer.cc
REQUIRES = fiasco
LIBS = cxx server env alarm
LIBS = cxx server env alarm signal
INC_DIR = $(PRG_DIR)/../include $(PRG_DIR)/../include_periodic

View File

@ -1,8 +1,9 @@
TARGET = timer
SRC_CC = main.cc
SRC_CC = main.cc platform_timer.cc
REQUIRES = foc
LIBS = cxx server env
LIBS = cxx server env alarm signal
INC_DIR = $(PRG_DIR)
INC_DIR = $(PRG_DIR)/../include $(PRG_DIR)/../include_periodic
vpath main.cc $(PRG_DIR)/..
vpath platform_timer.cc $(REP_DIR)/src/drivers/timer/fiasco

View File

@ -1,95 +0,0 @@
/*
* \brief Root interface to timer service
* \author Norman Feske
* \author Stefan Kalkowski
* \date 2006-08-15
*/
/*
* Copyright (C) 2006-2013 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 _TIMER_ROOT_H_
#define _TIMER_ROOT_H_
#include <util/arg_string.h>
#include <util/list.h>
#include <base/printf.h>
#include <base/rpc_server.h>
#include <root/root.h>
#include <cap_session/cap_session.h>
#include "timer_session_component.h"
namespace Timer {
class Root_component : public Genode::Rpc_object<Genode::Typed_root<Session> >
{
private:
Genode::Allocator *_md_alloc;
Genode::Cap_session *_cap_session;
Genode::List<Session_component> _sessions;
public:
/**
* Constructor
*/
Root_component(Genode::Rpc_entrypoint *session_ep,
Genode::Allocator *md_alloc,
Genode::Cap_session *cap)
: _md_alloc(md_alloc), _cap_session(cap) { }
/********************
** Root interface **
********************/
Genode::Session_capability session(Root::Session_args const &args)
{
using namespace Genode;
if (!args.is_valid_string()) throw Invalid_args();
size_t ram_quota = Arg_string::find_arg(args.string(), "ram_quota").ulong_value(0);
size_t require = sizeof(Session_component) + STACK_SIZE;
if (ram_quota < require) {
PWRN("Insufficient donated ram_quota (%zd bytes), require %zd bytes",
ram_quota, require);
}
/* create session object */
Session_component *sc = new (_md_alloc) Session_component(_cap_session);
_sessions.insert(sc);
return sc->cap();
}
void upgrade(Genode::Session_capability, Root::Upgrade_args const &) { }
void close(Genode::Session_capability session_cap)
{
/*
* Lookup session-component by its capability by asking each
* entry point for object belonging to the capability. Only one
* entry point is expected to give the right answer.
*/
Session_component *sc = _sessions.first();
for (; sc && !sc->belongs_to(session_cap); sc = sc->next());
if (!sc) {
PWRN("attempted to close non-existing session");
return;
}
_sessions.remove(sc);
destroy(_md_alloc, sc);
}
};
}
#endif

View File

@ -1,139 +0,0 @@
/*
* \brief Instance of the timer session interface
* \author Norman Feske
* \author Stefan Kalkowski
* \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 <base/rpc_server.h>
#include <timer_session/capability.h>
#include <os/attached_rom_dataspace.h>
/* Fiasco.OC includes */
namespace Fiasco {
#include <l4/sys/ipc.h>
#include <l4/sys/kip.h>
}
static Fiasco::l4_timeout_s mus_to_timeout(unsigned int mus)
{
using namespace Fiasco;
if (mus == 0)
return L4_IPC_TIMEOUT_0;
else if (mus == ~0UL)
return L4_IPC_TIMEOUT_NEVER;
long e = Genode::log2(mus) - 7;
unsigned long m;
if (e < 0) e = 0;
m = mus / (1UL << e);
/* check corner case */
if ((e > 31 ) || (m > 1023)) {
PWRN("invalid timeout %x, using max. values\n", mus);
e = 0;
m = 1023;
}
return l4_timeout_rel(m, e);
}
namespace Timer {
enum { STACK_SIZE = 1024 * sizeof(Genode::addr_t) };
/**
* Timer session
*/
class Session_component : public Genode::Rpc_object<Session>,
public Genode::List<Session_component>::Element
{
private:
Genode::Rpc_entrypoint _entrypoint;
Session_capability _session_cap;
Genode::Attached_rom_dataspace _kip_ds;
Fiasco::l4_kernel_info_t * const _kip;
Fiasco::l4_cpu_time_t const _initial_clock_value;
public:
/**
* Constructor
*/
Session_component(Genode::Cap_session *cap)
:
_entrypoint(cap, STACK_SIZE, "timer_session_ep"),
_session_cap(_entrypoint.manage(this)),
_kip_ds("l4v2_kip"),
_kip(_kip_ds.local_addr<Fiasco::l4_kernel_info_t>()),
_initial_clock_value(_kip->clock)
{ }
/**
* Destructor
*/
~Session_component()
{
_entrypoint.dissolve(this);
}
/**
* 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)
{
using namespace Fiasco;
l4_ipc_sleep(l4_timeout(L4_IPC_TIMEOUT_NEVER, mus_to_timeout(1000*ms)));
}
void usleep(unsigned us)
{
using namespace Fiasco;
l4_ipc_sleep(l4_timeout(L4_IPC_TIMEOUT_NEVER, mus_to_timeout(us)));
}
unsigned long elapsed_ms() const
{
return (_kip->clock - _initial_clock_value) / 1000;
}
};
}
#endif

View File

@ -14,10 +14,10 @@ SRC_CC += main.cc
REQUIRES += hw_pbxa9
# Add libraries
LIBS += cxx server env alarm
LIBS += cxx server env alarm signal
# Add include paths
INC_DIR += $(PRG_DIR) $(PRG_DIR)/../ $(PRG_DIR)/../../nova/
INC_DIR += $(PRG_DIR) $(PRG_DIR)/../ $(PRG_DIR)/../../include
# Declare source paths
vpath main.cc $(PRG_DIR)/../..

View File

@ -30,19 +30,21 @@ class Platform_timer : public Platform_timer_base,
enum { MAX_TIMER_IRQS_PER_MS = 1 };
unsigned long const _max_timeout_us; /* Maximum timeout in microsecs */
unsigned long _curr_time_us; /* Accumulate already measured timeouts */
unsigned long _init_value; /* Mark last processed timer value */
Genode::Lock _update_curr_time_lock; /* Serialize curr_time access */
unsigned long const _max_timeout_us; /* maximum timeout in microsecs */
unsigned long mutable _curr_time_us; /* accumulate already measured timeouts */
unsigned long mutable _init_value; /* mark last processed timer value */
Genode::Lock mutable _update_curr_time_lock; /* serialize curr_time access */
public:
/**
* Constructor
*/
Platform_timer() : Irq_connection(Platform_timer_base::IRQ),
_max_timeout_us(tics_to_us(max_value())),
_curr_time_us(0), _init_value(0)
Platform_timer()
:
Irq_connection(Platform_timer_base::IRQ),
_max_timeout_us(tics_to_us(max_value())),
_curr_time_us(0), _init_value(0)
{ }
/**
@ -51,22 +53,22 @@ class Platform_timer : public Platform_timer_base,
* This function has to be executed regulary,
* at least all max_timeout() us.
*/
unsigned long curr_time()
unsigned long curr_time() const
{
/* Serialize updates on timeout counter */
/* serialize updates on timeout counter */
Genode::Lock::Guard lock(_update_curr_time_lock);
/* Get time that passed since last time we've read the timer */
/* get time that passed since last time we've read the timer */
bool wrapped;
unsigned long const v = value(wrapped);
unsigned long passed_time;
if (wrapped) passed_time = _init_value + max_value() - v;
else passed_time = _init_value - v;
/* Update initial value for subsequent calculations */
/* update initial value for subsequent calculations */
_init_value = v;
/* Refresh our timeout counter and return it */
/* refresh our timeout counter and return it */
_curr_time_us += tics_to_us(passed_time);
return _curr_time_us;
}
@ -83,19 +85,23 @@ class Platform_timer : public Platform_timer_base,
*/
void schedule_timeout(unsigned long timeout_us)
{
/* Serialize updates on timeout counter */
/* serialize updates on timeout counter */
Genode::Lock::Guard lock(_update_curr_time_lock);
/* Constraint timout value with our maximum IRQ rate
* and the maximum possible timout */
/*
* Constrain timout value with our maximum IRQ rate and the maximum
* possible timeout.
*/
if (timeout_us < 1000/MAX_TIMER_IRQS_PER_MS)
timeout_us = 1000/MAX_TIMER_IRQS_PER_MS;
if (timeout_us > _max_timeout_us)
timeout_us = _max_timeout_us;
/* Once the timer runs, one can wait for the its IRQ and update our
/*
* Once the timer runs, one can wait for its IRQ and update our
* timeout counter through 'curr_time()' (We rely on the fact that
* this is done at least one time in every max-timeout period) */
* this is done at least one time in every max-timeout period)
*/
_init_value = us_to_tics(timeout_us);
run_and_wrap(_init_value);
}

View File

@ -14,10 +14,10 @@ SRC_CC += main.cc
REQUIRES += hw_vea9x4
# Add libraries
LIBS += cxx server env alarm
LIBS += cxx server env alarm signal
# Add include paths
INC_DIR += $(PRG_DIR)/../ $(PRG_DIR)/../pbxa9 $(PRG_DIR)/../../nova/
INC_DIR += $(PRG_DIR)/../ $(PRG_DIR)/../pbxa9 $(PRG_DIR)/../../include
# Declare source paths
vpath main.cc $(PRG_DIR)/../..

View File

@ -29,14 +29,14 @@ namespace Timer {
{
private:
Platform_timer _platform_timer;
Timeout_scheduler _timeout_scheduler;
Genode::Rpc_entrypoint *_entrypoint;
Platform_timer _platform_timer;
Timeout_scheduler _timeout_scheduler;
protected:
Session_component *_create_session(const char *args)
{
PLOG("args='%s'", args);
Genode::size_t ram_quota = Genode::Arg_string::find_arg(args, "ram_quota").ulong_value(0);
if (ram_quota < sizeof(Session_component)) {
@ -45,7 +45,7 @@ namespace Timer {
}
return new (md_alloc())
Session_component(&_timeout_scheduler, _entrypoint);
Session_component(_timeout_scheduler);
}
public:
@ -61,8 +61,7 @@ namespace Timer {
Genode::Cap_session *cap)
:
Genode::Root_component<Session_component>(session_ep, md_alloc),
_timeout_scheduler(&_platform_timer, session_ep),
_entrypoint(session_ep)
_timeout_scheduler(&_platform_timer, session_ep)
{ }
};
}

View File

@ -47,8 +47,8 @@ namespace Timer {
* we are able to answer those requests from here (by calling the
* 'handle()' function of the alarm scheduler).
*/
class Irq_dispatcher_component : public Genode::Rpc_object<Irq_dispatcher,
Irq_dispatcher_component>
class Irq_dispatcher_component : public Rpc_object<Irq_dispatcher,
Irq_dispatcher_component>
{
private:
@ -95,24 +95,21 @@ namespace Timer {
/**
* Alarm for answering a sleep request
* Alarm for answering an oneshot timeout request
*/
class Wake_up_alarm : public Genode::Alarm
{
private:
Genode::Native_capability _reply_cap;
Genode::Rpc_entrypoint *_entrypoint;
Signal_context_capability _sigh;
bool _periodic;
public:
Wake_up_alarm(Genode::Rpc_entrypoint *ep) : _entrypoint(ep) { }
Wake_up_alarm() : _periodic(false) { }
/**
* Set reply target to wake up when the alarm triggers
*/
void reply_cap(Genode::Native_capability reply_cap) {
_reply_cap = reply_cap; }
void sigh(Signal_context_capability sigh) { _sigh = sigh; }
void periodic(bool periodic) { _periodic = periodic; }
/*********************
@ -126,10 +123,9 @@ namespace Timer {
*/
bool on_alarm()
{
_entrypoint->explicit_reply(_reply_cap, 0);
Signal_transmitter(_sigh).submit();
/* do not re-schedule */
return 0;
return _periodic;
}
};
@ -184,42 +180,51 @@ namespace Timer {
}
/**
* Called from the 'msleep' function executed by the server activation
* Called from the '_trigger' function executed by the server activation
*/
void schedule_timeout(Genode::Alarm *alarm, Genode::Alarm::Time timeout)
{
Genode::Alarm::Time now = _platform_timer->curr_time();
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 Genode::Rpc_object<Session>,
public Genode::List<Session_component>::Element
class Session_component : public Rpc_object<Session>,
public List<Session_component>::Element
{
private:
Timeout_scheduler *_timeout_scheduler;
Genode::Rpc_entrypoint *_entrypoint;
Wake_up_alarm _wake_up_alarm;
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,
Genode::Rpc_entrypoint *ep)
Session_component(Timeout_scheduler &ts)
:
_timeout_scheduler(ts),
_entrypoint(ep),
_wake_up_alarm(ep)
_initial_time(_timeout_scheduler.curr_time())
{ }
/**
@ -227,7 +232,7 @@ namespace Timer {
*/
~Session_component()
{
_timeout_scheduler->discard(&_wake_up_alarm);
_timeout_scheduler.discard(&_wake_up_alarm);
}
@ -235,24 +240,29 @@ namespace Timer {
** Timer session interface **
*****************************/
void msleep(unsigned ms)
void trigger_once(unsigned us)
{
usleep(1000*ms);
_trigger(us, false);
}
void usleep(unsigned us)
void trigger_periodic(unsigned us)
{
_wake_up_alarm.reply_cap(_entrypoint->reply_dst());
_timeout_scheduler->schedule_timeout(&_wake_up_alarm, us);
/*
* Prevent the server activation from immediately answering the
* current call. The caller of 'msleep' will be unblocked via
* 'Rpc_entrypoint::explicit_reply' when its timeout alarm
* triggers.
*/
_entrypoint->omit_reply();
_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 */ }
};
}

View File

@ -22,9 +22,9 @@ class Platform_timer
{
private:
Genode::Lock _lock; /* for protecting '_next_timeout_usec' */
unsigned long _next_timeout_usec; /* timeout of current sleep */
unsigned long _curr_time_usec; /* accumulated sleep time */
Genode::Lock mutable _lock; /* for protecting '_next_timeout_usec' */
unsigned long _next_timeout_usec; /* timeout of current sleep */
unsigned long _curr_time_usec; /* accumulated sleep time */
/**
* Platform-specific sleep implementation
@ -38,7 +38,6 @@ class Platform_timer
*/
Platform_timer() : _next_timeout_usec(max_timeout()), _curr_time_usec(0) { }
/**
* Set next relative timeout
*/
@ -48,18 +47,15 @@ class Platform_timer
_next_timeout_usec = timeout_usec;
}
/**
* Return maximum supported timeout in microseconds
*/
unsigned long max_timeout();
/**
* Get current time in microseconds
*/
unsigned long curr_time();
unsigned long curr_time() const;
/**
* Block until the scheduled timeout triggers

View File

@ -61,9 +61,9 @@ class Platform_timer
Genode::Io_port_connection _io_port;
Genode::Irq_connection _timer_irq;
unsigned long _curr_time_usec;
unsigned long _counter_init_value;
Genode::Lock _update_curr_time_lock;
unsigned long mutable _curr_time_usec;
unsigned long mutable _counter_init_value;
Genode::Lock mutable _update_curr_time_lock;
/**
* Set PIT counter value
@ -117,15 +117,21 @@ class Platform_timer
* This function has to be executed regulary,
* at least all max_timeout() usecs.
*/
unsigned long curr_time()
unsigned long curr_time() const
{
Genode::Lock::Guard lock(_update_curr_time_lock);
unsigned long curr_counter, passed_ticks;
/* read PIT count and status */
/*
* Read PIT count and status
*
* Reading the PIT registers via port I/O is a non-const operation.
* Since 'curr_time' is declared as const, however, we need to
* explicitly override the const-ness of the 'this' pointer.
*/
bool wrapped;
curr_counter = _read_counter(&wrapped);
curr_counter = const_cast<Platform_timer *>(this)->_read_counter(&wrapped);
/* determine the time since we looked at the counter */
if (wrapped)

View File

@ -34,7 +34,7 @@ unsigned long Platform_timer::max_timeout()
}
unsigned long Platform_timer::curr_time()
unsigned long Platform_timer::curr_time() const
{
struct timeval tv;
lx_gettimeofday(&tv, 0);

View File

@ -1,7 +1,7 @@
TARGET = timer
SRC_CC = main.cc platform_timer.cc
REQUIRES = linux
LIBS = cxx server env alarm syscall
LIBS = cxx server env alarm syscall signal
INC_DIR += $(PRG_DIR)/../include $(PRG_DIR)/../include_periodic
vpath main.cc $(PRG_DIR)/..

View File

@ -1,8 +1,8 @@
TARGET = timer
SRC_CC = main.cc
REQUIRES = nova x86
LIBS = cxx server env alarm
LIBS = cxx server env alarm signal
INC_DIR = $(PRG_DIR) $(PRG_DIR)/../include_pit
INC_DIR = $(PRG_DIR)/../include $(PRG_DIR)/../include_pit
vpath main.cc $(PRG_DIR)/..

View File

@ -1,106 +0,0 @@
/*
* \brief Root interface to timer service
* \author Norman Feske
* \date 2006-08-15
*/
/*
* Copyright (C) 2006-2013 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 _TIMER_ROOT_H_
#define _TIMER_ROOT_H_
#include <util/arg_string.h>
#include <util/list.h>
#include <base/printf.h>
#include <base/rpc_server.h>
#include <root/root.h>
#include <cap_session/cap_session.h>
#include "timer_session_component.h"
namespace Timer {
class Root_component : public Genode::Rpc_object<Genode::Typed_root<Session> >
{
private:
Genode::Allocator *_md_alloc;
Platform_timer _platform_timer;
Timeout_scheduler _timeout_scheduler;
Genode::Cap_session *_cap_session;
Genode::Lock _sessions_lock;
Genode::List<Session_component> _sessions;
public:
/**
* Constructor
*/
Root_component(Genode::Rpc_entrypoint *session_ep,
Genode::Allocator *md_alloc,
Genode::Cap_session *cap)
:
_md_alloc(md_alloc),
_timeout_scheduler(&_platform_timer, session_ep), _cap_session(cap)
{ }
/********************
** Root interface **
********************/
Genode::Session_capability session(Root::Session_args const &args)
{
using namespace Genode;
if (!args.is_valid_string()) throw Invalid_args();
size_t ram_quota = Arg_string::find_arg(args.string(), "ram_quota").ulong_value(0);
size_t require = sizeof(Session_component) + STACK_SIZE;
if (ram_quota < require) {
PWRN("Insufficient donated ram_quota (%zd bytes), require %zd bytes",
ram_quota, require);
}
Lock::Guard guard(_sessions_lock);
/* create session object */
Session_component *sc = new (_md_alloc)
Session_component(&_timeout_scheduler, _cap_session);
_sessions.insert(sc);
return sc->cap();
}
void upgrade(Genode::Session_capability, Root::Upgrade_args const &) { }
void close(Genode::Session_capability session_cap)
{
Genode::Lock::Guard guard(_sessions_lock);
/*
* Lookup session-component by its capability by asking each
* entry point for object belonging to the capability. Only one
* entry point is expected to give the right answer.
*/
Session_component *sc = _sessions.first();
for (; sc && !sc->belongs_to(session_cap); sc = sc->next());
if (!sc) {
PWRN("attempted to close non-existing session");
return;
}
_sessions.remove(sc);
destroy(_md_alloc, sc);
}
};
}
#endif

View File

@ -1,204 +0,0 @@
/*
* \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

View File

@ -1,40 +0,0 @@
/*
* \brief Dummy platform-timer implementation
* \author Norman Feske
* \date 2009-11-19
*/
/*
* Copyright (C) 2009-2013 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.
*/
/* Genode includes */
#include <base/thread.h>
/* local includes */
#include "timer_session_component.h"
/* OKL4 includes */
namespace Okl4 { extern "C" {
#include <l4/schedule.h>
#include <l4/ipc.h>
} }
unsigned long Platform_timer::max_timeout() { return 1000; }
unsigned long Platform_timer::curr_time()
{
Genode::Lock::Guard lock_guard(_lock);
return _curr_time_usec;
}
void Platform_timer::_usleep(unsigned long usecs)
{
for (int i = 0; i < 10; i++)
Okl4::L4_Yield();
}

View File

@ -1,8 +0,0 @@
TARGET = timer
SRC_CC = main.cc platform_timer.cc
REQUIRES = okl4 arm
LIBS = cxx server env alarm
INC_DIR = $(PRG_DIR)/../include $(PRG_DIR)/../include_periodic
vpath main.cc $(PRG_DIR)/..

View File

@ -1,7 +1,7 @@
TARGET = timer
SRC_CC = main.cc
REQUIRES = okl4 x86
LIBS = cxx server env alarm
LIBS = cxx server env alarm signal
INC_DIR = $(PRG_DIR)/../include $(PRG_DIR)/../include_pit

View File

@ -30,7 +30,7 @@ unsigned long Platform_timer::max_timeout()
}
unsigned long Platform_timer::curr_time()
unsigned long Platform_timer::curr_time() const
{
Genode::Lock::Guard lock_guard(_lock);
return _curr_time_usec;

View File

@ -1,7 +1,7 @@
TARGET = timer
SRC_CC = main.cc platform_timer.cc
REQUIRES = pistachio
LIBS = cxx server env alarm
LIBS = cxx server env alarm signal
INC_DIR = $(PRG_DIR)/../include $(PRG_DIR)/../include_periodic

View File

@ -1,5 +1,5 @@
TARGET = nitpicker
LIBS = cxx env server blit
LIBS = cxx env server blit signal
SRC_CC = main.cc \
view_stack.cc \
view.cc \

View File

@ -1,3 +1,3 @@
TARGET = testnit
SRC_CC = test.cc
LIBS = cxx env
LIBS = cxx env signal

View File

@ -1,3 +1,3 @@
TARGET = test-timer
SRC_CC = main.cc
LIBS = cxx env thread
LIBS = cxx env thread signal

View File

@ -1,4 +1,5 @@
ldso
timer
lwip
rm_fault
rom_blk