timer: move to the new timeout framework

Ref #2170
This commit is contained in:
Martin Stein 2016-11-08 14:06:20 +01:00 committed by Christian Helmuth
parent 791138ee63
commit b85fa1d069
32 changed files with 988 additions and 1046 deletions

View File

@ -1,6 +1,5 @@
INC_DIR += $(REP_DIR)/src/drivers/timer/spec/periodic
SRC_CC += spec/periodic/time_source.cc spec/fiasco/time_source.cc
include $(REP_DIR)/lib/mk/timer.inc
INC_DIR += $(REP_DIR)/src/drivers/timer/include_periodic
SRC_CC += platform_timer.cc
vpath platform_timer.cc $(REP_DIR)/src/drivers/timer/spec/fiasco

View File

@ -1,6 +1,5 @@
INC_DIR += $(REP_DIR)/src/drivers/timer/spec/periodic
SRC_CC += spec/periodic/time_source.cc spec/fiasco/time_source.cc
include $(REP_DIR)/lib/mk/timer.inc
INC_DIR += $(REP_DIR)/src/drivers/timer/include_periodic
SRC_CC += platform_timer.cc
vpath platform_timer.cc $(REP_DIR)/src/drivers/timer/spec/fiasco

View File

@ -1,3 +1,5 @@
INC_DIR += $(REP_DIR)/src/drivers/timer/spec/hw
SRC_CC += spec/hw/time_source.cc
include $(REP_DIR)/lib/mk/timer.inc

View File

@ -1,8 +1,7 @@
include $(REP_DIR)/lib/mk/timer.inc
INC_DIR += $(REP_DIR)/src/drivers/timer/spec/periodic
INC_DIR += $(REP_DIR)/src/drivers/timer/include_periodic
SRC_CC += spec/periodic/time_source.cc spec/linux/time_source.cc
LIBS += syscall
SRC_CC += platform_timer.cc
vpath platform_timer.cc $(REP_DIR)/src/drivers/timer/spec/linux
include $(REP_DIR)/lib/mk/timer.inc

View File

@ -1,3 +1,5 @@
include $(REP_DIR)/lib/mk/timer.inc
INC_DIR += $(REP_DIR)/src/drivers/timer/spec/nova
SRC_CC += spec/nova/time_source.cc
include $(REP_DIR)/lib/mk/timer.inc

View File

@ -1,3 +1,5 @@
include $(REP_DIR)/lib/mk/timer.inc
INC_DIR += $(REP_DIR)/src/drivers/timer/spec/pit
INC_DIR += $(REP_DIR)/src/drivers/timer/include_pit
SRC_CC += spec/pit/time_source.cc
include $(REP_DIR)/lib/mk/timer.inc

View File

@ -1,6 +1,5 @@
INC_DIR += $(REP_DIR)/src/drivers/timer/spec/periodic
SRC_CC += spec/periodic/time_source.cc spec/pistachio/time_source.cc
include $(REP_DIR)/lib/mk/timer.inc
INC_DIR += $(REP_DIR)/src/drivers/timer/include_periodic
SRC_CC += platform_timer.cc
vpath platform_timer.cc $(REP_DIR)/src/drivers/timer/spec/pistachio

View File

@ -1,3 +1,5 @@
include $(REP_DIR)/lib/mk/timer.inc
INC_DIR += $(REP_DIR)/src/drivers/timer/spec/pit
INC_DIR += $(REP_DIR)/src/drivers/timer/include_pit
SRC_CC += spec/pit/time_source.cc
include $(REP_DIR)/lib/mk/timer.inc

View File

@ -1,5 +1,7 @@
SRC_CC += main.cc
LIBS += base alarm server
SRC_CC += main.cc
LIBS += base timeout
INC_DIR += $(REP_DIR)/src/drivers/timer/include
vpath main.cc $(REP_DIR)/src/drivers/timer
vpath %.cc $(REP_DIR)/src/drivers/timer

View File

@ -0,0 +1,62 @@
/*
* \brief Root interface to timer service
* \author Norman Feske
* \author Martin Stein
* \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 _ROOT_COMPONENT_H_
#define _ROOT_COMPONENT_H_
/* Genode includes */
#include <root/component.h>
/* local includes */
#include <time_source.h>
#include <session_component.h>
namespace Timer { class Root_component; }
class Timer::Root_component : public Genode::Root_component<Session_component>
{
private:
Time_source _time_source;
Genode::Alarm_timeout_scheduler _timeout_scheduler;
/********************
** Root_component **
********************/
Session_component *_create_session(const char *args)
{
using namespace Genode;
size_t const ram_quota =
Arg_string::find_arg(args, "ram_quota").ulong_value(0);
if (ram_quota < sizeof(Session_component)) {
throw Root::Quota_exceeded(); }
return new (md_alloc())
Session_component(_timeout_scheduler);
}
public:
Root_component(Genode::Entrypoint &ep, Genode::Allocator &md_alloc)
:
Genode::Root_component<Session_component>(&ep.rpc_ep(), &md_alloc),
_time_source(ep), _timeout_scheduler(_time_source)
{ }
};
#endif /* _ROOT_COMPONENT_H_ */

View File

@ -0,0 +1,69 @@
/*
* \brief Instance of the timer session interface
* \author Norman Feske
* \author Markus Partheymueller
* \author Martin Stein
* \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 _SESSION_COMPONENT_
#define _SESSION_COMPONENT_
/* Genode includes */
#include <util/list.h>
#include <timer_session/timer_session.h>
#include <base/rpc_server.h>
#include <os/timeout.h>
namespace Timer { class Session_component; }
class Timer::Session_component : public Genode::Rpc_object<Session>,
public Genode::List<Session_component>::Element,
private Genode::Timeout::Handler
{
private:
Genode::Timeout _timeout;
Genode::Timeout_scheduler &_timeout_scheduler;
Genode::Signal_context_capability _sigh;
unsigned long const _init_time_us = _timeout_scheduler.curr_time().value;
void handle_timeout(Microseconds) {
Genode::Signal_transmitter(_sigh).submit(); }
public:
Session_component(Genode::Timeout_scheduler &timeout_scheduler)
: _timeout(timeout_scheduler), _timeout_scheduler(timeout_scheduler) { }
/********************
** Timer::Session **
********************/
void trigger_once(unsigned us) override {
_timeout.schedule_one_shot(Microseconds(us), *this); }
void trigger_periodic(unsigned us) override {
_timeout.schedule_periodic(Microseconds(us), *this); }
void sigh(Signal_context_capability sigh) override { _sigh = sigh; }
unsigned long elapsed_ms() const override {
return (_timeout_scheduler.curr_time().value - _init_time_us) / 1000; }
void msleep(unsigned) override { /* never called at the server side */ }
void usleep(unsigned) override { /* never called at the server side */ }
};
#endif /* _SESSION_COMPONENT_ */

