From a23f6209aefae9236eef4f9932fe1bcd4ed35d52 Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Fri, 17 Jun 2022 15:14:25 +0200 Subject: [PATCH] lx_emul: stop ticking in idle task Fixes #4540 --- repos/dde_linux/src/include/lx_emul/task.h | 2 ++ repos/dde_linux/src/include/lx_kit/scheduler.h | 2 ++ .../src/lib/lx_emul/shadow/kernel/sched/core.c | 1 + .../src/lib/lx_emul/shadow/kernel/softirq.c | 1 + .../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 | 8 ++++++++ repos/dde_linux/src/lib/lx_emul/task.cc | 8 ++++++++ repos/dde_linux/src/lib/lx_kit/scheduler.cc | 17 +++++++++++++++++ 9 files changed, 47 insertions(+) diff --git a/repos/dde_linux/src/include/lx_emul/task.h b/repos/dde_linux/src/include/lx_emul/task.h index 6cc629e857..487c8eed39 100644 --- a/repos/dde_linux/src/include/lx_emul/task.h +++ b/repos/dde_linux/src/include/lx_emul/task.h @@ -44,6 +44,8 @@ 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); + #ifdef __cplusplus } #endif diff --git a/repos/dde_linux/src/include/lx_kit/scheduler.h b/repos/dde_linux/src/include/lx_kit/scheduler.h index a80aa580d4..26e9b0c4ac 100644 --- a/repos/dde_linux/src/include/lx_kit/scheduler.h +++ b/repos/dde_linux/src/include/lx_kit/scheduler.h @@ -45,6 +45,8 @@ 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/shadow/kernel/sched/core.c b/repos/dde_linux/src/lib/lx_emul/shadow/kernel/sched/core.c index 988268294d..5f81b1feba 100644 --- a/repos/dde_linux/src/lib/lx_emul/shadow/kernel/sched/core.c +++ b/repos/dde_linux/src/lib/lx_emul/shadow/kernel/sched/core.c @@ -64,6 +64,7 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags) lx_emul_task_unblock(p); p->__state = TASK_RUNNING; + return 1; } diff --git a/repos/dde_linux/src/lib/lx_emul/shadow/kernel/softirq.c b/repos/dde_linux/src/lib/lx_emul/shadow/kernel/softirq.c index ba80a41d1c..542f1a8110 100644 --- a/repos/dde_linux/src/lib/lx_emul/shadow/kernel/softirq.c +++ b/repos/dde_linux/src/lib/lx_emul/shadow/kernel/softirq.c @@ -13,6 +13,7 @@ #include #include +#include #define CREATE_TRACE_POINTS #include 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 9e5cb9f24d..862790614c 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,6 +17,7 @@ #include #include #include +#include #include <../kernel/irq/internals.h> static int dde_irq_set_wake(struct irq_data *d, unsigned int on) @@ -174,6 +175,9 @@ 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 fd3cb9e570..707317e849 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,6 +15,7 @@ #include #include #include +#include #include <../kernel/irq/internals.h> @@ -46,6 +47,9 @@ 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 ec9469edca..ebad304827 100644 --- a/repos/dde_linux/src/lib/lx_emul/start.c +++ b/repos/dde_linux/src/lib/lx_emul/start.c @@ -73,8 +73,16 @@ 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(); } } diff --git a/repos/dde_linux/src/lib/lx_emul/task.cc b/repos/dde_linux/src/lib/lx_emul/task.cc index 350d121a27..04ba17b4fb 100644 --- a/repos/dde_linux/src/lib/lx_emul/task.cc +++ b/repos/dde_linux/src/lib/lx_emul/task.cc @@ -100,3 +100,11 @@ extern "C" void * lx_emul_task_stack(struct task_struct const * t) return ret; } + + +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); +} diff --git a/repos/dde_linux/src/lib/lx_kit/scheduler.cc b/repos/dde_linux/src/lib/lx_kit/scheduler.cc index d6182b3ba9..e0ec62e8b5 100644 --- a/repos/dde_linux/src/lib/lx_kit/scheduler.cc +++ b/repos/dde_linux/src/lib/lx_kit/scheduler.cc @@ -127,3 +127,20 @@ void Scheduler::schedule() /* 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; +}