nova: limit timeout rate in nova_timer_drv

Issue #2579
This commit is contained in:
Alexander Boettcher 2017-11-16 20:49:37 +01:00 committed by Christian Helmuth
parent 59f97802a9
commit f3dafbf5a6
2 changed files with 49 additions and 21 deletions

View File

@ -35,7 +35,7 @@ class Timer::Threaded_time_source : public Genode::Time_source,
struct Irq_dispatcher
{
GENODE_RPC(Rpc_do_dispatch, void, do_dispatch, Duration);
GENODE_RPC(Rpc_do_dispatch, void, do_dispatch);
GENODE_RPC_INTERFACE(Rpc_do_dispatch);
};
@ -43,16 +43,23 @@ class Timer::Threaded_time_source : public Genode::Time_source,
Irq_dispatcher_component>
{
Timeout_handler *handler = nullptr;
Threaded_time_source &ts;
Irq_dispatcher_component(Threaded_time_source &ts) : ts(ts) { }
/********************
** Irq_dispatcher **
********************/
void do_dispatch(Duration curr_time)
void do_dispatch()
{
if (handler) {
handler->handle_timeout(Duration(curr_time)); }
/* call curr_time in ep and not in ts (no locks in use!) */
ts._irq = true;
Duration us = ts.curr_time();
ts._irq = false;
if (handler)
handler->handle_timeout(us);
}
} _irq_dispatcher_component;
@ -61,7 +68,6 @@ class Timer::Threaded_time_source : public Genode::Time_source,
virtual void _wait_for_irq() = 0;
/***********************
** Thread_deprecated **
***********************/
@ -70,15 +76,20 @@ class Timer::Threaded_time_source : public Genode::Time_source,
{
while (true) {
_wait_for_irq();
_irq_dispatcher_cap.call<Irq_dispatcher::Rpc_do_dispatch>(curr_time());
_irq_dispatcher_cap.call<Irq_dispatcher::Rpc_do_dispatch>();
}
}
protected:
bool _irq { false };
public:
Threaded_time_source(Genode::Env &env)
:
Thread(env, "threaded_time_source", 8 * 1024 * sizeof(Genode::addr_t)),
_irq_dispatcher_component(*this),
_irq_dispatcher_cap(env.ep().rpc_ep().manage(&_irq_dispatcher_component))
{ }

View File

@ -28,22 +28,19 @@ 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;
Genode::addr_t _sem { ~0UL };
unsigned long _timeout_us { 0 };
unsigned long _tsc_khz { 0 };
Duration _curr_time { Microseconds(0) };
Genode::Trace::Timestamp _tsc_start { Genode::Trace::timestamp() };
Genode::Trace::Timestamp _tsc_last { _tsc_start };
/* 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
inline Genode::uint64_t _tsc_to_us(Genode::uint64_t tsc) const
{
if (sub_tsc_start) {
return Microseconds((tsc - _tsc_start) /
(_tsc_khz / TSC_FACTOR));
}
return Microseconds((tsc) / (_tsc_khz / TSC_FACTOR));
return (tsc) / (_tsc_khz / TSC_FACTOR);
}
@ -62,10 +59,30 @@ class Timer::Time_source : public Threaded_time_source
** Genode::Time_source **
*************************/
Microseconds max_timeout() const override { return _tsc_to_us(~0UL); }
void schedule_timeout(Microseconds duration, Timeout_handler &handler) override;
Duration curr_time() override {
return Duration(_tsc_to_us(Genode::Trace::timestamp())); }
void schedule_timeout(Microseconds duration,
Timeout_handler &handler) override;
Microseconds max_timeout() const override
{
unsigned long long const max_us_ull = _tsc_to_us(~0ULL);
return max_us_ull > ~0UL ? Microseconds(~0UL) : Microseconds(max_us_ull);
}
Duration curr_time() override
{
using namespace Genode::Trace;
Timestamp const curr_tsc = timestamp();
Microseconds const diff(_tsc_to_us(curr_tsc - _tsc_last));
/* update in irq context or if update rate is below 4000 irq/s */
if (_irq || diff.value > 250) {
_curr_time += diff;
_tsc_last = curr_tsc;
}
return _curr_time;
}
};
#endif /* _TIME_SOURCE_H_ */