View File

@ -0,0 +1,49 @@
/*
* \brief Time source that handles timeouts via a signal handler
* \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 _SIGNALLED_TIME_SOURCE_H_
#define _SIGNALLED_TIME_SOURCE_H_
/* Genode includes */
#include <os/time_source.h>
#include <base/rpc_client.h>
#include <base/entrypoint.h>
namespace Genode { class Signalled_time_source; }
class Genode::Signalled_time_source : public Time_source
{
protected:
using Signal_handler = Genode::Signal_handler<Signalled_time_source>;
Signal_handler _signal_handler;
Timeout_handler *_handler = nullptr;
void _handle_timeout()
{
if (_handler) {
_handler->handle_timeout(curr_time()); }
}
public:
Signalled_time_source(Entrypoint &ep)
:
_signal_handler(ep, *this,
&Signalled_time_source::_handle_timeout)
{ }
};
#endif /* _SIGNALLED_TIME_SOURCE_H_ */

View File

@ -0,0 +1,89 @@
/*
* \brief Time source that uses an extra thread for timeout handling
* \author Norman Feske
* \author Martin Stein
* \date 2009-06-16
*/
/*
* Copyright (C) 2009-2015 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 _THREADED_TIME_SOURCE_H_
#define _THREADED_TIME_SOURCE_H_
/* Genode inludes */
#include <base/entrypoint.h>
#include <base/rpc_client.h>
#include <os/time_source.h>
namespace Timer {
enum { STACK_SIZE = 8 * 1024 * sizeof(Genode::addr_t) };
class Threaded_time_source;
}
class Timer::Threaded_time_source : public Genode::Time_source,
protected Genode::Thread_deprecated<STACK_SIZE>
{
private:
struct Irq_dispatcher
{
GENODE_RPC(Rpc_do_dispatch, void, do_dispatch, Microseconds);
GENODE_RPC_INTERFACE(Rpc_do_dispatch);
};
struct Irq_dispatcher_component : Genode::Rpc_object<Irq_dispatcher,
Irq_dispatcher_component>
{
Timeout_handler *handler = nullptr;
/********************
** Irq_dispatcher **
********************/
void do_dispatch(Microseconds duration)
{
if (handler) {
handler->handle_timeout(Microseconds(duration)); }
}
} _irq_dispatcher_component;
Genode::Capability<Irq_dispatcher> _irq_dispatcher_cap;
virtual void _wait_for_irq() = 0;
/***********************
** Thread_deprecated **
***********************/
void entry()
{
while (true) {
_wait_for_irq();
_irq_dispatcher_cap.call<Irq_dispatcher::Rpc_do_dispatch>(curr_time());
}
}
public:
Threaded_time_source(Genode::Entrypoint &ep)
:
Thread_deprecated<STACK_SIZE>("threaded_time_source"),
_irq_dispatcher_cap(ep.rpc_ep().manage(&_irq_dispatcher_component))
{ }
void handler(Timeout_handler &handler) {
_irq_dispatcher_component.handler = &handler; }
};
#endif /* _THREADED_TIME_SOURCE_H_ */

View File

@ -1,71 +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_
/* Genode includes */
#include <util/arg_string.h>
#include <base/printf.h>
#include <base/heap.h>
#include <root/component.h>
#include <cap_session/cap_session.h>
#include <os/server.h>
/* local includes */
#include "timer_session_component.h"
namespace Timer { class Root_component; }
class Timer::Root_component : public Genode::Root_component<Session_component>
{
private:
Platform_timer _platform_timer;
Timeout_scheduler _timeout_scheduler;
protected:
Session_component *_create_session(const char *args)
{
Genode::size_t ram_quota = Genode::Arg_string::find_arg(args, "ram_quota").ulong_value(0);
if (ram_quota < sizeof(Session_component)) {
PWRN("Insufficient donated ram_quota (%ld bytes), require %zd bytes",
ram_quota, sizeof(Session_component));
}
return new (md_alloc())
Session_component(_timeout_scheduler);
}
public:
/**
* Constructor
*
* The 'cap' argument is not used by the single-threaded server
* variant.
*/
Root_component(Server::Entrypoint &ep,
Genode::Allocator *md_alloc,
Genode::Cap_session *cap)
:
Genode::Root_component<Session_component>(&ep.rpc_ep(), md_alloc),
_timeout_scheduler(&_platform_timer, &ep.rpc_ep())
{ }
};
#endif

View File

@ -1,282 +0,0 @@
/*
* \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;
class Irq_dispatcher_component;
class Wake_up_alarm;
class Timeout_scheduler;
class Session_component;
}
struct Timer::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 Timer::Irq_dispatcher_component : public Genode::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 Timer::Wake_up_alarm : public Genode::Alarm
{
private:
Genode::Signal_context_capability _sigh;
bool _periodic;
public:
Wake_up_alarm() : _periodic(false) { }
void sigh(Genode::Signal_context_capability sigh) { _sigh = sigh; }
void periodic(bool periodic) { _periodic = periodic; }
bool periodic() { return _periodic; }
/*********************
** Alarm interface **
*********************/
/**
* Dispatch a wakeup alarm
*
* This function gets called by the 'Alarm_scheduler' thread.
*/
bool on_alarm (unsigned cnt) override
{
Genode::Signal_transmitter(_sigh).submit(cnt);
return _periodic;
}
};
class Timer::Timeout_scheduler : public Genode::Alarm_scheduler,
Genode::Thread_deprecated<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)
:
Thread_deprecated("timeout_scheduler"),
_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(Wake_up_alarm *alarm, Genode::Alarm::Time timeout)
{
Genode::Alarm::Time now = _platform_timer->curr_time();
if (alarm->periodic()) {
handle(now); /* update '_now' in 'Alarm_scheduler' */
schedule(alarm, timeout);
} else schedule_absolute(alarm, now + timeout);
/* interrupt current 'wait_for_timeout' */
if (head_timeout(alarm))
_platform_timer->schedule_timeout(0);
}
unsigned long curr_time() const
{
return _platform_timer->curr_time();
}
};
/**
* Timer session
*/
class Timer::Session_component : public Genode::Rpc_object<Session>,
public Genode::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) / 1000;
}
void msleep(unsigned) { /* never called at the server side */ }
void usleep(unsigned) { /* never called at the server side */ }
};
#endif

