From 2c1724d7f2e41f4e5d721a1209abbd5e870820d6 Mon Sep 17 00:00:00 2001 From: Stefan Kalkowski Date: Tue, 28 Feb 2023 13:00:46 +0100 Subject: [PATCH] lx_emul: adjust start & stop tick behaviour Do not start and stop idle ticking within the timer interrupt routine, but do it around the whole Lx_kit scheduling, which is always called when Linux code gets active again, either because of backend signals, interrupts, or timing signals. This commit implicitly reverts the (incomplete) solution of issue #4550 Ref genodelabs/genode#4778 --- repos/dde_linux/src/include/lx_emul/task.h | 4 +- .../dde_linux/src/include/lx_kit/scheduler.h | 7 +++- .../src/lib/lx_emul/spec/arm/irqchip.c | 4 -- .../src/lib/lx_emul/spec/x86/irqchip.c | 4 -- repos/dde_linux/src/lib/lx_emul/start.c | 39 ++++++++++++++----- repos/dde_linux/src/lib/lx_emul/task.cc | 14 +++---- repos/dde_linux/src/lib/lx_kit/scheduler.cc | 34 +++++++--------- 7 files changed, 56 insertions(+), 50 deletions(-) diff --git a/repos/dde_linux/src/include/lx_emul/task.h b/repos/dde_linux/src/include/lx_emul/task.h index 3873bdff22..76708e0723 100644 --- a/repos/dde_linux/src/include/lx_emul/task.h +++ b/repos/dde_linux/src/include/lx_emul/task.h @@ -44,9 +44,9 @@ void lx_emul_task_name(struct task_struct * task, const char * name); void *lx_emul_task_stack(struct task_struct const * task); -char lx_emul_task_another_runnable(void); +void lx_emul_task_mark_for_removal(struct task_struct const * task); -void lx_emul_task_mark_for_removal(struct task_struct const * task); +void lx_emul_task_set_idle(void); #ifdef __cplusplus } diff --git a/repos/dde_linux/src/include/lx_kit/scheduler.h b/repos/dde_linux/src/include/lx_kit/scheduler.h index 418f790e52..3e2e12aebf 100644 --- a/repos/dde_linux/src/include/lx_kit/scheduler.h +++ b/repos/dde_linux/src/include/lx_kit/scheduler.h @@ -31,13 +31,18 @@ class Lx_kit::Scheduler List _present_list { }; Task * _current { nullptr }; + Task * _idle { nullptr }; Genode::Entrypoint &ep; + void _idle_pre_post_process(); + public: Task & current(); + void idle(Task & idle) { _idle = &idle; } + bool active() const; void add(Task & task); @@ -47,8 +52,6 @@ class Lx_kit::Scheduler void unblock_irq_handler(); void unblock_time_handler(); - bool another_runnable(Task *); - Task & task(void * t); template diff --git a/repos/dde_linux/src/lib/lx_emul/spec/arm/irqchip.c b/repos/dde_linux/src/lib/lx_emul/spec/arm/irqchip.c index 4892c6903d..7a35bbbe18 100644 --- a/repos/dde_linux/src/lib/lx_emul/spec/arm/irqchip.c +++ b/repos/dde_linux/src/lib/lx_emul/spec/arm/irqchip.c @@ -17,7 +17,6 @@ #include #include #include -#include #include <../kernel/irq/internals.h> static int dde_irq_set_wake(struct irq_data *d, unsigned int on) @@ -173,9 +172,6 @@ int lx_emul_irq_task_function(void * data) if (!dde_irq_domain) continue; - /* check restarting ticking which may stopped in idle task */ - tick_nohz_idle_restart_tick(); - irq_enter(); irq = irq_find_mapping(dde_irq_domain, lx_emul_irq_last()); diff --git a/repos/dde_linux/src/lib/lx_emul/spec/x86/irqchip.c b/repos/dde_linux/src/lib/lx_emul/spec/x86/irqchip.c index b6b53149fe..a59c6c37f7 100644 --- a/repos/dde_linux/src/lib/lx_emul/spec/x86/irqchip.c +++ b/repos/dde_linux/src/lib/lx_emul/spec/x86/irqchip.c @@ -15,7 +15,6 @@ #include #include #include -#include #include <../kernel/irq/internals.h> @@ -53,9 +52,6 @@ int lx_emul_irq_task_function(void * data) for (;;) { lx_emul_task_schedule(true); - /* check restarting ticking which may stopped in idle task */ - tick_nohz_idle_restart_tick(); - irq_enter(); irq = lx_emul_irq_last(); diff --git a/repos/dde_linux/src/lib/lx_emul/start.c b/repos/dde_linux/src/lib/lx_emul/start.c index b12d7901e8..21236a4474 100644 --- a/repos/dde_linux/src/lib/lx_emul/start.c +++ b/repos/dde_linux/src/lib/lx_emul/start.c @@ -69,21 +69,39 @@ static int kernel_init(void * args) } +static int kernel_idle(void * args) +{ + struct task_struct *tsk = current; + set_task_comm(tsk, "idle"); + + /* set this current task to be the idle task */ + lx_emul_task_set_idle(); + + /* + * Idle task always gets run in the end of each schedule + * and again at the beginning of each schedule + */ + for (;;) { + lx_emul_task_schedule(true); + + tick_nohz_idle_enter(); + tick_nohz_idle_stop_tick(); + + lx_emul_task_schedule(true); + + tick_nohz_idle_restart_tick(); + tick_nohz_idle_exit(); + } + + return 0; +} + + static void timer_loop(void) { for (;;) { - tick_nohz_idle_enter(); - - if (!lx_emul_task_another_runnable()) - tick_nohz_idle_stop_tick(); - lx_emul_task_schedule(true); lx_emul_time_handle(); - - /* check restarting ticking */ - tick_nohz_idle_restart_tick(); - - tick_nohz_idle_exit(); } } @@ -125,6 +143,7 @@ int lx_emul_init_task_function(void * dtb) sched_clock_init(); kernel_thread(kernel_init, NULL, CLONE_FS); + kernel_thread(kernel_idle, NULL, CLONE_FS); pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES); kthreadd_task = find_task_by_pid_ns(pid, NULL);; diff --git a/repos/dde_linux/src/lib/lx_emul/task.cc b/repos/dde_linux/src/lib/lx_emul/task.cc index fd3f82934b..28f97a1c5a 100644 --- a/repos/dde_linux/src/lib/lx_emul/task.cc +++ b/repos/dde_linux/src/lib/lx_emul/task.cc @@ -102,15 +102,13 @@ extern "C" void * lx_emul_task_stack(struct task_struct const * t) } -extern "C" char lx_emul_task_another_runnable() -{ - Lx_kit::Task & task = Lx_kit::env().scheduler.current(); - - return Lx_kit::env().scheduler.another_runnable(&task); -} - - extern "C" void lx_emul_task_mark_for_removal(struct task_struct const *t) { Lx_kit::env().scheduler.task((void*)t).mark_for_destruction(); } + + +extern "C" void lx_emul_task_set_idle(void) +{ + return Lx_kit::env().scheduler.idle(Lx_kit::env().scheduler.current()); +} diff --git a/repos/dde_linux/src/lib/lx_kit/scheduler.cc b/repos/dde_linux/src/lib/lx_kit/scheduler.cc index 7f64977fb0..187c8f4531 100644 --- a/repos/dde_linux/src/lib/lx_kit/scheduler.cc +++ b/repos/dde_linux/src/lib/lx_kit/scheduler.cc @@ -27,6 +27,16 @@ using namespace Genode; using namespace Lx_kit; +void Scheduler::_idle_pre_post_process() +{ + if (!_idle) + return; + + _current = _idle; + _idle->run(); +} + + Task & Scheduler::current() { if (!_current) { @@ -104,6 +114,8 @@ void Scheduler::schedule() Genode::sleep_forever(); } + _idle_pre_post_process(); + /* * Iterate over all tasks and run first runnable. * @@ -116,9 +128,6 @@ void Scheduler::schedule() while (true) { bool at_least_one = false; - /* update jiffies before running task */ - //Lx::timer_update_jiffies(); - for (Task * t = _present_list.first(); t; ) { Task *tmp = t; @@ -148,23 +157,8 @@ void Scheduler::schedule() break; } + _idle_pre_post_process(); + /* clear current as no task is running */ _current = nullptr; } - - -bool Scheduler::another_runnable(Task * skip) -{ - for (Task * t = _present_list.first(); t; t = t->next()) { - - if (!t->runnable()) - continue; - - if (skip && t == skip) - continue; - - return true; - }; - - return false; -}