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:
Emery Hemingway 2017-11-01 14:31:06 -05:00 committed by Norman Feske
parent 3725e91603
commit 260fc30be3
4 changed files with 150 additions and 158 deletions

View File

@ -15,6 +15,7 @@
#ifndef _LX_H_
#define _LX_H_
#include <timer/timeout.h>
#include <base/signal.h>
namespace Lx_kit { class Env; }
@ -25,15 +26,11 @@ namespace Lx {
Genode::Allocator &alloc,
void (*ticker)());
void timer_init(Genode::Env &env,
Genode::Entrypoint &ep,
void timer_init(Genode::Entrypoint &ep,
Genode::Timeout_scheduler &scheduler,
Genode::Allocator &alloc,
void (*ticker)());
void event_init(Genode::Env &env,
Genode::Entrypoint &ep,
void (*ticker)());
void timer_update_jiffies();
void lxcc_emul_init(Lx_kit::Env &env);

View File

@ -20,8 +20,8 @@
#include <base/snprintf.h>
#include <dataspace/client.h>
#include <region_map/client.h>
#include <timer_session/connection.h>
#include <trace/timestamp.h>
#include <timer_session/connection.h>
/* local includes */
#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 **
*****************/
@ -711,49 +628,3 @@ int schedule_delayed_work(struct delayed_work *dwork, unsigned long 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;
}

View File

@ -83,9 +83,18 @@ class Lx::Timer
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;
Genode::Io_signal_handler<Lx::Timer> _handler;
Genode::Tslab<Context, 32 * sizeof(Context)> _timer_alloc;
void (*_tick)();
@ -120,7 +129,7 @@ class Lx::Timer
/* calculate relative microseconds for trigger */
unsigned long us = ctx->timeout > jiffies ?
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();
}
/**
* Handle trigger_once signal
*/
void _handle()
inline void _upate_jiffies(Genode::Duration dur)
{
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()) {
if (ctx->timeout > jiffies)
@ -174,20 +192,23 @@ class Lx::Timer
_tick();
}
void _handle_wait(Genode::Duration dur) { _upate_jiffies(dur); }
public:
/**
* Constructor
*/
Timer(Genode::Env &env, Genode::Entrypoint &ep, Genode::Allocator &alloc,
Timer(Genode::Entrypoint &ep,
Genode::Timeout_scheduler &scheduler,
Genode::Allocator &alloc,
void (*tick)())
:
_timer_conn(env),
_handler(ep, *this, &Lx::Timer::_handle),
_ep(ep),
_scheduler(scheduler),
_timer_alloc(&alloc),
_tick(tick)
{
_timer_conn.sigh(_handler);
update_jiffies();
}
@ -275,32 +296,48 @@ class Lx::Timer
* Do not use lx_emul usecs_to_jiffies(unsigned int) because
* 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
*/
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;
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)())
{
static Lx::Timer inst(env, ep, alloc, tick);
static Lx::Timer inst(ep, scheduler, alloc, tick);
_timer = &inst;
}
void update_jiffies()
{
_timer->update_jiffies();
}
void update_jiffies() { _timer->update_jiffies(); }
void Lx::timer_update_jiffies() { update_jiffies(); }
/*******************
** 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;
}

View File

@ -23,6 +23,7 @@
#include <vfs/file_io_service.h>
#include <vfs/file_system_factory.h>
#include <vfs/vfs_handle.h>
#include <timer_session/connection.h>
/* Lxip includes */
#include <lxip/lxip.h>
@ -1962,15 +1963,17 @@ struct Lxip_factory : Vfs::File_system_factory
char *_parse_config(Genode::Xml_node);
Timer::Connection timer;
Init(Genode::Env &env,
Genode::Allocator &alloc)
: timer(env, "vfs_lxip")
{
Lx_kit::Env &lx_env = Lx_kit::construct_env(env);
Lx::lxcc_emul_init(lx_env);
Lx::malloc_init(env, lx_env.heap());
Lx::timer_init(env, lx_env.env().ep(), lx_env.heap(), &poll_all);
Lx::event_init(env, lx_env.env().ep(), &poll_all);
Lx::timer_init(env.ep(), timer, lx_env.heap(), &poll_all);
Lx::nic_client_init(env, lx_env.heap(), &poll_all);
lxip_init();