View File

@ -1,91 +0,0 @@
/*
* \brief Platform timer based on spinning usleep
* \author Norman Feske
* \date 2009-06-16
*/
/*
* Copyright (C) 2009-2015 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 _PLATFORM_TIMER_H_
#define _PLATFORM_TIMER_H_
/* Genode inludes */
#include <base/thread.h>
#include <os/server.h>
class Platform_timer
{
private:
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
*/
void _usleep(unsigned long usecs);
public:
/**
* Constructor
*/
Platform_timer() : _next_timeout_usec(max_timeout()), _curr_time_usec(0) { }
/**
* Set next relative timeout
*/
void schedule_timeout(unsigned long timeout_usec)
{
Genode::Lock::Guard lock_guard(_lock);
_next_timeout_usec = timeout_usec;
}
/**
* Return maximum supported timeout in microseconds
*/
unsigned long max_timeout();
/**
* Get current time in microseconds
*/
unsigned long curr_time() const;
/**
* Block until the scheduled timeout triggers
*/
void wait_for_timeout(Genode::Thread *blocking_thread)
{
enum { SLEEP_GRANULARITY_USEC = 1000UL };
unsigned long last_time = curr_time();
_lock.lock();
while (_next_timeout_usec) {
_lock.unlock();
try { _usleep(SLEEP_GRANULARITY_USEC); }
catch (Genode::Blocking_canceled) { }
unsigned long now_time = curr_time();
unsigned long sleep_duration = now_time - last_time;
last_time = now_time;
_lock.lock();
if (_next_timeout_usec >= sleep_duration)
_next_timeout_usec -= sleep_duration;
else
break;
}
_lock.unlock();
}
};
#endif /* _PLATFORM_TIMER_H_ */

View File

@ -1,205 +0,0 @@
/*
* \brief Platform timer based on the Programmable Interval Timer (PIT)
* \author Norman Feske
* \date 2009-06-16
*/
/*
* Copyright (C) 2009-2015 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 _PLATFORM_TIMER_H_
#define _PLATFORM_TIMER_H_
/* Genode includes */
#include <io_port_session/connection.h>
#include <irq_session/connection.h>
#include <os/server.h>
class Platform_timer
{
private:
enum {
PIT_TICKS_PER_SECOND = 1193182,
PIT_TICKS_PER_MSEC = PIT_TICKS_PER_SECOND/1000,
PIT_MAX_COUNT = 65535,
PIT_DATA_PORT_0 = 0x40, /* data port for PIT channel 0,
connected to the PIC */
PIT_CMD_PORT = 0x43, /* PIT command port */
PIT_MAX_USEC = (PIT_MAX_COUNT*1000)/(PIT_TICKS_PER_MSEC)
};
enum {
IRQ_PIT = 0, /* timer interrupt at the PIC */
};
/**
* Bit definitions for accessing the PIT command port
*/
enum {
PIT_CMD_SELECT_CHANNEL_0 = 0 << 6,
PIT_CMD_ACCESS_LO = 1 << 4,
PIT_CMD_ACCESS_LO_HI = 3 << 4,
PIT_CMD_MODE_IRQ = 0 << 1,
PIT_CMD_MODE_RATE = 2 << 1,
PIT_CMD_READ_BACK = 3 << 6,
PIT_CMD_RB_COUNT = 0 << 5,
PIT_CMD_RB_STATUS = 0 << 4,
PIT_CMD_RB_CHANNEL_0 = 1 << 1,
};
/**
* Bit definitions of the PIT status byte
*/
enum {
PIT_STAT_INT_LINE = 1 << 7,
};
Genode::Io_port_connection _io_port;
Genode::Irq_connection _timer_irq;
unsigned long mutable _curr_time_usec;
Genode::uint16_t mutable _counter_init_value;
bool mutable _handled_wrap;
Genode::Signal_receiver _irq_rec;
Genode::Signal_context _irq_ctx;
/**
* Set PIT counter value
*/
void _set_counter(Genode::uint16_t value)
{
_handled_wrap = false;
_io_port.outb(PIT_DATA_PORT_0, value & 0xff);
_io_port.outb(PIT_DATA_PORT_0, (value >> 8) & 0xff);
}
/**
* Read current PIT counter value
*/
Genode::uint16_t _read_counter(bool *wrapped)
{
/* read-back count and status of counter 0 */
_io_port.outb(PIT_CMD_PORT, PIT_CMD_READ_BACK |
PIT_CMD_RB_COUNT | PIT_CMD_RB_STATUS | PIT_CMD_RB_CHANNEL_0);
/* read status byte from latch register */
Genode::uint8_t status = _io_port.inb(PIT_DATA_PORT_0);
/* read low and high bytes from latch register */
Genode::uint16_t lo = _io_port.inb(PIT_DATA_PORT_0);
Genode::uint16_t hi = _io_port.inb(PIT_DATA_PORT_0);
*wrapped = status & PIT_STAT_INT_LINE ? true : false;
return (hi << 8) | lo;
}
public:
/**
* Constructor
*/
Platform_timer()
:
_io_port(PIT_DATA_PORT_0, PIT_CMD_PORT - PIT_DATA_PORT_0 + 1),
_timer_irq(IRQ_PIT),
_curr_time_usec(0),
_counter_init_value(0),
_handled_wrap(false)
{
/* operate PIT in one-shot mode */
_io_port.outb(PIT_CMD_PORT, PIT_CMD_SELECT_CHANNEL_0 |
PIT_CMD_ACCESS_LO_HI | PIT_CMD_MODE_IRQ);
_timer_irq.sigh(_irq_rec.manage(&_irq_ctx));
_timer_irq.ack_irq();
}
~Platform_timer() { _irq_rec.dissolve(&_irq_ctx); }
/**
* Return current time-counter value in microseconds
*
* This function has to be executed regularly,
* at least all max_timeout() usecs.
*/
unsigned long curr_time() const
{
Genode::uint32_t passed_ticks;
/*
* 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;
Genode::uint16_t const curr_counter = const_cast<Platform_timer *>(this)->_read_counter(&wrapped);
/* determine the time since we looked at the counter */
if (wrapped && !_handled_wrap) {
passed_ticks = _counter_init_value;
/* the counter really wrapped around */
if (curr_counter)
passed_ticks += PIT_MAX_COUNT + 1 - curr_counter;
_handled_wrap = true;
} else {
if (_counter_init_value)
passed_ticks = _counter_init_value - curr_counter;
else
passed_ticks = PIT_MAX_COUNT + 1 - curr_counter;
}
_curr_time_usec += (passed_ticks*1000)/PIT_TICKS_PER_MSEC;
/* use current counter as the reference for the next update */
_counter_init_value = curr_counter;
return _curr_time_usec;
}
/**
* Return maximum timeout as supported by the platform
*/
unsigned long max_timeout() { return PIT_MAX_USEC; }
/**
* Schedule next timeout
*
* \param timeout_usec timeout in microseconds
*
* The maximum value for 'timeout_ms' is 54924 microseconds. If
* specifying a higher timeout, this maximum value will be scheduled.
*/
void schedule_timeout(unsigned long timeout_usec)
{
/* limit timer-interrupt rate */
enum { MAX_TIMER_IRQS_PER_SECOND = 4*1000 };
if (timeout_usec < 1000*1000/MAX_TIMER_IRQS_PER_SECOND)
timeout_usec = 1000*1000/MAX_TIMER_IRQS_PER_SECOND;
if (timeout_usec > max_timeout())
timeout_usec = max_timeout();
_counter_init_value = (PIT_TICKS_PER_MSEC * timeout_usec)/1000;
_set_counter(_counter_init_value);
}
/**
* Block for the next scheduled timeout
*/
void wait_for_timeout(Genode::Thread *blocking_thread)
{
_irq_rec.wait_for_signal();
_timer_irq.ack_irq();
}
};
#endif /* _PLATFORM_TIMER_H_ */

