genode/base-mb/src/kernel/include/generic/scheduler.h

373 lines
7.8 KiB
C++
Executable File

/*
* \brief Declaration of a round robin scheduler
* \author Martin stein
* \date 2010-06-25
*/
/*
* Copyright (C) 2010-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _KERNEL__GENERIC__INCLUDE__SCHEDULER_H_
#define _KERNEL__GENERIC__INCLUDE__SCHEDULER_H_
/* generic includes */
#include <generic/timer.h>
#include <generic/verbose.h>
/* util includes */
#include <util/queue.h>
namespace Kernel {
enum { SHOW_SCHEDULING = 0 };
enum { SCHEDULER__TRACE = 1,
SCHEDULER__VERBOSE = 0,
SCHEDULER__ERROR = 1,
SCHEDULER__WARNING = 1 };
class Exec_context;
class Platform;
class Scheduler : public Tracks_time
{
enum { MS_PER_ROUND_PER_CLIENT = SCHEDULING_MS_INTERVAL,
SCHEDULE__VERBOSE__SUCCESS = SCHEDULER__VERBOSE,
SCHEDULE__ERROR = SCHEDULER__ERROR };
public:
typedef Scheduling_timer Timer;
typedef unsigned int Quota;
typedef Kernel::Platform Ressource;
private:
Timer * const _timer;
const Quota _quota_per_round_per_client;
Ressource* _ressource;
bool _new_clients;
void _schedule();
inline Quota _ms_to_quota(unsigned int const &ms);
/**
* Utilise idle client as current client
*/
inline void _prep_idle_round();
public:
inline void time_consumed(Quota const & q);
enum { CLIENT__WARNING = 1,
CLIENT__VERBOSE = SCHEDULER__VERBOSE };
class Client_queue;
class Client : public Kernel::Queue<Client>::Item
{
friend class Scheduler;
friend class Client_queue;
typedef Kernel::Scheduler::Quota Quota;
Quota _quota;
Scheduler *_scheduler;
bool _sleeping;
protected:
typedef Kernel::Exec_context Context;
private:
inline Quota _consume(Quota const &consumed);
inline void _earn_quota(Quota const &q);
inline Context *_schedulable_context();
protected:
enum{ SCHEDULABLE_context__VERBOSE = 1 };
inline Client();
virtual ~Client();
inline void _sleep();
inline void _wake();
virtual Context *_context() = 0;
virtual bool _preemptable() = 0;
public:
virtual int label() = 0;
};
struct Client_queue : public Kernel::Queue<Client>
{
inline void print_state();
};
private:
Client_queue _client_queue;
Client* _current_client;
Client* _last_client;
Client* _idle_client;
public:
enum{ ADD__VERBOSE = SCHEDULER__VERBOSE||SHOW_SCHEDULING,
REMOVE__VERBOSE = SCHEDULER__VERBOSE||SHOW_SCHEDULING,
RUN__VERBOSE = SCHEDULER__VERBOSE||SHOW_SCHEDULING };
/**
* Constructor
* \param r Ressource that is shared by the clients
* \param t Timer to measure exclusive access duration
* \param idle_client this client gets scheduled if there's
* no other client, it can't be removed
*/
Scheduler(Ressource* r, Scheduling_timer * const t, Client* idle_client);
void add(Client* c);
void remove(Client* c);
void run();
inline Client* current_client();
inline void skip_next_time(Client* c);
protected:
/* debugging */
inline void _print_clients_via_labels();
inline void _run__verbose__success();
inline void _run__error__no_ready_client();
inline void _run__trace__client_checks();
inline void _schedule__error__no_clients();
inline void _schedule__verbose__success() ;
inline void _remove__warning__invalid_client();
inline void _remove__verbose__success(Client* c);
inline void _remove__trace(Client *c);
inline void _add__warning__invalid_client();
inline void _add__verbose__success();
};
/**
* Pointer to kernels static scheduler for execution time
*/
Scheduler *scheduler();
}
/***********************************
** Kernel::Scheduler definitions **
***********************************/
void Kernel::Scheduler::_prep_idle_round()
{
if(_current_client) { _client_queue.enqueue(_current_client); }
_current_client=_idle_client;
}
void Kernel::Scheduler::time_consumed(Quota const & q)
{
_current_client->_consume(q);
}
Kernel::Scheduler::Client* Kernel::Scheduler::current_client()
{
return _current_client;
}
void Kernel::Scheduler::skip_next_time(Client *c) { c->_quota=0; }
Kernel::Scheduler::Quota Kernel::Scheduler::_ms_to_quota(unsigned int const & ms)
{
return _timer->msec_to_native(ms);
}
void Kernel::Scheduler::_print_clients_via_labels()
{
printf("scheduled ");
_last_client ? printf("%i", _last_client->label())
: printf("ø");
printf("");
_current_client ? printf("%i", _current_client->label())
: printf("ø");
printf(", queue ");
_client_queue.print_state();
}
void Kernel::Scheduler::_run__verbose__success()
{
if (!RUN__VERBOSE)
return;
printf("Kernel::Scheduler::run, ");
_print_clients_via_labels();
printf("\n");
}
void Kernel::Scheduler::_run__error__no_ready_client()
{
if (!SCHEDULER__ERROR) return;
printf("Error in Kernel::Scheduler::run, no client is ready, halt\n");
halt();
}
void Kernel::Scheduler::_remove__trace(Client* c)
{
if (SCHEDULER__TRACE && Verbose::trace_current_kernel_pass())
printf("rm(%i) ", c->label());
}
void Kernel::Scheduler::_run__trace__client_checks()
{
if (SCHEDULER__TRACE && Verbose::trace_current_kernel_pass())
printf("ask(%i,%i) ",
_current_client->label(), _current_client->_quota);
}
void Kernel::Scheduler::_schedule__error__no_clients()
{
if (!SCHEDULER__ERROR) return;
printf("Error in Kernel::Scheduler::_schedule, no clients registered, halt\n");
halt();
}
void Kernel::Scheduler::_remove__warning__invalid_client()
{
if (!SCHEDULER__WARNING) return;
printf("Warning in Kernel::Scheduler::remove, client invalid, skip\n");
}
void Kernel::Scheduler::_add__warning__invalid_client()
{
if (!SCHEDULER__WARNING) return;
printf("Warning in Kernel::Scheduler::add, client invalid, skip\n");
}
void Kernel::Scheduler::_add__verbose__success()
{
if (!ADD__VERBOSE) return;
printf("Kernel::Scheduler::add, ");
_print_clients_via_labels();
printf(" ← )\n");
}
void Kernel::Scheduler::_remove__verbose__success(Client* c)
{
if (!REMOVE__VERBOSE) return;
printf("Kernel::Scheduler::remove, ");
_print_clients_via_labels();
printf(" → %i\n", c->label());
}
void Kernel::Scheduler::_schedule__verbose__success()
{
if (!SCHEDULER__VERBOSE) return;
Client* const a = _last_client;
Client* const b = _current_client;
Verbose::indent(10);
if (a) printf("from %i", a->label());
else printf("from NULL");
Verbose::indent(10);
printf("to %i\n", b->label());
}
/*******************************************
** Kernel::Scheduler::Client definitions **
*******************************************/
Kernel::Scheduler::Client::Context *
Kernel::Scheduler::Client::_schedulable_context()
{
Context *result = 0;
if (!_sleeping) {
result = _context();
if (_sleeping)
result = 0;
}
return result;
}
Kernel::Scheduler::Client::Quota
Kernel::Scheduler::Client::_consume(Quota const &consumed)
{
if (consumed > _quota) {
_quota = 0;
} else{
_quota = _quota - consumed;
}
return _quota;
}
Kernel::Scheduler::Client::Client()
: _quota(0), _scheduler(0), _sleeping(false) { }
void Kernel::Scheduler::Client::_earn_quota(Quota const &q) { _quota += q; }
void Kernel::Scheduler::Client::_sleep() { _sleeping = true; }
void Kernel::Scheduler::Client::_wake(){ _sleeping = false; }
/*************************************************
** Kernel::Scheduler::Client_queue definitions **
*************************************************/
void Kernel::Scheduler::Client_queue::print_state()
{
Client *i = _head;
if (!i) printf("ø");
while (i) {
printf("%i", i->label());
if (i != _tail) printf("");
i = i->_next;
}
}
#endif /* _KERNEL__INCLUDE__SCHEDULER_H_ */