mirror of
https://github.com/genodelabs/genode.git
synced 2025-05-05 02:03:07 +00:00
231 lines
5.0 KiB
C++
231 lines
5.0 KiB
C++
/*
|
|
* \brief Scheduler for executing Lx::Task objects
|
|
* \author Sebastian Sumpf
|
|
* \author Josef Soentgen
|
|
* \author Norman Feske
|
|
* \date 2014-10-10
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2014-2017 Genode Labs GmbH
|
|
*
|
|
* This file is distributed under the terms of the GNU General Public License
|
|
* version 2.
|
|
*/
|
|
|
|
/* Genode includes */
|
|
#include <base/env.h>
|
|
#include <base/lock.h>
|
|
#include <base/log.h>
|
|
#include <base/sleep.h>
|
|
#include <base/thread.h>
|
|
#include <timer_session/connection.h>
|
|
|
|
/* Linux emulation environment includes */
|
|
#include <lx_kit/scheduler.h>
|
|
|
|
#include <lx_kit/timer.h>
|
|
|
|
|
|
namespace Lx_kit {
|
|
class Scheduler;
|
|
}
|
|
|
|
|
|
class Lx_kit::Scheduler : public Lx::Scheduler
|
|
{
|
|
private:
|
|
|
|
bool verbose = false;
|
|
|
|
Lx_kit::List<Lx::Task> _present_list;
|
|
Genode::Lock _present_list_mutex;
|
|
|
|
Lx::Task *_current = nullptr; /* currently scheduled task */
|
|
|
|
bool _run_task(Lx::Task *);
|
|
|
|
/*
|
|
* Support for logging
|
|
*/
|
|
|
|
static inline char const *_ansi_esc_reset() { return "\033[00m"; }
|
|
static inline char const *_ansi_esc_black() { return "\033[30m"; }
|
|
static inline char const *_ansi_esc_red() { return "\033[31m"; }
|
|
static inline char const *_ansi_esc_yellow() { return "\033[33m"; }
|
|
|
|
static inline char const *_state_color(Lx::Task::State state)
|
|
{
|
|
switch (state) {
|
|
case Lx::Task::STATE_INIT: return _ansi_esc_reset();
|
|
case Lx::Task::STATE_RUNNING: return _ansi_esc_red();
|
|
case Lx::Task::STATE_BLOCKED: return _ansi_esc_yellow();
|
|
case Lx::Task::STATE_MUTEX_BLOCKED: return _ansi_esc_yellow();
|
|
case Lx::Task::STATE_WAIT_BLOCKED: return _ansi_esc_yellow();
|
|
}
|
|
|
|
return _ansi_esc_black();
|
|
}
|
|
|
|
struct Logger : Genode::Thread
|
|
{
|
|
Timer::Connection _timer;
|
|
Lx::Scheduler &_scheduler;
|
|
unsigned const _interval;
|
|
|
|
Logger(Genode::Env &env, Lx::Scheduler &scheduler,
|
|
unsigned interval_seconds)
|
|
:
|
|
Genode::Thread(env, "logger", 0x4000),
|
|
_timer(env), _scheduler(scheduler),
|
|
_interval(interval_seconds)
|
|
{
|
|
start();
|
|
}
|
|
|
|
void entry()
|
|
{
|
|
_timer.msleep(1000 * _interval);
|
|
while (true) {
|
|
_scheduler.log_state("LOGGER");
|
|
_timer.msleep(2000);
|
|
}
|
|
}
|
|
};
|
|
|
|
Genode::Constructible<Logger> _logger;
|
|
|
|
public:
|
|
|
|
Scheduler(Genode::Env &env)
|
|
{
|
|
if (verbose) { _logger.construct(env, *this, 10); }
|
|
}
|
|
|
|
/*****************************
|
|
** Lx::Scheduler interface **
|
|
*****************************/
|
|
|
|
Lx::Task *current() override
|
|
{
|
|
if (!_current) {
|
|
Genode::error("BUG: _current is zero!");
|
|
Genode::sleep_forever();
|
|
}
|
|
|
|
return _current;
|
|
}
|
|
|
|
bool active() const override {
|
|
return _current != nullptr; }
|
|
|
|
void add(Lx::Task *task) override
|
|
{
|
|
Lx::Task *p = _present_list.first();
|
|
for ( ; p; p = p->next()) {
|
|
if (p->priority() <= task->priority()) {
|
|
_present_list.insert_before(task, p);
|
|
break;
|
|
}
|
|
}
|
|
if (!p)
|
|
_present_list.append(task);
|
|
}
|
|
|
|
void remove(Lx::Task *task) override
|
|
{
|
|
_present_list.remove(task);
|
|
}
|
|
|
|
void schedule() override
|
|
{
|
|
bool at_least_one = false;
|
|
|
|
/*
|
|
* Iterate over all tasks and run first runnable.
|
|
*
|
|
* (1) If one runnable tasks was run start over from beginning of
|
|
* list.
|
|
*
|
|
* (2) If no task is runnable quit scheduling (break endless
|
|
* loop).
|
|
*/
|
|
while (true) {
|
|
/* update jiffies before running task */
|
|
Lx::timer_update_jiffies();
|
|
|
|
bool was_run = false;
|
|
for (Lx::Task *t = _present_list.first(); t; t = t->next()) {
|
|
/* update current before running task */
|
|
_current = t;
|
|
|
|
if ((was_run = t->run())) {
|
|
at_least_one = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!was_run)
|
|
break;
|
|
}
|
|
|
|
if (!at_least_one) {
|
|
Genode::warning("schedule() called without runnable tasks");
|
|
log_state("SCHEDULE");
|
|
}
|
|
|
|
/* clear current as no task is running */
|
|
_current = nullptr;
|
|
}
|
|
|
|
void log_state(char const *prefix) override
|
|
{
|
|
unsigned i;
|
|
Lx::Task *t;
|
|
for (i = 0, t = _present_list.first(); t; t = t->next(), ++i) {
|
|
Genode::log(prefix, " [", i, "] "
|
|
"prio: ", (int)t->priority(), " "
|
|
"state: ", _state_color(t->state()), (int)t->state(),
|
|
_ansi_esc_reset(), " ",
|
|
t->name());
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
/*****************************
|
|
** Lx::Task implementation **
|
|
*****************************/
|
|
|
|
Lx::Task::Task(void (*func)(void*), void *arg, char const *name,
|
|
Priority priority, Scheduler &scheduler)
|
|
:
|
|
_priority(priority), _scheduler(scheduler),
|
|
_func(func), _arg(arg), _name(name)
|
|
{
|
|
scheduler.add(this);
|
|
|
|
if (verbose)
|
|
Genode::log("name: '", name, "' " "func: ", func, " "
|
|
"arg: ", arg, " prio: ", (int)priority, " t: ", this);
|
|
}
|
|
|
|
|
|
Lx::Task::~Task()
|
|
{
|
|
_scheduler.remove(this);
|
|
|
|
if (_stack)
|
|
Genode::Thread::myself()->free_secondary_stack(_stack);
|
|
}
|
|
|
|
|
|
/**********************************
|
|
** Lx::Scheduler implementation **
|
|
**********************************/
|
|
|
|
Lx::Scheduler &Lx::scheduler(Genode::Env *env)
|
|
{
|
|
static Lx_kit::Scheduler inst { *env };
|
|
return inst;
|
|
}
|