View File

@ -1,6 +1,7 @@
/*
* \brief Timer service
* \brief Provides the Timer service to multiple clients
* \author Norman Feske
* \author Martin Stein
* \date 2006-08-15
*/
@ -12,45 +13,35 @@
*/
/* Genode includes */
#include <base/env.h>
#include <base/sleep.h>
#include <base/heap.h>
#include <cap_session/connection.h>
#include <os/server.h>
#include <base/component.h>
/* local includes */
#include "timer_root.h"
#include <root_component.h>
using namespace Genode;
using namespace Timer;
struct Main
class Main
{
Server::Entrypoint &ep;
Sliced_heap sliced_heap;
Timer::Root_component root;
private:
Main(Server::Entrypoint &ep)
:
ep(ep),
sliced_heap(Genode::env()->ram_session(), Genode::env()->rm_session()),
root(ep, &sliced_heap, 0)
{
/*
* Announce timer service at our parent.
*/
env()->parent()->announce(ep.manage(root));
}
Sliced_heap _sliced_heap;
Timer::Root_component _root;
public:
Main(Env &env) : _sliced_heap(env.ram(), env.rm()),
_root(env.ep(), _sliced_heap)
{
env.parent().announce(env.ep().manage(_root));
}
};
/************
** Server **
************/
/***************
** Component **
***************/
namespace Server {
char const *name() { return "timer_drv_ep"; }
size_t stack_size() { return 2048*sizeof(long); }
void construct(Entrypoint &ep) { static Main server(ep); }
}
size_t Component::stack_size() { return 2 * 1024 * sizeof(addr_t); }
void Component::construct(Env &env) { static Main main(env); }

View File

@ -1,7 +1,8 @@
/*
* \brief Fiasco-specific sleep implementation
* \brief Time source that uses sleeping by the means of the kernel
* \author Christian Helmuth
* \author Norman Feske
* \author Martin Stein
* \date 2006-08-30
*/
@ -14,7 +15,6 @@
/* Genode includes */
#include <util/misc_math.h>
#include <base/printf.h>
#include <os/attached_rom_dataspace.h>
/* Fiasco includes */
@ -36,9 +36,10 @@ namespace Fiasco {
#endif /* L4_SYS_KIP_H__ */
/* local includes */
#include "timer_session_component.h"
#include <time_source.h>
using namespace Fiasco;
using Microseconds = Genode::Time_source::Microseconds;
static l4_timeout_s mus_to_timeout(unsigned long mus)
@ -50,42 +51,36 @@ static l4_timeout_s mus_to_timeout(unsigned long mus)
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 %ld, using max. values\n", mus);
Genode::warning("invalid timeout ", mus, ", using max. values");
e = 0;
m = 1023;
}
return l4_timeout_rel(m, e);
}
unsigned long Platform_timer::max_timeout()
Microseconds Timer::Time_source::max_timeout() const
{
Genode::Lock::Guard lock_guard(_lock);
return 1000*1000*100;
return Microseconds(1000 * 1000 * 100);
}
unsigned long Platform_timer::curr_time() const
Microseconds Timer::Time_source::curr_time() const
{
Genode::Lock::Guard lock_guard(_lock);
static Genode::Attached_rom_dataspace kip_ds("l4v2_kip");
static Genode::Attached_rom_dataspace kip_ds("l4v2_kip");
static Fiasco::l4_kernel_info_t * const kip =
kip_ds.local_addr<Fiasco::l4_kernel_info_t>();
return kip->clock;
return Microseconds(kip->clock);
}
void Platform_timer::_usleep(unsigned long usecs)
{
l4_ipc_sleep(l4_timeout(L4_IPC_TIMEOUT_NEVER, mus_to_timeout(usecs)));
}
void Timer::Time_source::_usleep(unsigned long usecs) {
l4_ipc_sleep(l4_timeout(L4_IPC_TIMEOUT_NEVER, mus_to_timeout(usecs))); }

View File

