mirror of
https://github.com/genodelabs/genode.git
synced 2025-06-15 21:58:24 +00:00
lxip: consolidate lx timers and timeouts
Use a single timeout scheduler passed during lxip instantiation for both timers and 'schedule_timeout' facilites rather than instantiate two timer sessions and signal handlers. This reduces the library's capability cost and initialization time. Fix #2961
This commit is contained in:
committed by
Norman Feske
parent
3725e91603
commit
260fc30be3
@ -15,6 +15,7 @@
|
|||||||
#ifndef _LX_H_
|
#ifndef _LX_H_
|
||||||
#define _LX_H_
|
#define _LX_H_
|
||||||
|
|
||||||
|
#include <timer/timeout.h>
|
||||||
#include <base/signal.h>
|
#include <base/signal.h>
|
||||||
|
|
||||||
namespace Lx_kit { class Env; }
|
namespace Lx_kit { class Env; }
|
||||||
@ -25,15 +26,11 @@ namespace Lx {
|
|||||||
Genode::Allocator &alloc,
|
Genode::Allocator &alloc,
|
||||||
void (*ticker)());
|
void (*ticker)());
|
||||||
|
|
||||||
void timer_init(Genode::Env &env,
|
void timer_init(Genode::Entrypoint &ep,
|
||||||
Genode::Entrypoint &ep,
|
Genode::Timeout_scheduler &scheduler,
|
||||||
Genode::Allocator &alloc,
|
Genode::Allocator &alloc,
|
||||||
void (*ticker)());
|
void (*ticker)());
|
||||||
|
|
||||||
void event_init(Genode::Env &env,
|
|
||||||
Genode::Entrypoint &ep,
|
|
||||||
void (*ticker)());
|
|
||||||
|
|
||||||
void timer_update_jiffies();
|
void timer_update_jiffies();
|
||||||
|
|
||||||
void lxcc_emul_init(Lx_kit::Env &env);
|
void lxcc_emul_init(Lx_kit::Env &env);
|
||||||
|
@ -20,8 +20,8 @@
|
|||||||
#include <base/snprintf.h>
|
#include <base/snprintf.h>
|
||||||
#include <dataspace/client.h>
|
#include <dataspace/client.h>
|
||||||
#include <region_map/client.h>
|
#include <region_map/client.h>
|
||||||
#include <timer_session/connection.h>
|
|
||||||
#include <trace/timestamp.h>
|
#include <trace/timestamp.h>
|
||||||
|
#include <timer_session/connection.h>
|
||||||
|
|
||||||
/* local includes */
|
/* local includes */
|
||||||
#include <lx_emul.h>
|
#include <lx_emul.h>
|
||||||
@ -301,89 +301,6 @@ void *memmove(void *d, const void *s, size_t n)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*******************
|
|
||||||
** linux/sched.h **
|
|
||||||
*******************/
|
|
||||||
|
|
||||||
struct Timeout : Genode::Io_signal_handler<Timeout>
|
|
||||||
{
|
|
||||||
Genode::Entrypoint &ep;
|
|
||||||
Timer::Connection timer;
|
|
||||||
void (*tick)();
|
|
||||||
|
|
||||||
void handle()
|
|
||||||
{
|
|
||||||
update_jiffies();
|
|
||||||
|
|
||||||
/* tick the higher layer of the component */
|
|
||||||
tick();
|
|
||||||
}
|
|
||||||
|
|
||||||
Timeout(Genode::Env &env, Genode::Entrypoint &ep, void (*ticker)())
|
|
||||||
:
|
|
||||||
Io_signal_handler<Timeout>(ep, *this, &Timeout::handle),
|
|
||||||
ep(ep), timer(env), tick(ticker)
|
|
||||||
{
|
|
||||||
timer.sigh(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void schedule(signed long msec)
|
|
||||||
{
|
|
||||||
timer.trigger_once(msec * 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
void wait()
|
|
||||||
{
|
|
||||||
ep.wait_and_dispatch_one_io_signal();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static Timeout *_timeout;
|
|
||||||
static Genode::Signal_context_capability tick_sig_cap;
|
|
||||||
|
|
||||||
void Lx::event_init(Genode::Env &env, Genode::Entrypoint &ep, void (*ticker)())
|
|
||||||
{
|
|
||||||
static ::Timeout handler(env, ep, ticker);
|
|
||||||
_timeout = &handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
signed long schedule_timeout(signed long timeout)
|
|
||||||
{
|
|
||||||
long start = jiffies;
|
|
||||||
_timeout->schedule(timeout);
|
|
||||||
_timeout->wait();
|
|
||||||
timeout -= jiffies - start;
|
|
||||||
return timeout < 0 ? 0 : timeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
long schedule_timeout_uninterruptible(signed long timeout)
|
|
||||||
{
|
|
||||||
return schedule_timeout(timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p)
|
|
||||||
{
|
|
||||||
_timeout->wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool poll_does_not_wait(const poll_table *p)
|
|
||||||
{
|
|
||||||
return p == nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/******************
|
|
||||||
** linux/time.h **
|
|
||||||
******************/
|
|
||||||
|
|
||||||
unsigned long get_seconds(void)
|
|
||||||
{
|
|
||||||
return jiffies / HZ;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*****************
|
/*****************
|
||||||
** linux/gfp.h **
|
** linux/gfp.h **
|
||||||
*****************/
|
*****************/
|
||||||
@ -711,49 +628,3 @@ int schedule_delayed_work(struct delayed_work *dwork, unsigned long delay)
|
|||||||
{
|
{
|
||||||
return mod_delayed_work(0, dwork, delay);
|
return mod_delayed_work(0, dwork, delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*******************
|
|
||||||
** linux/timer.h **
|
|
||||||
*******************/
|
|
||||||
|
|
||||||
static unsigned long round_jiffies(unsigned long j, bool force_up)
|
|
||||||
{
|
|
||||||
unsigned remainder = j % HZ;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* from timer.c
|
|
||||||
*
|
|
||||||
* If the target jiffie is just after a whole second (which can happen
|
|
||||||
* due to delays of the timer irq, long irq off times etc etc) then
|
|
||||||
* we should round down to the whole second, not up. Use 1/4th second
|
|
||||||
* as cutoff for this rounding as an extreme upper bound for this.
|
|
||||||
* But never round down if @force_up is set.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* per default round down */
|
|
||||||
j = j - remainder;
|
|
||||||
|
|
||||||
/* round up if remainder more than 1/4 second (or if we're forced to) */
|
|
||||||
if (remainder >= HZ/4 || force_up)
|
|
||||||
j += HZ;
|
|
||||||
|
|
||||||
return j;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long round_jiffies(unsigned long j)
|
|
||||||
{
|
|
||||||
return round_jiffies(j, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
unsigned long round_jiffies_up(unsigned long j)
|
|
||||||
{
|
|
||||||
return round_jiffies(j, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
unsigned long round_jiffies_relative(unsigned long j)
|
|
||||||
{
|
|
||||||
return round_jiffies(j + jiffies, false) - jiffies;
|
|
||||||
}
|
|
||||||
|
@ -83,9 +83,18 @@ class Lx::Timer
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
::Timer::Connection _timer_conn;
|
Genode::Entrypoint &_ep;
|
||||||
|
Genode::Timeout_scheduler &_scheduler;
|
||||||
|
|
||||||
|
/* One-shot timeout for timer list */
|
||||||
|
::Timer::One_shot_timeout<Lx::Timer> _timers_one_shot {
|
||||||
|
_scheduler, *this, &Lx::Timer::_handle_timers };
|
||||||
|
|
||||||
|
/* One-shot timeout for 'wait' */
|
||||||
|
::Timer::One_shot_timeout<Lx::Timer> _wait_one_shot {
|
||||||
|
_scheduler, *this, &Lx::Timer::_handle_wait };
|
||||||
|
|
||||||
Lx_kit::List<Context> _list;
|
Lx_kit::List<Context> _list;
|
||||||
Genode::Io_signal_handler<Lx::Timer> _handler;
|
|
||||||
Genode::Tslab<Context, 32 * sizeof(Context)> _timer_alloc;
|
Genode::Tslab<Context, 32 * sizeof(Context)> _timer_alloc;
|
||||||
|
|
||||||
void (*_tick)();
|
void (*_tick)();
|
||||||
@ -120,7 +129,7 @@ class Lx::Timer
|
|||||||
/* calculate relative microseconds for trigger */
|
/* calculate relative microseconds for trigger */
|
||||||
unsigned long us = ctx->timeout > jiffies ?
|
unsigned long us = ctx->timeout > jiffies ?
|
||||||
jiffies_to_msecs(ctx->timeout - jiffies) * 1000 : 0;
|
jiffies_to_msecs(ctx->timeout - jiffies) * 1000 : 0;
|
||||||
_timer_conn.trigger_once(us);
|
_timers_one_shot.schedule(Genode::Microseconds{us});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -152,12 +161,21 @@ class Lx::Timer
|
|||||||
_program_first_timer();
|
_program_first_timer();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
inline void _upate_jiffies(Genode::Duration dur)
|
||||||
* Handle trigger_once signal
|
|
||||||
*/
|
|
||||||
void _handle()
|
|
||||||
{
|
{
|
||||||
update_jiffies();
|
auto new_jiffies = usecs_to_jiffies(dur.trunc_to_plain_us().value);
|
||||||
|
if (new_jiffies < jiffies)
|
||||||
|
jiffies = usecs_to_jiffies(_scheduler.curr_time().trunc_to_plain_us().value);
|
||||||
|
else
|
||||||
|
jiffies = new_jiffies;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check timers and wake application
|
||||||
|
*/
|
||||||
|
void _handle_timers(Genode::Duration dur)
|
||||||
|
{
|
||||||
|
_upate_jiffies(dur);
|
||||||
|
|
||||||
while (Lx::Timer::Context *ctx = _list.first()) {
|
while (Lx::Timer::Context *ctx = _list.first()) {
|
||||||
if (ctx->timeout > jiffies)
|
if (ctx->timeout > jiffies)
|
||||||
@ -174,20 +192,23 @@ class Lx::Timer
|
|||||||
_tick();
|
_tick();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _handle_wait(Genode::Duration dur) { _upate_jiffies(dur); }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
Timer(Genode::Env &env, Genode::Entrypoint &ep, Genode::Allocator &alloc,
|
Timer(Genode::Entrypoint &ep,
|
||||||
|
Genode::Timeout_scheduler &scheduler,
|
||||||
|
Genode::Allocator &alloc,
|
||||||
void (*tick)())
|
void (*tick)())
|
||||||
:
|
:
|
||||||
_timer_conn(env),
|
_ep(ep),
|
||||||
_handler(ep, *this, &Lx::Timer::_handle),
|
_scheduler(scheduler),
|
||||||
_timer_alloc(&alloc),
|
_timer_alloc(&alloc),
|
||||||
_tick(tick)
|
_tick(tick)
|
||||||
{
|
{
|
||||||
_timer_conn.sigh(_handler);
|
|
||||||
update_jiffies();
|
update_jiffies();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,32 +296,48 @@ class Lx::Timer
|
|||||||
* Do not use lx_emul usecs_to_jiffies(unsigned int) because
|
* Do not use lx_emul usecs_to_jiffies(unsigned int) because
|
||||||
* of implicit truncation!
|
* of implicit truncation!
|
||||||
*/
|
*/
|
||||||
jiffies = _timer_conn.curr_time().trunc_to_plain_ms().value / JIFFIES_TICK_MS;
|
jiffies = _scheduler.curr_time().trunc_to_plain_ms().value / JIFFIES_TICK_MS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get first timer context
|
* Get first timer context
|
||||||
*/
|
*/
|
||||||
Context* first() { return _list.first(); }
|
Context* first() { return _list.first(); }
|
||||||
|
|
||||||
|
void wait(unsigned long timeo = 0)
|
||||||
|
{
|
||||||
|
if (timeo > 0)
|
||||||
|
_wait_one_shot.schedule(Genode::Microseconds(jiffies_to_usecs(timeo)));
|
||||||
|
|
||||||
|
_ep.wait_and_dispatch_one_io_signal();
|
||||||
|
}
|
||||||
|
|
||||||
|
void wait_uninterruptible(unsigned long timeo)
|
||||||
|
{
|
||||||
|
if (timeo > 0) {
|
||||||
|
_wait_one_shot.schedule(Genode::Microseconds(jiffies_to_usecs(timeo)));
|
||||||
|
while (_wait_one_shot.scheduled())
|
||||||
|
_ep.wait_and_dispatch_one_io_signal();
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static Lx::Timer *_timer;
|
static Lx::Timer *_timer;
|
||||||
|
|
||||||
|
|
||||||
void Lx::timer_init(Genode::Env &env, Genode::Entrypoint &ep,
|
void Lx::timer_init(Genode::Entrypoint &ep,
|
||||||
|
Genode::Timeout_scheduler &scheduler,
|
||||||
Genode::Allocator &alloc, void (*tick)())
|
Genode::Allocator &alloc, void (*tick)())
|
||||||
{
|
{
|
||||||
static Lx::Timer inst(env, ep, alloc, tick);
|
static Lx::Timer inst(ep, scheduler, alloc, tick);
|
||||||
_timer = &inst;
|
_timer = &inst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void update_jiffies()
|
void update_jiffies() { _timer->update_jiffies(); }
|
||||||
{
|
|
||||||
_timer->update_jiffies();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
void Lx::timer_update_jiffies() { update_jiffies(); }
|
||||||
|
|
||||||
/*******************
|
/*******************
|
||||||
** linux/timer.h **
|
** linux/timer.h **
|
||||||
@ -354,4 +391,88 @@ int del_timer(struct timer_list *timer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Lx::timer_update_jiffies() { update_jiffies(); }
|
/*******************
|
||||||
|
** linux/sched.h **
|
||||||
|
*******************/
|
||||||
|
|
||||||
|
signed long schedule_timeout(signed long timeout)
|
||||||
|
{
|
||||||
|
unsigned long expire = timeout + jiffies;
|
||||||
|
|
||||||
|
long start = jiffies;
|
||||||
|
_timer->wait(timeout);
|
||||||
|
timeout -= jiffies - start;
|
||||||
|
return timeout < 0 ? 0 : timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
long schedule_timeout_uninterruptible(signed long timeout)
|
||||||
|
{
|
||||||
|
_timer->wait_uninterruptible(timeout);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p)
|
||||||
|
{
|
||||||
|
_timer->wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool poll_does_not_wait(const poll_table *p)
|
||||||
|
{
|
||||||
|
return p == nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************
|
||||||
|
** linux/time.h **
|
||||||
|
******************/
|
||||||
|
|
||||||
|
unsigned long get_seconds(void)
|
||||||
|
{
|
||||||
|
return jiffies / HZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*******************
|
||||||
|
** linux/timer.h **
|
||||||
|
*******************/
|
||||||
|
|
||||||
|
static unsigned long round_jiffies(unsigned long j, bool force_up)
|
||||||
|
{
|
||||||
|
unsigned remainder = j % HZ;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* from timer.c
|
||||||
|
*
|
||||||
|
* If the target jiffie is just after a whole second (which can happen
|
||||||
|
* due to delays of the timer irq, long irq off times etc etc) then
|
||||||
|
* we should round down to the whole second, not up. Use 1/4th second
|
||||||
|
* as cutoff for this rounding as an extreme upper bound for this.
|
||||||
|
* But never round down if @force_up is set.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* per default round down */
|
||||||
|
j = j - remainder;
|
||||||
|
|
||||||
|
/* round up if remainder more than 1/4 second (or if we're forced to) */
|
||||||
|
if (remainder >= HZ/4 || force_up)
|
||||||
|
j += HZ;
|
||||||
|
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long round_jiffies(unsigned long j)
|
||||||
|
{
|
||||||
|
return round_jiffies(j, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned long round_jiffies_up(unsigned long j)
|
||||||
|
{
|
||||||
|
return round_jiffies(j, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned long round_jiffies_relative(unsigned long j)
|
||||||
|
{
|
||||||
|
return round_jiffies(j + jiffies, false) - jiffies;
|
||||||
|
}
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include <vfs/file_io_service.h>
|
#include <vfs/file_io_service.h>
|
||||||
#include <vfs/file_system_factory.h>
|
#include <vfs/file_system_factory.h>
|
||||||
#include <vfs/vfs_handle.h>
|
#include <vfs/vfs_handle.h>
|
||||||
|
#include <timer_session/connection.h>
|
||||||
|
|
||||||
/* Lxip includes */
|
/* Lxip includes */
|
||||||
#include <lxip/lxip.h>
|
#include <lxip/lxip.h>
|
||||||
@ -1962,15 +1963,17 @@ struct Lxip_factory : Vfs::File_system_factory
|
|||||||
|
|
||||||
char *_parse_config(Genode::Xml_node);
|
char *_parse_config(Genode::Xml_node);
|
||||||
|
|
||||||
|
Timer::Connection timer;
|
||||||
|
|
||||||
Init(Genode::Env &env,
|
Init(Genode::Env &env,
|
||||||
Genode::Allocator &alloc)
|
Genode::Allocator &alloc)
|
||||||
|
: timer(env, "vfs_lxip")
|
||||||
{
|
{
|
||||||
Lx_kit::Env &lx_env = Lx_kit::construct_env(env);
|
Lx_kit::Env &lx_env = Lx_kit::construct_env(env);
|
||||||
|
|
||||||
Lx::lxcc_emul_init(lx_env);
|
Lx::lxcc_emul_init(lx_env);
|
||||||
Lx::malloc_init(env, lx_env.heap());
|
Lx::malloc_init(env, lx_env.heap());
|
||||||
Lx::timer_init(env, lx_env.env().ep(), lx_env.heap(), &poll_all);
|
Lx::timer_init(env.ep(), timer, lx_env.heap(), &poll_all);
|
||||||
Lx::event_init(env, lx_env.env().ep(), &poll_all);
|
|
||||||
Lx::nic_client_init(env, lx_env.heap(), &poll_all);
|
Lx::nic_client_init(env, lx_env.heap(), &poll_all);
|
||||||
|
|
||||||
lxip_init();
|
lxip_init();
|
||||||
|
Reference in New Issue
Block a user