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);
char lx_emul_task_another_runnable(void);
void lx_emul_task_mark_for_removal(struct task_struct const * task);
void lx_emul_task_set_idle(void);
#ifdef __cplusplus
}
#endif

View File

@ -31,13 +31,18 @@ class Lx_kit::Scheduler
List<Task> _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 <typename FN>

View File

@ -17,7 +17,6 @@
#include <linux/of_irq.h>
#include <linux/slab.h>
#include <linux/irqchip.h>
#include <linux/tick.h>
#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());

View File

@ -15,7 +15,6 @@
#include <lx_emul/irq.h>
#include <linux/irq.h>
#include <linux/irqchip.h>
#include <linux/tick.h>
#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();

View File

@ -69,22 +69,40 @@ static int kernel_init(void * args)
}
static void timer_loop(void)
static int kernel_idle(void * args)
{
for (;;) {
tick_nohz_idle_enter();
struct task_struct *tsk = current;
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();
lx_emul_task_schedule(true);
lx_emul_time_handle();
/* check restarting ticking */
tick_nohz_idle_restart_tick();
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();
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);;

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)
{
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 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;
}