@ -1,125 +0,0 @@
/*
* \brief Platform timer specific for base-hw
* \author Martin Stein
* \date 2012-05-03
*/
/*
* Copyright (C) 2012-2015 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__SRC__DRIVERS__TIMER__HW__PLATFORM_TIMER_H_
#define _OS__SRC__DRIVERS__TIMER__HW__PLATFORM_TIMER_H_
/* Genode includes */
#include <base/signal.h>
#include <os/server.h>
/* base-hw includes */
#include <kernel/interface.h>
/**
* Platform timer specific for base-hw
*/
class Platform_timer
{
private:
using time_t = Kernel::time_t;
Genode::Signal_receiver _sigrec;
Genode::Signal_context _sigctx;
Kernel::capid_t const _sigid;
unsigned long mutable _curr_time_us;
Genode::Lock mutable _curr_time_us_lock;
unsigned long mutable _last_timeout_age_us;
time_t const _max_timeout_us;
/**
* Return kernel capability selector of Genode capability
*
* This function is normally framework-internal and defined in
* 'base/internal/capability_space.h'.
*/
static inline Kernel::capid_t _capid(Genode::Native_capability const &cap)
{
Genode::addr_t const index = (Genode::addr_t)cap.data();
return index;
}
public:
Platform_timer()
:
_sigid(_capid(_sigrec.manage(&_sigctx))),
_curr_time_us(0), _last_timeout_age_us(0),
_max_timeout_us(Kernel::timeout_max_us())
{
Genode::log("maximum timeout ", _max_timeout_us, " us");
if (max_timeout() < min_timeout()) {
Genode::error("minimum timeout greater then maximum timeout");
throw Genode::Exception();
}
}
~Platform_timer() { _sigrec.dissolve(&_sigctx); }
/**
* Refresh and return time in microseconds
*
* This function has to be executed regulary, at least all
* max_timeout() us.
*/
unsigned long curr_time() const
{
Genode::Lock::Guard lock(_curr_time_us_lock);
time_t const timeout_age_us = Kernel::timeout_age_us();
if (timeout_age_us > _last_timeout_age_us) {
/* increment time by the difference since the last update */
_curr_time_us += timeout_age_us - _last_timeout_age_us;
_last_timeout_age_us = timeout_age_us;
}
return _curr_time_us;
}
/**
* Return maximum timeout in microseconds
*/
time_t max_timeout() const { return _max_timeout_us; }
/**
* Return minimum timeout in microseconds
*/
static time_t min_timeout() { return 1000; }
/**
* Schedule next timeout, bad timeouts are adapted
*
* \param timeout_us Timeout in microseconds
*/
void schedule_timeout(time_t timeout_us)
{
Genode::Lock::Guard lock(_curr_time_us_lock);
if (timeout_us < min_timeout()) { timeout_us = min_timeout(); }
if (timeout_us > max_timeout()) { timeout_us = max_timeout(); }
/*
* Once the timer runs, one can wait for its signal 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)
*/
_last_timeout_age_us = 0;
Kernel::timeout(timeout_us, _sigid);
}
/**
* Await the lastly scheduled timeout
*/
void wait_for_timeout(Genode::Thread *) { _sigrec.wait_for_signal(); }
};
#endif /* _OS__SRC__DRIVERS__TIMER__HW__PLATFORM_TIMER_H_ */

View File

@ -0,0 +1,69 @@
/*
* \brief Time source that uses the timeout syscalls of the HW kernel
* \author Martin Stein
* \date 2012-05-03
*/
/*
* Copyright (C) 2012-2015 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/log.h>
#include <base/signal.h>
#include <base/entrypoint.h>
/* local includes */
#include <time_source.h>
/* base-hw includes */
#include <kernel/interface.h>
using namespace Genode;
using Microseconds = Genode::Time_source::Microseconds;
enum { MIN_TIMEOUT_US = 1000 };
Timer::Time_source::Time_source(Entrypoint &ep)
:
Signalled_time_source(ep),
_max_timeout_us(Kernel::timeout_max_us())
{
if (_max_timeout_us < MIN_TIMEOUT_US) {
error("minimum timeout greater then maximum timeout");
throw Genode::Exception();
}
}
void Timer::Time_source::schedule_timeout(Microseconds duration,
Timeout_handler &handler)
{
unsigned long duration_us = duration.value;
if (duration_us < MIN_TIMEOUT_US) {
duration_us = MIN_TIMEOUT_US; }
if (duration_us > max_timeout().value) {
duration_us = max_timeout().value; }
_handler = &handler;
_last_timeout_age_us = 0;
Kernel::timeout(duration_us, (addr_t)_signal_handler.data());
}
Microseconds Timer::Time_source::curr_time() const
{
unsigned long const timeout_age_us = Kernel::timeout_age_us();
if (timeout_age_us > _last_timeout_age_us) {
/* increment time by the difference since the last update */
_curr_time_us += timeout_age_us - _last_timeout_age_us;
_last_timeout_age_us = timeout_age_us;
}
return Microseconds(_curr_time_us);
}

View File

@ -0,0 +1,46 @@
/*
* \brief Time source that uses the timeout syscalls of the HW kernel
* \author Martin Stein
* \date 2012-05-03
*/
/*
* Copyright (C) 2012-2015 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 _TIME_SOURCE_H_
#define _TIME_SOURCE_H_
/* local includes */
#include <signalled_time_source.h>
namespace Timer { class Time_source; }
class Timer::Time_source : public Genode::Signalled_time_source
{
private:
unsigned long mutable _curr_time_us = 0;
unsigned long mutable _last_timeout_age_us = 0;
unsigned long const _max_timeout_us;
public:
Time_source(Genode::Entrypoint &ep);
/*************************
** Genode::Time_source **
*************************/
Microseconds curr_time() const override;
void schedule_timeout(Microseconds duration, Timeout_handler &handler) override;
Microseconds max_timeout() const override {
return Microseconds(_max_timeout_us); };
};
#endif /* _TIME_SOURCE_H_ */

View File

@ -1,53 +0,0 @@
/*
* \brief Linux-specific sleep implementation
* \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.
*/
/* Linux syscall bindings */
#include <linux_syscalls.h>
/* local includes */
#include "timer_session_component.h"
/* Linux includes */
#include <linux_syscalls.h>
#include <sys/time.h>
inline int lx_gettimeofday(struct timeval *tv, struct timeval *tz)
{
return lx_syscall(SYS_gettimeofday, tv, tz);
}
unsigned long Platform_timer::max_timeout()
{
Genode::Lock::Guard lock_guard(_lock);
return 1000*1000;
}
unsigned long Platform_timer::curr_time() const
{
struct timeval tv;
lx_gettimeofday(&tv, 0);
return tv.tv_sec*1000*1000 + tv.tv_usec;
}
void Platform_timer::_usleep(unsigned long usecs)
{
struct timespec ts;
ts.tv_sec = usecs / (1000*1000);
ts.tv_nsec = (usecs % (1000*1000)) * 1000;
if (lx_nanosleep(&ts, &ts) != 0)
throw Genode::Blocking_canceled();
}

