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
This commit is contained in:
Stefan Kalkowski 2023-02-28 13:00:46 +01:00 committed by Christian Helmuth
parent b9b18c92d0
commit 2c1724d7f2
7 changed files with 56 additions and 50 deletions

View File

@ -44,10 +44,10 @@ void lx_emul_task_name(struct task_struct * task, const char * name);
void *lx_emul_task_stack(struct task_struct const * task); 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 #ifdef __cplusplus
} }
#endif #endif

View File

@ -31,13 +31,18 @@ class Lx_kit::Scheduler
List<Task> _present_list { }; List<Task> _present_list { };
Task * _current { nullptr }; Task * _current { nullptr };
Task * _idle { nullptr };
Genode::Entrypoint &ep; Genode::Entrypoint &ep;
void _idle_pre_post_process();
public: public:
Task & current(); Task & current();
void idle(Task & idle) { _idle = &idle; }
bool active() const; bool active() const;
void add(Task & task); void add(Task & task);
@ -47,8 +52,6 @@ class Lx_kit::Scheduler
void unblock_irq_handler(); void unblock_irq_handler();
void unblock_time_handler(); void unblock_time_handler();
bool another_runnable(Task *);
Task & task(void * t); Task & task(void * t);
template <typename FN> template <typename FN>

View File

@ -17,7 +17,6 @@
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/irqchip.h> #include <linux/irqchip.h>
#include <linux/tick.h>
#include <../kernel/irq/internals.h> #include <../kernel/irq/internals.h>
static int dde_irq_set_wake(struct irq_data *d, unsigned int on) 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) if (!dde_irq_domain)
continue; continue;
/* check restarting ticking which may stopped in idle task */
tick_nohz_idle_restart_tick();
irq_enter(); irq_enter();
irq = irq_find_mapping(dde_irq_domain, lx_emul_irq_last()); irq = irq_find_mapping(dde_irq_domain, lx_emul_irq_last());

View File

@ -15,7 +15,6 @@
#include <lx_emul/irq.h> #include <lx_emul/irq.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/irqchip.h> #include <linux/irqchip.h>
#include <linux/tick.h>
#include <../kernel/irq/internals.h> #include <../kernel/irq/internals.h>
@ -53,9 +52,6 @@ int lx_emul_irq_task_function(void * data)
for (;;) { for (;;) {
lx_emul_task_schedule(true); lx_emul_task_schedule(true);
/* check restarting ticking which may stopped in idle task */
tick_nohz_idle_restart_tick();
irq_enter(); irq_enter();
irq = lx_emul_irq_last(); irq = lx_emul_irq_last();

View File

@ -69,22 +69,40 @@ static int kernel_init(void * args)
} }
static void timer_loop(void) static int kernel_idle(void * args)
{ {
for (;;) { struct task_struct *tsk = current;
tick_nohz_idle_enter(); set_task_comm(tsk, "idle");
if (!lx_emul_task_another_runnable()) /* 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(); tick_nohz_idle_stop_tick();
lx_emul_task_schedule(true); lx_emul_task_schedule(true);
lx_emul_time_handle();
/* check restarting ticking */
tick_nohz_idle_restart_tick(); tick_nohz_idle_restart_tick();
tick_nohz_idle_exit(); tick_nohz_idle_exit();
} }
return 0;
}
static void timer_loop(void)
{
for (;;) {
lx_emul_task_schedule(true);
lx_emul_time_handle();
}
} }
@ -125,6 +143,7 @@ int lx_emul_init_task_function(void * dtb)
sched_clock_init(); sched_clock_init();
kernel_thread(kernel_init, NULL, CLONE_FS); kernel_thread(kernel_init, NULL, CLONE_FS);
kernel_thread(kernel_idle, NULL, CLONE_FS);
pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES); pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
kthreadd_task = find_task_by_pid_ns(pid, NULL);; kthreadd_task = find_task_by_pid_ns(pid, NULL);;

View File

@ -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) extern "C" void lx_emul_task_mark_for_removal(struct task_struct const *t)
{ {
Lx_kit::env().scheduler.task((void*)t).mark_for_destruction(); 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());
}

View File

@ -27,6 +27,16 @@
using namespace Genode; using namespace Genode;
using namespace Lx_kit; using namespace Lx_kit;
void Scheduler::_idle_pre_post_process()
{
if (!_idle)
return;
_current = _idle;
_idle->run();
}
Task & Scheduler::current() Task & Scheduler::current()
{ {
if (!_current) { if (!_current) {
@ -104,6 +114,8 @@ void Scheduler::schedule()
Genode::sleep_forever(); Genode::sleep_forever();
} }
_idle_pre_post_process();
/* /*
* Iterate over all tasks and run first runnable. * Iterate over all tasks and run first runnable.
* *
@ -116,9 +128,6 @@ void Scheduler::schedule()
while (true) { while (true) {
bool at_least_one = false; bool at_least_one = false;
/* update jiffies before running task */
//Lx::timer_update_jiffies();
for (Task * t = _present_list.first(); t; ) { for (Task * t = _present_list.first(); t; ) {
Task *tmp = t; Task *tmp = t;
@ -148,23 +157,8 @@ void Scheduler::schedule()
break; break;
} }
_idle_pre_post_process();
/* clear current as no task is running */ /* clear current as no task is running */
_current = nullptr; _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;
}