From 260fc30be341645a0fb28b82882b5a1eebfba765 Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Wed, 1 Nov 2017 14:31:06 -0500 Subject: [PATCH] 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 --- repos/dde_linux/src/lib/lxip/lx.h | 9 +- repos/dde_linux/src/lib/lxip/lxcc_emul.cc | 131 +------------- repos/dde_linux/src/lib/lxip/timer_handler.cc | 161 +++++++++++++++--- repos/dde_linux/src/lib/vfs/lxip/vfs.cc | 7 +- 4 files changed, 150 insertions(+), 158 deletions(-) diff --git a/repos/dde_linux/src/lib/lxip/lx.h b/repos/dde_linux/src/lib/lxip/lx.h index a7fb8d481..45010b3b8 100644 --- a/repos/dde_linux/src/lib/lxip/lx.h +++ b/repos/dde_linux/src/lib/lxip/lx.h @@ -15,6 +15,7 @@ #ifndef _LX_H_ #define _LX_H_ +#include #include 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); diff --git a/repos/dde_linux/src/lib/lxip/lxcc_emul.cc b/repos/dde_linux/src/lib/lxip/lxcc_emul.cc index ed01f8c1c..2672f13a4 100644 --- a/repos/dde_linux/src/lib/lxip/lxcc_emul.cc +++ b/repos/dde_linux/src/lib/lxip/lxcc_emul.cc @@ -20,8 +20,8 @@ #include #include #include -#include #include +#include /* local includes */ #include @@ -301,89 +301,6 @@ void *memmove(void *d, const void *s, size_t n) } -/******************* - ** linux/sched.h ** - *******************/ - -struct Timeout : Genode::Io_signal_handler -{ - 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(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; -} diff --git a/repos/dde_linux/src/lib/lxip/timer_handler.cc b/repos/dde_linux/src/lib/lxip/timer_handler.cc index 2aacb15d5..45e8bb28f 100644 --- a/repos/dde_linux/src/lib/lxip/timer_handler.cc +++ b/repos/dde_linux/src/lib/lxip/timer_handler.cc @@ -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 _timers_one_shot { + _scheduler, *this, &Lx::Timer::_handle_timers }; + + /* One-shot timeout for 'wait' */ + ::Timer::One_shot_timeout _wait_one_shot { + _scheduler, *this, &Lx::Timer::_handle_wait }; + Lx_kit::List _list; - Genode::Io_signal_handler _handler; Genode::Tslab _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; +} diff --git a/repos/dde_linux/src/lib/vfs/lxip/vfs.cc b/repos/dde_linux/src/lib/vfs/lxip/vfs.cc index 73bd5006e..b9e47d308 100644 --- a/repos/dde_linux/src/lib/vfs/lxip/vfs.cc +++ b/repos/dde_linux/src/lib/vfs/lxip/vfs.cc @@ -23,6 +23,7 @@ #include #include #include +#include /* Lxip includes */ #include @@ -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();