View File

@ -0,0 +1,53 @@
/*
* \brief Time source that uses sleeping by the means of the kernel
* \author Norman Feske
* \author Martin Stein
* \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.
*/
/* Linux includes */
#include <linux_syscalls.h>
#include <sys/time.h>
/* local includes */
#include <time_source.h>
using namespace Genode;
using Microseconds = Genode::Time_source::Microseconds;
inline int lx_gettimeofday(struct timeval *tv, struct timeval *tz) {
return lx_syscall(SYS_gettimeofday, tv, tz); }
Microseconds Timer::Time_source::max_timeout() const
{
Lock::Guard lock_guard(_lock);
return Microseconds(1000 * 1000);
}
Microseconds Timer::Time_source::curr_time() const
{
struct timeval tv;
lx_gettimeofday(&tv, 0);
return Microseconds(tv.tv_sec * 1000 * 1000 + tv.tv_usec);
}
void Timer::Time_source::_usleep(unsigned long us)
{
struct timespec ts;
ts.tv_sec = us / (1000 * 1000);
ts.tv_nsec = (us % (1000 * 1000)) * 1000;
if (lx_nanosleep(&ts, &ts) != 0)
throw Blocking_canceled();
}

View File

@ -1,132 +0,0 @@
/*
* \brief Platform timer using Nova timed semaphore down
* \author Alexander Boettcher
* \date 2014-06-24
*/
/*
* Copyright (C) 2014-2015 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 _PLATFORM_TIMER_H_
#define _PLATFORM_TIMER_H_
/* Genode includes */
#include <os/attached_rom_dataspace.h>
#include <os/server.h>
#include <trace/timestamp.h>
/* NOVA includes */
#include <nova/native_thread.h>
class Platform_timer
{
private:
Genode::addr_t _sem;
unsigned long _timeout;
Genode::Trace::Timestamp _tsc_start;
unsigned long _tsc_khz;
/* 1 / ((us / (1000 * 1000)) * (tsc_khz * 1000)) */
enum { TSC_FACTOR = 1000ULL };
/**
* Convenience function to calculate time in us value out of tsc
*/
inline unsigned long _time_in_us(unsigned long long tsc,
bool sub_tsc_start = true) const
{
if (sub_tsc_start)
return (tsc - _tsc_start) / (_tsc_khz / TSC_FACTOR);
return (tsc) / (_tsc_khz / TSC_FACTOR);
}
public:
/**
* Constructor
*/
Platform_timer()
:
_sem(~0UL), _timeout(0),
_tsc_start(Genode::Trace::timestamp())
{
/* read out the tsc frequenzy once */
Genode::Attached_rom_dataspace _ds("hypervisor_info_page");
Nova::Hip * const hip = _ds.local_addr<Nova::Hip>();
_tsc_khz = hip->tsc_freq;
}
/**
* Return current time-counter value in microseconds
*/
unsigned long curr_time() const
{
return _time_in_us(Genode::Trace::timestamp());
}
/**
* Return maximum timeout as supported by the platform
*/
unsigned long max_timeout() { return _time_in_us(~0UL); }
/**
* Schedule next timeout
*
* \param timeout_usec timeout in microseconds
*/
void schedule_timeout(unsigned long timeout_usec)
{
using namespace Genode;
/* check whether to cancel last timeout */
if (timeout_usec == 0 && _sem != ~0UL) {
uint8_t res = Nova::sm_ctrl(_sem, Nova::SEMAPHORE_UP);
if (res != Nova::NOVA_OK)
nova_die();
}
/* remember timeout to be set during wait_for_timeout call */
_timeout = timeout_usec;
}
/**
* Block for the next scheduled timeout
*/
void wait_for_timeout(Genode::Thread *blocking_thread)
{
using namespace Genode;
using namespace Nova;
if (_sem == ~0UL)
_sem = blocking_thread->native_thread().exc_pt_sel + SM_SEL_EC;
addr_t sem = _sem;
/* calculate absolute timeout */
Trace::Timestamp now = Trace::timestamp();
Trace::Timestamp us_64 = _timeout;
if (_timeout == max_timeout()) {
/* tsc_absolute == 0 means blocking without timeout */
Genode::uint8_t res = sm_ctrl(sem, SEMAPHORE_DOWN, 0);
if (res != Nova::NOVA_OK && res != Nova::NOVA_TIMEOUT)
nova_die();
return;
}
/* block until timeout fires or it gets canceled */
unsigned long long tsc_absolute = now + us_64 * (_tsc_khz / TSC_FACTOR);
Genode::uint8_t res = sm_ctrl(sem, SEMAPHORE_DOWN, tsc_absolute);
if (res != Nova::NOVA_OK && res != Nova::NOVA_TIMEOUT)
nova_die();
}
};
#endif /* _PLATFORM_TIMER_H_ */

View File

@ -0,0 +1,81 @@
/*
* \brief Time source using Nova timed semaphore down
* \author Alexander Boettcher
* \author Martin Stein
* \date 2014-06-24
*/
/*
* Copyright (C) 2014-2015 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 <os/attached_rom_dataspace.h>
/* NOVA includes */
#include <nova/native_thread.h>
/* local includes */
#include <time_source.h>
using namespace Genode;
using namespace Nova;
using Microseconds = Genode::Time_source::Microseconds;
Timer::Time_source::Time_source(Entrypoint &ep) : Threaded_time_source(ep)
{
/* read out the tsc frequenzy once */
Attached_rom_dataspace _ds("hypervisor_info_page");
Nova::Hip * const hip = _ds.local_addr<Nova::Hip>();
_tsc_khz = hip->tsc_freq;
start();
}
void Timer::Time_source::schedule_timeout(Microseconds duration,
Timeout_handler &handler)
{
Threaded_time_source::handler(handler);
/* check whether to cancel last timeout */
if (duration.value == 0 && _sem != ~0UL) {
uint8_t res = Nova::sm_ctrl(_sem, Nova::SEMAPHORE_UP);
if (res != Nova::NOVA_OK)
nova_die();
}
/* remember timeout to be set during wait_for_timeout call */
_timeout_us = duration.value;
}
void Timer::Time_source::_wait_for_irq()
{
if (_sem == ~0UL) {
_sem = Thread::native_thread().exc_pt_sel + SM_SEL_EC; }
addr_t sem = _sem;
/* calculate absolute timeout */
Trace::Timestamp now = Trace::timestamp();
Trace::Timestamp us_64 = _timeout_us;
if (_timeout_us == max_timeout().value) {
/* tsc_absolute == 0 means blocking without timeout */
uint8_t res = sm_ctrl(sem, SEMAPHORE_DOWN, 0);
if (res != Nova::NOVA_OK && res != Nova::NOVA_TIMEOUT) {
nova_die(); }
} else {
/* block until timeout fires or it gets canceled */
unsigned long long tsc_absolute = now + us_64 * (_tsc_khz / TSC_FACTOR);
uint8_t res = sm_ctrl(sem, SEMAPHORE_DOWN, tsc_absolute);
if (res != Nova::NOVA_OK && res != Nova::NOVA_TIMEOUT) {
nova_die(); }
}
}

