|
|
|
@ -16,7 +16,6 @@
|
|
|
|
|
|
|
|
|
|
/* core includes */
|
|
|
|
|
#include <util.h>
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
#include <kernel/configuration.h>
|
|
|
|
|
#include <kernel/double_list.h>
|
|
|
|
|
|
|
|
|
@ -137,109 +136,33 @@ class Kernel::Cpu_scheduler
|
|
|
|
|
template <typename T>
|
|
|
|
|
static Share * _share(T * const t) { return static_cast<Share *>(t); }
|
|
|
|
|
|
|
|
|
|
static void _reset(Claim * const c) {
|
|
|
|
|
_share(c)->_claim = _share(c)->_quota; }
|
|
|
|
|
static void _reset(Claim * const c);
|
|
|
|
|
|
|
|
|
|
void _reset_claims(unsigned const p)
|
|
|
|
|
{
|
|
|
|
|
_rcl[p].for_each([&] (Claim * const c) { _reset(c); });
|
|
|
|
|
_ucl[p].for_each([&] (Claim * const c) { _reset(c); });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void _next_round()
|
|
|
|
|
{
|
|
|
|
|
_residual = _quota;
|
|
|
|
|
_for_each_prio([&] (unsigned const p) { _reset_claims(p); });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void _consumed(unsigned const q)
|
|
|
|
|
{
|
|
|
|
|
if (_residual > q) { _residual -= q; }
|
|
|
|
|
else { _next_round(); }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void _set_head(Share * const s, unsigned const q, bool const c)
|
|
|
|
|
{
|
|
|
|
|
_head_quota = q;
|
|
|
|
|
_head_claims = c;
|
|
|
|
|
_head = s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void _next_fill()
|
|
|
|
|
{
|
|
|
|
|
_head->_fill = _fill;
|
|
|
|
|
_fills.head_to_tail();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void _head_claimed(unsigned const r)
|
|
|
|
|
{
|
|
|
|
|
if (!_head->_quota) { return; }
|
|
|
|
|
_head->_claim = r > _head->_quota ? _head->_quota : r;
|
|
|
|
|
if (_head->_claim || !_head->_ready) { return; }
|
|
|
|
|
_rcl[_head->_prio].to_tail(_head);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void _head_filled(unsigned const r)
|
|
|
|
|
{
|
|
|
|
|
if (_fills.head() != _head) { return; }
|
|
|
|
|
if (r) { _head->_fill = r; }
|
|
|
|
|
else { _next_fill(); }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool _claim_for_head()
|
|
|
|
|
{
|
|
|
|
|
for (signed p = Prio::max; p > Prio::min - 1; p--) {
|
|
|
|
|
Share * const s = _share(_rcl[p].head());
|
|
|
|
|
if (!s) { continue; }
|
|
|
|
|
if (!s->_claim) { continue; }
|
|
|
|
|
_set_head(s, s->_claim, 1);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool _fill_for_head()
|
|
|
|
|
{
|
|
|
|
|
Share * const s = _share(_fills.head());
|
|
|
|
|
if (!s) { return 0; }
|
|
|
|
|
_set_head(s, s->_fill, 0);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsigned _trim_consumption(unsigned & q)
|
|
|
|
|
{
|
|
|
|
|
q = Genode::min(Genode::min(q, _head_quota), _residual);
|
|
|
|
|
if (!_head_yields) { return _head_quota - q; }
|
|
|
|
|
_head_yields = 0;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
void _reset_claims(unsigned const p);
|
|
|
|
|
void _next_round();
|
|
|
|
|
void _consumed(unsigned const q);
|
|
|
|
|
void _set_head(Share * const s, unsigned const q, bool const c);
|
|
|
|
|
void _next_fill();
|
|
|
|
|
void _head_claimed(unsigned const r);
|
|
|
|
|
void _head_filled(unsigned const r);
|
|
|
|
|
bool _claim_for_head();
|
|
|
|
|
bool _fill_for_head();
|
|
|
|
|
unsigned _trim_consumption(unsigned & q);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Fill 's' becomes a claim due to a quota donation
|
|
|
|
|
*/
|
|
|
|
|
void _quota_introduction(Share * const s)
|
|
|
|
|
{
|
|
|
|
|
if (s->_ready) { _rcl[s->_prio].insert_tail(s); }
|
|
|
|
|
else { _ucl[s->_prio].insert_tail(s); }
|
|
|
|
|
}
|
|
|
|
|
void _quota_introduction(Share * const s);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Claim 's' looses its state as claim due to quota revokation
|
|
|
|
|
*/
|
|
|
|
|
void _quota_revokation(Share * const s)
|
|
|
|
|
{
|
|
|
|
|
if (s->_ready) { _rcl[s->_prio].remove(s); }
|
|
|
|
|
else { _ucl[s->_prio].remove(s); }
|
|
|
|
|
}
|
|
|
|
|
void _quota_revokation(Share * const s);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The quota of claim 's' changes to 'q'
|
|
|
|
|
*/
|
|
|
|
|
void _quota_adaption(Share * const s, unsigned const q)
|
|
|
|
|
{
|
|
|
|
|
if (q) { if (s->_claim > q) { s->_claim = q; } }
|
|
|
|
|
else { _quota_revokation(s); }
|
|
|
|
|
}
|
|
|
|
|
void _quota_adaption(Share * const s, unsigned const q);
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
|
@ -251,104 +174,47 @@ class Kernel::Cpu_scheduler
|
|
|
|
|
* \param q total amount of time quota that can be claimed by shares
|
|
|
|
|
* \param f time-slice length of the fill round-robin
|
|
|
|
|
*/
|
|
|
|
|
Cpu_scheduler(Share * const i, unsigned const q, unsigned const f)
|
|
|
|
|
: _idle(i), _head_yields(0), _quota(q), _residual(q), _fill(f)
|
|
|
|
|
{ _set_head(i, f, 0); }
|
|
|
|
|
Cpu_scheduler(Share * const i, unsigned const q, unsigned const f);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Update head according to the consumption of quota 'q'
|
|
|
|
|
*/
|
|
|
|
|
void update(unsigned q)
|
|
|
|
|
{
|
|
|
|
|
unsigned const r = _trim_consumption(q);
|
|
|
|
|
if (_head_claims) { _head_claimed(r); }
|
|
|
|
|
else { _head_filled(r); }
|
|
|
|
|
_consumed(q);
|
|
|
|
|
if (_claim_for_head()) { return; }
|
|
|
|
|
if (_fill_for_head()) { return; }
|
|
|
|
|
_set_head(_idle, _fill, 0);
|
|
|
|
|
}
|
|
|
|
|
void update(unsigned q);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Set 's1' ready and return wether this outdates current head
|
|
|
|
|
*/
|
|
|
|
|
bool ready_check(Share * const s1)
|
|
|
|
|
{
|
|
|
|
|
ready(s1);
|
|
|
|
|
Share * s2 = _head;
|
|
|
|
|
if (!s1->_claim) { return s2 == _idle; }
|
|
|
|
|
if (!_head_claims) { return 1; }
|
|
|
|
|
if (s1->_prio != s2->_prio) { return s1->_prio > s2->_prio; }
|
|
|
|
|
for (; s2 && s2 != s1; s2 = _share(Claim_list::next(s2))) ;
|
|
|
|
|
return !s2;
|
|
|
|
|
}
|
|
|
|
|
bool ready_check(Share * const s1);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Set share 's' ready
|
|
|
|
|
*/
|
|
|
|
|
void ready(Share * const s)
|
|
|
|
|
{
|
|
|
|
|
assert(!s->_ready && s != _idle);
|
|
|
|
|
s->_ready = 1;
|
|
|
|
|
s->_fill = _fill;
|
|
|
|
|
_fills.insert_tail(s);
|
|
|
|
|
if (!s->_quota) { return; }
|
|
|
|
|
_ucl[s->_prio].remove(s);
|
|
|
|
|
if (s->_claim) { _rcl[s->_prio].insert_head(s); }
|
|
|
|
|
else { _rcl[s->_prio].insert_tail(s); }
|
|
|
|
|
}
|
|
|
|
|
void ready(Share * const s);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Set share 's' unready
|
|
|
|
|
*/
|
|
|
|
|
void unready(Share * const s)
|
|
|
|
|
{
|
|
|
|
|
assert(s->_ready && s != _idle);
|
|
|
|
|
s->_ready = 0;
|
|
|
|
|
_fills.remove(s);
|
|
|
|
|
if (!s->_quota) { return; }
|
|
|
|
|
_rcl[s->_prio].remove(s);
|
|
|
|
|
_ucl[s->_prio].insert_tail(s);
|
|
|
|
|
}
|
|
|
|
|
void unready(Share * const s);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Current head looses its current claim/fill for this round
|
|
|
|
|
*/
|
|
|
|
|
void yield() { _head_yields = 1; }
|
|
|
|
|
void yield();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Remove share 's' from scheduler
|
|
|
|
|
*/
|
|
|
|
|
void remove(Share * const s)
|
|
|
|
|
{
|
|
|
|
|
assert(s != _idle && s != _head);
|
|
|
|
|
if (s->_ready) { _fills.remove(s); }
|
|
|
|
|
if (!s->_quota) { return; }
|
|
|
|
|
if (s->_ready) { _rcl[s->_prio].remove(s); }
|
|
|
|
|
else { _ucl[s->_prio].remove(s); }
|
|
|
|
|
}
|
|
|
|
|
void remove(Share * const s);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Insert share 's' into scheduler
|
|
|
|
|
*/
|
|
|
|
|
void insert(Share * const s)
|
|
|
|
|
{
|
|
|
|
|
assert(!s->_ready);
|
|
|
|
|
if (!s->_quota) { return; }
|
|
|
|
|
s->_claim = s->_quota;
|
|
|
|
|
_ucl[s->_prio].insert_head(s);
|
|
|
|
|
}
|
|
|
|
|
void insert(Share * const s);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Set quota of share 's' to 'q'
|
|
|
|
|
*/
|
|
|
|
|
void quota(Share * const s, unsigned const q)
|
|
|
|
|
{
|
|
|
|
|
assert(s != _idle);
|
|
|
|
|
if (s->_quota) { _quota_adaption(s, q); }
|
|
|
|
|
else if (q) { _quota_introduction(s); }
|
|
|
|
|
s->_quota = q;
|
|
|
|
|
}
|
|
|
|
|
void quota(Share * const s, unsigned const q);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Accessors
|
|
|
|
|