View File

@ -0,0 +1,71 @@
/*
* \brief Time source using Nova timed semaphore down
* \author Alexander Boettcher
* \author Martin Stein
* \date 2014-06-24
*/
/*
* Copyright (C) 2014-2015 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 _TIME_SOURCE_H_
#define _TIME_SOURCE_H_
/* Genode includes */
#include <trace/timestamp.h>
/* local includes */
#include <threaded_time_source.h>
namespace Timer { class Time_source; }
class Timer::Time_source : public Threaded_time_source
{
private:
Genode::addr_t _sem = ~0UL;
unsigned long _timeout_us = 0;
Genode::Trace::Timestamp _tsc_start = Genode::Trace::timestamp();
unsigned long _tsc_khz;
/* 1 / ((us / (1000 * 1000)) * (tsc_khz * 1000)) */
enum { TSC_FACTOR = 1000ULL };
inline Microseconds _tsc_to_us(unsigned long long tsc,
bool sub_tsc_start = true) const
{
if (sub_tsc_start) {
return Microseconds((tsc - _tsc_start) /
(_tsc_khz / TSC_FACTOR));
}
return Microseconds((tsc) / (_tsc_khz / TSC_FACTOR));
}
/**************************
** Threaded_time_source **
**************************/
void _wait_for_irq();
public:
Time_source(Genode::Entrypoint &ep);
/*************************
** Genode::Time_source **
*************************/
Microseconds max_timeout() const override { return _tsc_to_us(~0UL); }
void schedule_timeout(Microseconds duration, Timeout_handler &handler) override;
Microseconds curr_time() const override {
return _tsc_to_us(Genode::Trace::timestamp()); }
};
#endif /* _TIME_SOURCE_H_ */

View File

@ -0,0 +1,52 @@
/*
* \brief Time source that uses sleeping by the means of the kernel
* \author Norman Feske
* \author Martin Stein
* \date 2009-06-16
*/
/*
* Copyright (C) 2009-2015 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.
*/
/* local includes */
#include <time_source.h>
using namespace Genode;
void Timer::Time_source::schedule_timeout(Microseconds duration,
Timeout_handler &handler)
{
Genode::Lock::Guard lock_guard(_lock);
Threaded_time_source::handler(handler);
_next_timeout_us = duration.value;
}
void Timer::Time_source::_wait_for_irq()
{
enum { SLEEP_GRANULARITY_US = 1000UL };
unsigned long last_time_us = curr_time().value;
_lock.lock();
while (_next_timeout_us > 0) {
_lock.unlock();
try { _usleep(SLEEP_GRANULARITY_US); }
catch (Blocking_canceled) { }
unsigned long curr_time_us = curr_time().value;
unsigned long sleep_duration_us = curr_time_us - last_time_us;
last_time_us = curr_time_us;
_lock.lock();
if (_next_timeout_us >= sleep_duration_us)
_next_timeout_us -= sleep_duration_us;
else
break;
}
_lock.unlock();
}

View File

@ -0,0 +1,56 @@
/*
* \brief Time source that uses sleeping by the means of the kernel
* \author Norman Feske
* \author Martin Stein
* \date 2009-06-16
*/
/*
* Copyright (C) 2009-2015 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 _TIME_SOURCE_H_
#define _TIME_SOURCE_H_
/* local includes */
#include <threaded_time_source.h>
namespace Timer { class Time_source; }
class Timer::Time_source : public Threaded_time_source
{
private:
Genode::Lock mutable _lock;
unsigned long _curr_time_us = 0;
unsigned long _next_timeout_us = max_timeout().value;
void _usleep(unsigned long us);
/**************************
** Threaded_time_source **
**************************/
void _wait_for_irq();
public:
Time_source(Genode::Entrypoint &ep) : Threaded_time_source(ep) {
start(); }
/*************************
** Genode::Time_source **
*************************/
Microseconds curr_time() const override;
Microseconds max_timeout() const override;
void schedule_timeout(Microseconds duration, Timeout_handler &handler) override;
};
#endif /* _TIME_SOURCE_H_ */

View File

@ -1,6 +1,7 @@
/*
* \brief Pistachio-specific sleep implementation
* \brief Time source that uses sleeping by the means of the kernel
* \author Julian Stecklina
* \author Martin Stein
* \date 2008-03-19
*/
@ -20,34 +21,37 @@ namespace Pistachio {
}
/* local includes */
#include "timer_session_component.h"
#include <time_source.h>
using namespace Genode;
using Microseconds = Genode::Time_source::Microseconds;
unsigned long Platform_timer::max_timeout()
Microseconds Timer::Time_source::max_timeout() const
{
Genode::Lock::Guard lock_guard(_lock);
return 1000*1000;
Lock::Guard lock_guard(_lock);
return Microseconds(1000 * 1000);
}
unsigned long Platform_timer::curr_time() const
Microseconds Timer::Time_source::curr_time() const
{
Genode::Lock::Guard lock_guard(_lock);
return _curr_time_usec;
Lock::Guard lock_guard(_lock);
return Microseconds(_curr_time_us);
}
void Platform_timer::_usleep(unsigned long usecs)
void Timer::Time_source::_usleep(unsigned long us)
{
using namespace Pistachio;
enum { MAGIC_USER_DEFINED_HANDLE = 13 };
L4_Set_UserDefinedHandle(MAGIC_USER_DEFINED_HANDLE);
L4_Sleep(L4_TimePeriod(usecs));
_curr_time_usec += usecs;
L4_Sleep(L4_TimePeriod(us));
_curr_time_us += us;
/* check if sleep was canceled */
if (L4_UserDefinedHandle() != MAGIC_USER_DEFINED_HANDLE)
throw Genode::Blocking_canceled();
throw Blocking_canceled();
}

View File

@ -0,0 +1,118 @@
/*
* \brief Time source that uses the Programmable Interval Timer (PIT)
* \author Norman Feske
* \author Martin Stein
* \date 2009-06-16
*/
/*
* Copyright (C) 2009-2015 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.
*/
/* local includes */
#include <time_source.h>
using namespace Genode;
using Microseconds = Genode::Time_source::Microseconds;
void Timer::Time_source::_set_counter(uint16_t value)
{
_handled_wrap = false;
_io_port.outb(PIT_DATA_PORT_0, value & 0xff);
_io_port.outb(PIT_DATA_PORT_0, (value >> 8) & 0xff);
}
uint16_t Timer::Time_source::_read_counter(bool *wrapped)
{
/* read-back count and status of counter 0 */
_io_port.outb(PIT_CMD_PORT, PIT_CMD_READ_BACK |
PIT_CMD_RB_COUNT |
PIT_CMD_RB_STATUS |
PIT_CMD_RB_CHANNEL_0);
/* read status byte from latch register */
uint8_t status = _io_port.inb(PIT_DATA_PORT_0);
/* read low and high bytes from latch register */
uint16_t lo = _io_port.inb(PIT_DATA_PORT_0);
uint16_t hi = _io_port.inb(PIT_DATA_PORT_0);
*wrapped = status & PIT_STAT_INT_LINE ? true : false;
return (hi << 8) | lo;
}
void Timer::Time_source::schedule_timeout(Microseconds duration,
Timeout_handler &handler)
{
_handler = &handler;
_timer_irq.ack_irq();
unsigned long duration_us = duration.value;
/* limit timer-interrupt rate */
enum { MAX_TIMER_IRQS_PER_SECOND = 4*1000 };
if (duration_us < 1000 * 1000 / MAX_TIMER_IRQS_PER_SECOND)
duration_us = 1000 * 1000 / MAX_TIMER_IRQS_PER_SECOND;
if (duration_us > max_timeout().value)
duration_us = max_timeout().value;
_counter_init_value = (PIT_TICKS_PER_MSEC * duration_us) / 1000;
_set_counter(_counter_init_value);
}
Microseconds Timer::Time_source::curr_time() const
{
uint32_t passed_ticks;
/*
* 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;
uint16_t const curr_counter =
const_cast<Time_source *>(this)->_read_counter(&wrapped);
/* determine the time since we looked at the counter */
if (wrapped && !_handled_wrap) {
passed_ticks = _counter_init_value;
/* the counter really wrapped around */
if (curr_counter)
passed_ticks += PIT_MAX_COUNT + 1 - curr_counter;
_handled_wrap = true;
} else {
if (_counter_init_value)
passed_ticks = _counter_init_value - curr_counter;
else
passed_ticks = PIT_MAX_COUNT + 1 - curr_counter;
}
_curr_time_us += (passed_ticks*1000)/PIT_TICKS_PER_MSEC;
/* use current counter as the reference for the next update */
_counter_init_value = curr_counter;
return Microseconds(_curr_time_us);
}
Timer::Time_source::Time_source(Entrypoint &ep)
:
Signalled_time_source(ep),
_io_port(PIT_DATA_PORT_0, PIT_CMD_PORT - PIT_DATA_PORT_0 + 1),
_timer_irq(IRQ_PIT)
{
/* operate PIT in one-shot mode */
_io_port.outb(PIT_CMD_PORT, PIT_CMD_SELECT_CHANNEL_0 |
PIT_CMD_ACCESS_LO_HI | PIT_CMD_MODE_IRQ);
_timer_irq.sigh(_signal_handler);
}

View File

@ -0,0 +1,90 @@
/*
* \brief Time source that uses the Programmable Interval Timer (PIT)
* \author Norman Feske
* \author Martin Stein
* \date 2009-06-16
*/
/*
* Copyright (C) 2009-2015 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 _TIME_SOURCE_H_
#define _TIME_SOURCE_H_
/* Genode includes */
#include <io_port_session/connection.h>
#include <irq_session/connection.h>
/* local includes */
#include <signalled_time_source.h>
namespace Timer { class Time_source; }
class Timer::Time_source : public Genode::Signalled_time_source
{
private:
enum {
PIT_TICKS_PER_SECOND = 1193182,
PIT_TICKS_PER_MSEC = PIT_TICKS_PER_SECOND/1000,
PIT_MAX_COUNT = 65535,
PIT_DATA_PORT_0 = 0x40, /* data port for PIT channel 0,
connected to the PIC */
PIT_CMD_PORT = 0x43, /* PIT command port */
PIT_MAX_USEC = (PIT_MAX_COUNT*1000)/(PIT_TICKS_PER_MSEC),
IRQ_PIT = 0, /* timer interrupt at the PIC */
/*
* Bit definitions for accessing the PIT command port
*/
PIT_CMD_SELECT_CHANNEL_0 = 0 << 6,
PIT_CMD_ACCESS_LO = 1 << 4,
PIT_CMD_ACCESS_LO_HI = 3 << 4,
PIT_CMD_MODE_IRQ = 0 << 1,
PIT_CMD_MODE_RATE = 2 << 1,
PIT_CMD_READ_BACK = 3 << 6,
PIT_CMD_RB_COUNT = 0 << 5,
PIT_CMD_RB_STATUS = 0 << 4,
PIT_CMD_RB_CHANNEL_0 = 1 << 1,
/*
* Bit definitions of the PIT status byte
*/
PIT_STAT_INT_LINE = 1 << 7,
};
Genode::Io_port_connection _io_port;
Genode::Irq_connection _timer_irq;
unsigned long mutable _curr_time_us = 0;
Genode::uint16_t mutable _counter_init_value = 0;
bool mutable _handled_wrap = false;
void _set_counter(Genode::uint16_t value);
Genode::uint16_t _read_counter(bool *wrapped);
public:
Time_source(Genode::Entrypoint &ep);
/*************************
** Genode::Time_source **
*************************/
Microseconds curr_time() const override;
void schedule_timeout(Microseconds duration, Timeout_handler &handler) override;
Microseconds max_timeout() const override {
return Microseconds(PIT_MAX_USEC); }
};
#endif /* _TIME_SOURCE_H_ */