hw: separate function declaration/implementation
Move kernel object functions from its headers to compilation units, thereby reducing the kernel's text section, cache, and TLB footprint. Fix #1492
This commit is contained in:
parent
bc3ba380ae
commit
e61a3db30d
|
@ -45,9 +45,12 @@ SRC_CC += thread_start.cc
|
||||||
SRC_CC += rm_session_support.cc
|
SRC_CC += rm_session_support.cc
|
||||||
SRC_CC += pager.cc
|
SRC_CC += pager.cc
|
||||||
SRC_CC += _main.cc
|
SRC_CC += _main.cc
|
||||||
|
SRC_CC += kernel/cpu_scheduler.cc
|
||||||
|
SRC_CC += kernel/double_list.cc
|
||||||
SRC_CC += kernel/kernel.cc
|
SRC_CC += kernel/kernel.cc
|
||||||
SRC_CC += kernel/thread.cc
|
SRC_CC += kernel/thread.cc
|
||||||
SRC_CC += kernel/signal_receiver.cc
|
SRC_CC += kernel/signal_receiver.cc
|
||||||
|
SRC_CC += kernel/ipc_node.cc
|
||||||
SRC_CC += kernel/irq.cc
|
SRC_CC += kernel/irq.cc
|
||||||
SRC_CC += kernel/pd.cc
|
SRC_CC += kernel/pd.cc
|
||||||
SRC_CC += kernel/cpu.cc
|
SRC_CC += kernel/cpu.cc
|
||||||
|
|
|
@ -16,14 +16,12 @@
|
||||||
#define _KERNEL__CPU_H_
|
#define _KERNEL__CPU_H_
|
||||||
|
|
||||||
/* core includes */
|
/* core includes */
|
||||||
#include <translation_table.h>
|
|
||||||
#include <timer.h>
|
#include <timer.h>
|
||||||
#include <cpu.h>
|
#include <cpu.h>
|
||||||
#include <kernel/cpu_scheduler.h>
|
#include <kernel/cpu_scheduler.h>
|
||||||
#include <kernel/irq.h>
|
#include <kernel/irq.h>
|
||||||
|
|
||||||
/* base includes */
|
namespace Genode { class Translation_table; }
|
||||||
#include <unmanaged_singleton.h>
|
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
@ -97,7 +95,7 @@ class Kernel::Cpu_domain_update : public Double_list_item
|
||||||
/**
|
/**
|
||||||
* Domain-update back-end
|
* Domain-update back-end
|
||||||
*/
|
*/
|
||||||
void _domain_update() { Genode::Cpu::flush_tlb_by_pid(_domain_id); }
|
void _domain_update();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform the domain update on the executing CPU
|
* Perform the domain update on the executing CPU
|
||||||
|
@ -106,13 +104,7 @@ class Kernel::Cpu_domain_update : public Double_list_item
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
/**
|
Cpu_domain_update();
|
||||||
* Constructor
|
|
||||||
*/
|
|
||||||
Cpu_domain_update()
|
|
||||||
{
|
|
||||||
for (unsigned i = 0; i < NR_OF_CPUS; i++) { _pending[i] = false; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Do an update of domain 'id' on all CPUs and return if this blocks
|
* Do an update of domain 'id' on all CPUs and return if this blocks
|
||||||
|
@ -177,8 +169,7 @@ class Kernel::Cpu_job : public Cpu_share
|
||||||
/**
|
/**
|
||||||
* Construct a job with scheduling priority 'p' and time quota 'q'
|
* Construct a job with scheduling priority 'p' and time quota 'q'
|
||||||
*/
|
*/
|
||||||
Cpu_job(Cpu_priority const p, unsigned const q)
|
Cpu_job(Cpu_priority const p, unsigned const q);
|
||||||
: Cpu_share(p, q), _cpu(0) { }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destructor
|
* Destructor
|
||||||
|
@ -219,7 +210,7 @@ class Kernel::Cpu_idle : public Genode::Cpu::User_context, public Cpu_job
|
||||||
/**
|
/**
|
||||||
* Main function of all idle threads
|
* Main function of all idle threads
|
||||||
*/
|
*/
|
||||||
static void _main() { while (1) { Genode::Cpu::wait_for_interrupt(); } }
|
static void _main();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -289,11 +280,7 @@ class Kernel::Cpu : public Genode::Cpu,
|
||||||
/**
|
/**
|
||||||
* Construct object for CPU 'id' with scheduling timer 'timer'
|
* Construct object for CPU 'id' with scheduling timer 'timer'
|
||||||
*/
|
*/
|
||||||
Cpu(unsigned const id, Timer * const timer)
|
Cpu(unsigned const id, Timer * const timer);
|
||||||
: _id(id), _idle(this), _timer(timer),
|
|
||||||
_scheduler(&_idle, _quota(), _fill()),
|
|
||||||
_ipi_irq(*this),
|
|
||||||
_timer_irq(_timer->interrupt_id(_id), *this) { }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Raise the IPI of the CPU
|
* Raise the IPI of the CPU
|
||||||
|
@ -306,13 +293,7 @@ class Kernel::Cpu : public Genode::Cpu,
|
||||||
* \param irq_id id of the interrupt that occured
|
* \param irq_id id of the interrupt that occured
|
||||||
* \returns true if the interrupt belongs to this CPU, otherwise false
|
* \returns true if the interrupt belongs to this CPU, otherwise false
|
||||||
*/
|
*/
|
||||||
bool interrupt(unsigned const irq_id)
|
bool interrupt(unsigned const irq_id);
|
||||||
{
|
|
||||||
Irq * const irq = object(irq_id);
|
|
||||||
if (!irq) return false;
|
|
||||||
irq->occurred();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Schedule 'job' at this CPU
|
* Schedule 'job' at this CPU
|
||||||
|
@ -322,32 +303,8 @@ class Kernel::Cpu : public Genode::Cpu,
|
||||||
/**
|
/**
|
||||||
* Handle recent exception of the CPU and proceed its user execution
|
* Handle recent exception of the CPU and proceed its user execution
|
||||||
*/
|
*/
|
||||||
void exception()
|
void exception();
|
||||||
{
|
|
||||||
/* update old job */
|
|
||||||
Job * const old_job = scheduled_job();
|
|
||||||
old_job->exception(_id);
|
|
||||||
|
|
||||||
/* update scheduler */
|
|
||||||
unsigned const old_time = _scheduler.head_quota();
|
|
||||||
unsigned const new_time = _timer->value(_id);
|
|
||||||
unsigned quota = old_time > new_time ? old_time - new_time : 1;
|
|
||||||
_scheduler.update(quota);
|
|
||||||
|
|
||||||
/* get new job */
|
|
||||||
Job * const new_job = scheduled_job();
|
|
||||||
quota = _scheduler.head_quota();
|
|
||||||
assert(quota);
|
|
||||||
_timer->start_one_shot(quota, _id);
|
|
||||||
|
|
||||||
/* switch between lazy state of old and new job */
|
|
||||||
Cpu_lazy_state * const old_state = old_job->lazy_state();
|
|
||||||
Cpu_lazy_state * const new_state = new_job->lazy_state();
|
|
||||||
prepare_proceeding(old_state, new_state);
|
|
||||||
|
|
||||||
/* resume new job */
|
|
||||||
new_job->proceed(_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/***************
|
/***************
|
||||||
** Accessors **
|
** Accessors **
|
||||||
|
@ -372,24 +329,12 @@ class Kernel::Cpu_pool
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
Cpu_pool();
|
||||||
* Construct pool and thereby objects for all available CPUs
|
|
||||||
*/
|
|
||||||
Cpu_pool()
|
|
||||||
{
|
|
||||||
for (unsigned id = 0; id < NR_OF_CPUS; id++) {
|
|
||||||
new (_cpus[id]) Cpu(id, &_timer); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return object of CPU 'id'
|
* Return object of CPU 'id'
|
||||||
*/
|
*/
|
||||||
Cpu * cpu(unsigned const id) const
|
Cpu * cpu(unsigned const id) const;
|
||||||
{
|
|
||||||
assert(id < NR_OF_CPUS);
|
|
||||||
char * const p = const_cast<char *>(_cpus[id]);
|
|
||||||
return reinterpret_cast<Cpu *>(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return object of primary CPU
|
* Return object of primary CPU
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
/* core includes */
|
/* core includes */
|
||||||
#include <util.h>
|
#include <util.h>
|
||||||
#include <assert.h>
|
|
||||||
#include <kernel/configuration.h>
|
#include <kernel/configuration.h>
|
||||||
#include <kernel/double_list.h>
|
#include <kernel/double_list.h>
|
||||||
|
|
||||||
|
@ -137,109 +136,33 @@ class Kernel::Cpu_scheduler
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static Share * _share(T * const t) { return static_cast<Share *>(t); }
|
static Share * _share(T * const t) { return static_cast<Share *>(t); }
|
||||||
|
|
||||||
static void _reset(Claim * const c) {
|
static void _reset(Claim * const c);
|
||||||
_share(c)->_claim = _share(c)->_quota; }
|
|
||||||
|
|
||||||
void _reset_claims(unsigned const p)
|
void _reset_claims(unsigned const p);
|
||||||
{
|
void _next_round();
|
||||||
_rcl[p].for_each([&] (Claim * const c) { _reset(c); });
|
void _consumed(unsigned const q);
|
||||||
_ucl[p].for_each([&] (Claim * const c) { _reset(c); });
|
void _set_head(Share * const s, unsigned const q, bool const c);
|
||||||
}
|
void _next_fill();
|
||||||
|
void _head_claimed(unsigned const r);
|
||||||
void _next_round()
|
void _head_filled(unsigned const r);
|
||||||
{
|
bool _claim_for_head();
|
||||||
_residual = _quota;
|
bool _fill_for_head();
|
||||||
_for_each_prio([&] (unsigned const p) { _reset_claims(p); });
|
unsigned _trim_consumption(unsigned & q);
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fill 's' becomes a claim due to a quota donation
|
* Fill 's' becomes a claim due to a quota donation
|
||||||
*/
|
*/
|
||||||
void _quota_introduction(Share * const s)
|
void _quota_introduction(Share * const s);
|
||||||
{
|
|
||||||
if (s->_ready) { _rcl[s->_prio].insert_tail(s); }
|
|
||||||
else { _ucl[s->_prio].insert_tail(s); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Claim 's' looses its state as claim due to quota revokation
|
* Claim 's' looses its state as claim due to quota revokation
|
||||||
*/
|
*/
|
||||||
void _quota_revokation(Share * const s)
|
void _quota_revokation(Share * const s);
|
||||||
{
|
|
||||||
if (s->_ready) { _rcl[s->_prio].remove(s); }
|
|
||||||
else { _ucl[s->_prio].remove(s); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The quota of claim 's' changes to 'q'
|
* The quota of claim 's' changes to 'q'
|
||||||
*/
|
*/
|
||||||
void _quota_adaption(Share * const s, unsigned const q)
|
void _quota_adaption(Share * const s, unsigned const q);
|
||||||
{
|
|
||||||
if (q) { if (s->_claim > q) { s->_claim = q; } }
|
|
||||||
else { _quota_revokation(s); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -251,104 +174,47 @@ class Kernel::Cpu_scheduler
|
||||||
* \param q total amount of time quota that can be claimed by shares
|
* \param q total amount of time quota that can be claimed by shares
|
||||||
* \param f time-slice length of the fill round-robin
|
* \param f time-slice length of the fill round-robin
|
||||||
*/
|
*/
|
||||||
Cpu_scheduler(Share * const i, unsigned const q, unsigned const f)
|
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); }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update head according to the consumption of quota 'q'
|
* Update head according to the consumption of quota 'q'
|
||||||
*/
|
*/
|
||||||
void update(unsigned 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set 's1' ready and return wether this outdates current head
|
* Set 's1' ready and return wether this outdates current head
|
||||||
*/
|
*/
|
||||||
bool ready_check(Share * const s1)
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set share 's' ready
|
* Set share 's' ready
|
||||||
*/
|
*/
|
||||||
void ready(Share * const s)
|
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); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set share 's' unready
|
* Set share 's' unready
|
||||||
*/
|
*/
|
||||||
void unready(Share * const s)
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Current head looses its current claim/fill for this round
|
* Current head looses its current claim/fill for this round
|
||||||
*/
|
*/
|
||||||
void yield() { _head_yields = 1; }
|
void yield();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove share 's' from scheduler
|
* Remove share 's' from scheduler
|
||||||
*/
|
*/
|
||||||
void remove(Share * const s)
|
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); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert share 's' into scheduler
|
* Insert share 's' into scheduler
|
||||||
*/
|
*/
|
||||||
void insert(Share * const s)
|
void insert(Share * const s);
|
||||||
{
|
|
||||||
assert(!s->_ready);
|
|
||||||
if (!s->_quota) { return; }
|
|
||||||
s->_claim = s->_quota;
|
|
||||||
_ucl[s->_prio].insert_head(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set quota of share 's' to 'q'
|
* Set quota of share 's' to 'q'
|
||||||
*/
|
*/
|
||||||
void quota(Share * const s, unsigned const 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Accessors
|
* Accessors
|
||||||
|
|
|
@ -51,86 +51,40 @@ class Kernel::Double_list
|
||||||
Item * _head;
|
Item * _head;
|
||||||
Item * _tail;
|
Item * _tail;
|
||||||
|
|
||||||
void _connect_neighbors(Item * const i)
|
void _connect_neighbors(Item * const i);
|
||||||
{
|
void _to_tail(Item * const i);
|
||||||
i->_prev->_next = i->_next;
|
|
||||||
i->_next->_prev = i->_prev;
|
|
||||||
}
|
|
||||||
|
|
||||||
void _to_tail(Item * const i)
|
|
||||||
{
|
|
||||||
if (i == _tail) { return; }
|
|
||||||
_connect_neighbors(i);
|
|
||||||
i->_prev = _tail;
|
|
||||||
i->_next = 0;
|
|
||||||
_tail->_next = i;
|
|
||||||
_tail = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct empty list
|
* Construct empty list
|
||||||
*/
|
*/
|
||||||
Double_list(): _head(0), _tail(0) { }
|
Double_list();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Move item 'i' from its current list position to the tail
|
* Move item 'i' from its current list position to the tail
|
||||||
*/
|
*/
|
||||||
void to_tail(Item * const i)
|
void to_tail(Item * const i);
|
||||||
{
|
|
||||||
if (i == _head) { head_to_tail(); }
|
|
||||||
else { _to_tail(i); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert item 'i' as new tail into list
|
* Insert item 'i' as new tail into list
|
||||||
*/
|
*/
|
||||||
void insert_tail(Item * const i)
|
void insert_tail(Item * const i);
|
||||||
{
|
|
||||||
if (_tail) { _tail->_next = i; }
|
|
||||||
else { _head = i; }
|
|
||||||
i->_prev = _tail;
|
|
||||||
i->_next = 0;
|
|
||||||
_tail = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert item 'i' as new head into list
|
* Insert item 'i' as new head into list
|
||||||
*/
|
*/
|
||||||
void insert_head(Item * const i)
|
void insert_head(Item * const i);
|
||||||
{
|
|
||||||
if (_head) { _head->_prev = i; }
|
|
||||||
else { _tail = i; }
|
|
||||||
i->_next = _head;
|
|
||||||
i->_prev = 0;
|
|
||||||
_head = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove item 'i' from list
|
* Remove item 'i' from list
|
||||||
*/
|
*/
|
||||||
void remove(Item * const i)
|
void remove(Item * const i);
|
||||||
{
|
|
||||||
if (i == _tail) { _tail = i->_prev; }
|
|
||||||
else { i->_next->_prev = i->_prev; }
|
|
||||||
if (i == _head) { _head = i->_next; }
|
|
||||||
else { i->_prev->_next = i->_next; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Move head item of list to tail position
|
* Move head item of list to tail position
|
||||||
*/
|
*/
|
||||||
void head_to_tail()
|
void head_to_tail();
|
||||||
{
|
|
||||||
if (!_head || _head == _tail) { return; }
|
|
||||||
_head->_prev = _tail;
|
|
||||||
_tail->_next = _head;
|
|
||||||
_head = _head->_next;
|
|
||||||
_head->_prev = 0;
|
|
||||||
_tail = _tail->_next;
|
|
||||||
_tail->_next = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call function 'f' of type 'void (Item *)' for each item in the list
|
* Call function 'f' of type 'void (Item *)' for each item in the list
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
/* core includes */
|
/* core includes */
|
||||||
#include <kernel/fifo.h>
|
#include <kernel/fifo.h>
|
||||||
#include <assert.h>
|
#include <kernel/interface.h>
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
@ -67,21 +67,7 @@ class Kernel::Ipc_node
|
||||||
/**
|
/**
|
||||||
* Buffer next request from request queue in 'r' to handle it
|
* Buffer next request from request queue in 'r' to handle it
|
||||||
*/
|
*/
|
||||||
void _receive_request(Message_buf * const r)
|
void _receive_request(Message_buf * const r);
|
||||||
{
|
|
||||||
/* FIXME: invalid requests should be discarded */
|
|
||||||
if (r->size > _inbuf.size) {
|
|
||||||
PWRN("oversized request");
|
|
||||||
r->size = _inbuf.size;
|
|
||||||
}
|
|
||||||
/* fetch message */
|
|
||||||
Genode::memcpy(_inbuf.base, r->base, r->size);
|
|
||||||
_inbuf.size = r->size;
|
|
||||||
_inbuf.src = r->src;
|
|
||||||
|
|
||||||
/* update state */
|
|
||||||
_state = PREPARE_REPLY;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Receive a given reply if one is expected
|
* Receive a given reply if one is expected
|
||||||
|
@ -89,105 +75,42 @@ class Kernel::Ipc_node
|
||||||
* \param base base of the reply payload
|
* \param base base of the reply payload
|
||||||
* \param size size of the reply payload
|
* \param size size of the reply payload
|
||||||
*/
|
*/
|
||||||
void _receive_reply(void * const base, size_t const size)
|
void _receive_reply(void * const base, size_t const size);
|
||||||
{
|
|
||||||
/* FIXME: when discard awaited replies userland must get a hint */
|
|
||||||
if (size > _inbuf.size) {
|
|
||||||
PDBG("discard invalid IPC reply");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/* receive reply */
|
|
||||||
Genode::memcpy(_inbuf.base, base, size);
|
|
||||||
_inbuf.size = size;
|
|
||||||
|
|
||||||
/* update state */
|
|
||||||
if (_state != PREPARE_AND_AWAIT_REPLY) { _state = INACTIVE; }
|
|
||||||
else { _state = PREPARE_REPLY; }
|
|
||||||
_send_request_succeeded();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert 'r' into request queue, buffer it if we were waiting for it
|
* Insert 'r' into request queue, buffer it if we were waiting for it
|
||||||
*/
|
*/
|
||||||
void _announce_request(Message_buf * const r)
|
void _announce_request(Message_buf * const r);
|
||||||
{
|
|
||||||
/* directly receive request if we've awaited it */
|
|
||||||
if (_state == AWAIT_REQUEST) {
|
|
||||||
_receive_request(r);
|
|
||||||
_await_request_succeeded();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/* cannot receive yet, so queue request */
|
|
||||||
_request_queue.enqueue(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cancel all requests in request queue
|
* Cancel all requests in request queue
|
||||||
*/
|
*/
|
||||||
void _cancel_request_queue()
|
void _cancel_request_queue();
|
||||||
{
|
|
||||||
while (1) {
|
|
||||||
Message_buf * const r = _request_queue.dequeue();
|
|
||||||
if (!r) { return; }
|
|
||||||
r->src->_outbuf_request_cancelled();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cancel request in outgoing buffer
|
* Cancel request in outgoing buffer
|
||||||
*/
|
*/
|
||||||
void _cancel_outbuf_request()
|
void _cancel_outbuf_request();
|
||||||
{
|
|
||||||
if (_outbuf_dst) {
|
|
||||||
_outbuf_dst->_announced_request_cancelled(&_outbuf);
|
|
||||||
_outbuf_dst = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cancel request in incoming buffer
|
* Cancel request in incoming buffer
|
||||||
*/
|
*/
|
||||||
void _cancel_inbuf_request()
|
void _cancel_inbuf_request();
|
||||||
{
|
|
||||||
if (_inbuf.src) {
|
|
||||||
_inbuf.src->_outbuf_request_cancelled();
|
|
||||||
_inbuf.src = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A request 'r' in inbuf or request queue was cancelled by sender
|
* A request 'r' in inbuf or request queue was cancelled by sender
|
||||||
*/
|
*/
|
||||||
void _announced_request_cancelled(Message_buf * const r)
|
void _announced_request_cancelled(Message_buf * const r);
|
||||||
{
|
|
||||||
if (_inbuf.src == r->src) {
|
|
||||||
_inbuf.src = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_request_queue.remove(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The request in the outbuf was cancelled by receiver
|
* The request in the outbuf was cancelled by receiver
|
||||||
*/
|
*/
|
||||||
void _outbuf_request_cancelled()
|
void _outbuf_request_cancelled();
|
||||||
{
|
|
||||||
if (_outbuf_dst) {
|
|
||||||
_outbuf_dst = 0;
|
|
||||||
if (!_inbuf.src) { _state = INACTIVE; }
|
|
||||||
else { _state = PREPARE_REPLY; }
|
|
||||||
_send_request_failed();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return wether we are the source of a helping relationship
|
* Return wether we are the source of a helping relationship
|
||||||
*/
|
*/
|
||||||
bool _helps_outbuf_dst()
|
bool _helps_outbuf_dst();
|
||||||
{
|
|
||||||
return (_state == PREPARE_AND_AWAIT_REPLY ||
|
|
||||||
_state == AWAIT_REPLY) && _outbuf_dst_help;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IPC node returned from waiting due to reply receipt
|
* IPC node returned from waiting due to reply receipt
|
||||||
|
@ -221,14 +144,8 @@ class Kernel::Ipc_node
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
Ipc_node();
|
||||||
* Constructor
|
~Ipc_node();
|
||||||
*/
|
|
||||||
Ipc_node() : _state(INACTIVE)
|
|
||||||
{
|
|
||||||
_inbuf.src = 0;
|
|
||||||
_outbuf_dst = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a request and wait for the according reply
|
* Send a request and wait for the according reply
|
||||||
|
@ -241,41 +158,12 @@ class Kernel::Ipc_node
|
||||||
*/
|
*/
|
||||||
void send_request(Ipc_node * const dst, void * const buf_base,
|
void send_request(Ipc_node * const dst, void * const buf_base,
|
||||||
size_t const buf_size, size_t const msg_size,
|
size_t const buf_size, size_t const msg_size,
|
||||||
bool help)
|
bool help);
|
||||||
{
|
|
||||||
/* assertions */
|
|
||||||
assert(_state == INACTIVE || _state == PREPARE_REPLY);
|
|
||||||
|
|
||||||
/* prepare transmission of request message */
|
|
||||||
_outbuf.base = buf_base;
|
|
||||||
_outbuf.size = msg_size;
|
|
||||||
_outbuf.src = this;
|
|
||||||
_outbuf_dst = dst;
|
|
||||||
_outbuf_dst_help = 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Prepare reception of reply message but don't clear
|
|
||||||
* '_inbuf.origin' because we might also prepare a reply.
|
|
||||||
*/
|
|
||||||
_inbuf.base = buf_base;
|
|
||||||
_inbuf.size = buf_size;
|
|
||||||
|
|
||||||
/* update state */
|
|
||||||
if (_state != PREPARE_REPLY) { _state = AWAIT_REPLY; }
|
|
||||||
else { _state = PREPARE_AND_AWAIT_REPLY; }
|
|
||||||
|
|
||||||
/* announce request */
|
|
||||||
dst->_announce_request(&_outbuf);
|
|
||||||
|
|
||||||
/* set help relation after announcement to simplify scheduling */
|
|
||||||
_outbuf_dst_help = help;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return root destination of the helping-relation tree we are in
|
* Return root destination of the helping-relation tree we are in
|
||||||
*/
|
*/
|
||||||
Ipc_node * helping_sink() {
|
Ipc_node * helping_sink();
|
||||||
return _helps_outbuf_dst() ? _outbuf_dst->helping_sink() : this; }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call function 'f' of type 'void (Ipc_node *)' for each helper
|
* Call function 'f' of type 'void (Ipc_node *)' for each helper
|
||||||
|
@ -300,25 +188,7 @@ class Kernel::Ipc_node
|
||||||
* \return wether a request could be received already
|
* \return wether a request could be received already
|
||||||
*/
|
*/
|
||||||
bool await_request(void * const buf_base,
|
bool await_request(void * const buf_base,
|
||||||
size_t const buf_size)
|
size_t const buf_size);
|
||||||
{
|
|
||||||
/* assertions */
|
|
||||||
assert(_state == INACTIVE);
|
|
||||||
|
|
||||||
/* prepare receipt of request */
|
|
||||||
_inbuf.base = buf_base;
|
|
||||||
_inbuf.size = buf_size;
|
|
||||||
_inbuf.src = 0;
|
|
||||||
|
|
||||||
/* if anybody already announced a request receive it */
|
|
||||||
if (!_request_queue.empty()) {
|
|
||||||
_receive_request(_request_queue.dequeue());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
/* no request announced, so wait */
|
|
||||||
_state = AWAIT_REQUEST;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reply to last request if there's any
|
* Reply to last request if there's any
|
||||||
|
@ -327,51 +197,12 @@ class Kernel::Ipc_node
|
||||||
* \param msg_size size of reply message
|
* \param msg_size size of reply message
|
||||||
*/
|
*/
|
||||||
void send_reply(void * const msg_base,
|
void send_reply(void * const msg_base,
|
||||||
size_t const msg_size)
|
size_t const msg_size);
|
||||||
{
|
|
||||||
/* reply to the last request if we have to */
|
|
||||||
if (_state == PREPARE_REPLY) {
|
|
||||||
if (_inbuf.src) {
|
|
||||||
_inbuf.src->_receive_reply(msg_base, msg_size);
|
|
||||||
_inbuf.src = 0;
|
|
||||||
}
|
|
||||||
_state = INACTIVE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destructor
|
|
||||||
*/
|
|
||||||
~Ipc_node()
|
|
||||||
{
|
|
||||||
_cancel_request_queue();
|
|
||||||
_cancel_inbuf_request();
|
|
||||||
_cancel_outbuf_request();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If IPC node waits, cancel '_outbuf' to stop waiting
|
* If IPC node waits, cancel '_outbuf' to stop waiting
|
||||||
*/
|
*/
|
||||||
void cancel_waiting()
|
void cancel_waiting();
|
||||||
{
|
|
||||||
switch (_state) {
|
|
||||||
case AWAIT_REPLY:
|
|
||||||
_cancel_outbuf_request();
|
|
||||||
_state = INACTIVE;
|
|
||||||
_send_request_failed();
|
|
||||||
return;
|
|
||||||
case AWAIT_REQUEST:
|
|
||||||
_state = INACTIVE;
|
|
||||||
_await_request_failed();
|
|
||||||
return;
|
|
||||||
case PREPARE_AND_AWAIT_REPLY:
|
|
||||||
_cancel_outbuf_request();
|
|
||||||
_state = PREPARE_REPLY;
|
|
||||||
_send_request_failed();
|
|
||||||
return;
|
|
||||||
default: return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _KERNEL__IPC_NODE_H_ */
|
#endif /* _KERNEL__IPC_NODE_H_ */
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* \brief Kernel lock
|
||||||
|
* \author Martin Stein
|
||||||
|
* \author Stefan Kalkowski
|
||||||
|
* \date 2012-11-30
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012-2015 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__LOCK_H_
|
||||||
|
#define _KERNEL__LOCK_H_
|
||||||
|
|
||||||
|
/* Genode includes */
|
||||||
|
#include <base/lock_guard.h>
|
||||||
|
#include <cpu/atomic.h>
|
||||||
|
#include <cpu/memory_barrier.h>
|
||||||
|
|
||||||
|
namespace Kernel
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Lock that enables synchronization inside the kernel
|
||||||
|
*/
|
||||||
|
class Lock;
|
||||||
|
|
||||||
|
Lock & data_lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
class Kernel::Lock
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
int volatile _locked;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Lock() : _locked(0) { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request the lock
|
||||||
|
*/
|
||||||
|
void lock() { while (!Genode::cmpxchg(&_locked, 0, 1)); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free the lock
|
||||||
|
*/
|
||||||
|
void unlock()
|
||||||
|
{
|
||||||
|
Genode::memory_barrier();
|
||||||
|
_locked = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provide guard semantic for this type of lock
|
||||||
|
*/
|
||||||
|
typedef Genode::Lock_guard<Kernel::Lock> Guard;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* _KERNEL__LOCK_H_ */
|
|
@ -15,62 +15,10 @@
|
||||||
#ifndef _KERNEL__PD_H_
|
#ifndef _KERNEL__PD_H_
|
||||||
#define _KERNEL__PD_H_
|
#define _KERNEL__PD_H_
|
||||||
|
|
||||||
/* Genode includes */
|
|
||||||
#include <cpu/atomic.h>
|
|
||||||
#include <cpu/memory_barrier.h>
|
|
||||||
|
|
||||||
/* core includes */
|
/* core includes */
|
||||||
#include <kernel/early_translations.h>
|
#include <kernel/early_translations.h>
|
||||||
#include <kernel/object.h>
|
#include <kernel/object.h>
|
||||||
#include <kernel/cpu.h>
|
#include <kernel/cpu.h>
|
||||||
#include <assert.h>
|
|
||||||
#include <page_slab.h>
|
|
||||||
|
|
||||||
/* structure of the mode transition */
|
|
||||||
extern int _mt_begin;
|
|
||||||
extern int _mt_end;
|
|
||||||
extern int _mt_user_entry_pic;
|
|
||||||
extern Genode::addr_t _mt_client_context_ptr;
|
|
||||||
extern Genode::addr_t _mt_master_context_begin;
|
|
||||||
extern Genode::addr_t _mt_master_context_end;
|
|
||||||
|
|
||||||
namespace Kernel
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Lock that enables synchronization inside the kernel
|
|
||||||
*/
|
|
||||||
class Lock;
|
|
||||||
}
|
|
||||||
|
|
||||||
class Kernel::Lock
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
|
|
||||||
int volatile _locked;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
Lock() : _locked(0) { }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Request the lock
|
|
||||||
*/
|
|
||||||
void lock() { while (!Genode::cmpxchg(&_locked, 0, 1)); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Free the lock
|
|
||||||
*/
|
|
||||||
void unlock()
|
|
||||||
{
|
|
||||||
Genode::memory_barrier();
|
|
||||||
_locked = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provide guard semantic for this type of lock
|
|
||||||
*/
|
|
||||||
typedef Genode::Lock_guard<Kernel::Lock> Guard;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
@ -99,8 +47,6 @@ namespace Kernel
|
||||||
typedef Object_pool<Pd> Pd_pool;
|
typedef Object_pool<Pd> Pd_pool;
|
||||||
|
|
||||||
Pd_pool * pd_pool();
|
Pd_pool * pd_pool();
|
||||||
|
|
||||||
Lock & data_lock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Kernel::Mode_transition_control
|
class Kernel::Mode_transition_control
|
||||||
|
@ -122,27 +68,17 @@ class Kernel::Mode_transition_control
|
||||||
/**
|
/**
|
||||||
* Return size of the mode transition
|
* Return size of the mode transition
|
||||||
*/
|
*/
|
||||||
static size_t _size() { return (addr_t)&_mt_end - (addr_t)&_mt_begin; }
|
static size_t _size();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return size of master-context space in the mode transition
|
* Return size of master-context space in the mode transition
|
||||||
*/
|
*/
|
||||||
static size_t _master_context_size()
|
static size_t _master_context_size();
|
||||||
{
|
|
||||||
addr_t const begin = (addr_t)&_mt_master_context_begin;
|
|
||||||
addr_t const end = (addr_t)&_mt_master_context_end;
|
|
||||||
return end - begin;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return virtual address of the user entry-code
|
* Return virtual address of the user entry-code
|
||||||
*/
|
*/
|
||||||
static addr_t _virt_user_entry()
|
static addr_t _virt_user_entry();
|
||||||
{
|
|
||||||
addr_t const phys = (addr_t)&_mt_user_entry_pic;
|
|
||||||
addr_t const phys_base = (addr_t)&_mt_begin;
|
|
||||||
return VIRT_BASE + (phys - phys_base);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -167,15 +103,7 @@ class Kernel::Mode_transition_control
|
||||||
* \param ram RAM donation for mapping (first try without)
|
* \param ram RAM donation for mapping (first try without)
|
||||||
*/
|
*/
|
||||||
void map(Genode::Translation_table * tt,
|
void map(Genode::Translation_table * tt,
|
||||||
Genode::Page_slab * alloc)
|
Genode::Page_slab * alloc);
|
||||||
{
|
|
||||||
try {
|
|
||||||
addr_t const phys_base = (addr_t)&_mt_begin;
|
|
||||||
tt->insert_translation(VIRT_BASE, phys_base, SIZE,
|
|
||||||
Page_flags::mode_transition(), alloc);
|
|
||||||
} catch(...) {
|
|
||||||
PERR("Inserting exception vector in page table failed!"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Continue execution of client context
|
* Continue execution of client context
|
||||||
|
@ -188,21 +116,7 @@ class Kernel::Mode_transition_control
|
||||||
void switch_to(Cpu::Context * const context,
|
void switch_to(Cpu::Context * const context,
|
||||||
unsigned const cpu,
|
unsigned const cpu,
|
||||||
addr_t const entry_raw,
|
addr_t const entry_raw,
|
||||||
addr_t const context_ptr_base)
|
addr_t const context_ptr_base);
|
||||||
{
|
|
||||||
/* override client-context pointer of the executing CPU */
|
|
||||||
size_t const context_ptr_offset = cpu * sizeof(context);
|
|
||||||
addr_t const context_ptr = context_ptr_base + context_ptr_offset;
|
|
||||||
*(void * *)context_ptr = context;
|
|
||||||
|
|
||||||
/* unlock kernel data */
|
|
||||||
data_lock().unlock();
|
|
||||||
|
|
||||||
/* call assembly code that applies the virtual-machine context */
|
|
||||||
typedef void (* Entry)();
|
|
||||||
Entry __attribute__((noreturn)) const entry = (Entry)entry_raw;
|
|
||||||
entry();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Continue execution of user context
|
* Continue execution of user context
|
||||||
|
@ -211,11 +125,7 @@ class Kernel::Mode_transition_control
|
||||||
* \param cpu kernel name of targeted CPU
|
* \param cpu kernel name of targeted CPU
|
||||||
*/
|
*/
|
||||||
void switch_to_user(Cpu::Context * const context,
|
void switch_to_user(Cpu::Context * const context,
|
||||||
unsigned const cpu)
|
unsigned const cpu);
|
||||||
{
|
|
||||||
switch_to(context, cpu, _virt_user_entry(),
|
|
||||||
(addr_t)&_mt_client_context_ptr);
|
|
||||||
}
|
|
||||||
} __attribute__((aligned(Mode_transition_control::ALIGN)));
|
} __attribute__((aligned(Mode_transition_control::ALIGN)));
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
#define _KERNEL__SIGNAL_RECEIVER_H_
|
#define _KERNEL__SIGNAL_RECEIVER_H_
|
||||||
|
|
||||||
/* Genode includes */
|
/* Genode includes */
|
||||||
#include <util/fifo.h>
|
|
||||||
#include <base/signal.h>
|
#include <base/signal.h>
|
||||||
|
|
||||||
/* core include */
|
/* core include */
|
||||||
|
@ -92,11 +91,6 @@ class Kernel::Signal_handler
|
||||||
Fifo_element _handlers_fe;
|
Fifo_element _handlers_fe;
|
||||||
Signal_receiver * _receiver;
|
Signal_receiver * _receiver;
|
||||||
|
|
||||||
/**
|
|
||||||
* Backend for for destructor and cancel_waiting
|
|
||||||
*/
|
|
||||||
void _cancel_waiting();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Let the handler block for signal receipt
|
* Let the handler block for signal receipt
|
||||||
*
|
*
|
||||||
|
@ -122,24 +116,13 @@ class Kernel::Signal_handler
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
Signal_handler();
|
||||||
* Constructor
|
virtual ~Signal_handler();
|
||||||
*/
|
|
||||||
Signal_handler()
|
|
||||||
:
|
|
||||||
_handlers_fe(this),
|
|
||||||
_receiver(0)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destructor
|
|
||||||
*/
|
|
||||||
virtual ~Signal_handler() { _cancel_waiting(); }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stop waiting for a signal receiver
|
* Stop waiting for a signal receiver
|
||||||
*/
|
*/
|
||||||
void cancel_waiting() { _cancel_waiting(); }
|
void cancel_waiting();
|
||||||
};
|
};
|
||||||
|
|
||||||
class Kernel::Signal_context_killer
|
class Kernel::Signal_context_killer
|
||||||
|
@ -150,11 +133,6 @@ class Kernel::Signal_context_killer
|
||||||
|
|
||||||
Signal_context * _context;
|
Signal_context * _context;
|
||||||
|
|
||||||
/**
|
|
||||||
* Backend for destructor and cancel_waiting
|
|
||||||
*/
|
|
||||||
void _cancel_waiting();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notice that the kill operation is pending
|
* Notice that the kill operation is pending
|
||||||
*/
|
*/
|
||||||
|
@ -180,20 +158,13 @@ class Kernel::Signal_context_killer
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
Signal_context_killer();
|
||||||
* Constructor
|
virtual ~Signal_context_killer();
|
||||||
*/
|
|
||||||
Signal_context_killer() : _context(0) { }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destructor
|
|
||||||
*/
|
|
||||||
virtual ~Signal_context_killer() { _cancel_waiting(); }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stop waiting for a signal context
|
* Stop waiting for a signal context
|
||||||
*/
|
*/
|
||||||
void cancel_waiting() { _cancel_waiting(); }
|
void cancel_waiting();
|
||||||
};
|
};
|
||||||
|
|
||||||
class Kernel::Signal_context
|
class Kernel::Signal_context
|
||||||
|
@ -239,16 +210,12 @@ class Kernel::Signal_context
|
||||||
/**
|
/**
|
||||||
* Called by receiver when all submits have been delivered
|
* Called by receiver when all submits have been delivered
|
||||||
*/
|
*/
|
||||||
void _delivered()
|
void _delivered();
|
||||||
{
|
|
||||||
_submits = 0;
|
|
||||||
_ack = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notice that the killer of the context has cancelled waiting
|
* Notice that the killer of the context has cancelled waiting
|
||||||
*/
|
*/
|
||||||
void _killer_cancelled() { _killer = 0; }
|
void _killer_cancelled();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -272,11 +239,7 @@ class Kernel::Signal_context
|
||||||
*
|
*
|
||||||
* \param h handler that shall be attached or 0 to detach handler
|
* \param h handler that shall be attached or 0 to detach handler
|
||||||
*/
|
*/
|
||||||
void ack_handler(Signal_ack_handler * const h)
|
void ack_handler(Signal_ack_handler * const h);
|
||||||
{
|
|
||||||
_ack_handler = h ? h : &_default_ack_handler;
|
|
||||||
_ack_handler->_signal_context = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Submit the signal
|
* Submit the signal
|
||||||
|
@ -286,32 +249,12 @@ class Kernel::Signal_context
|
||||||
* \retval 0 succeeded
|
* \retval 0 succeeded
|
||||||
* \retval -1 failed
|
* \retval -1 failed
|
||||||
*/
|
*/
|
||||||
int submit(unsigned const n)
|
int submit(unsigned const n);
|
||||||
{
|
|
||||||
if (_killed || _submits >= (unsigned)~0 - n) { return -1; }
|
|
||||||
_submits += n;
|
|
||||||
if (_ack) { _deliverable(); }
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Acknowledge delivery of signal
|
* Acknowledge delivery of signal
|
||||||
*/
|
*/
|
||||||
void ack()
|
void ack();
|
||||||
{
|
|
||||||
_ack_handler->_signal_acknowledged();
|
|
||||||
if (_ack) { return; }
|
|
||||||
if (!_killed) {
|
|
||||||
_ack = 1;
|
|
||||||
_deliverable();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (_killer) {
|
|
||||||
_killer->_context = 0;
|
|
||||||
_killer->_signal_context_kill_done();
|
|
||||||
_killer = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destruct context or prepare to do it as soon as delivery is done
|
* Destruct context or prepare to do it as soon as delivery is done
|
||||||
|
@ -321,25 +264,7 @@ class Kernel::Signal_context
|
||||||
* \retval 0 succeeded
|
* \retval 0 succeeded
|
||||||
* \retval -1 failed
|
* \retval -1 failed
|
||||||
*/
|
*/
|
||||||
int kill(Signal_context_killer * const k)
|
int kill(Signal_context_killer * const k);
|
||||||
{
|
|
||||||
/* check if in a kill operation or already killed */
|
|
||||||
if (_killed) {
|
|
||||||
if (_ack) { return 0; }
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
/* kill directly if there is no unacknowledged delivery */
|
|
||||||
if (_ack) {
|
|
||||||
_killed = 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/* wait for delivery acknowledgement */
|
|
||||||
_killer = k;
|
|
||||||
_killed = 1;
|
|
||||||
_killer->_context = this;
|
|
||||||
_killer->_signal_context_kill_pending();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Kernel::Signal_receiver
|
class Kernel::Signal_receiver
|
||||||
|
@ -361,79 +286,33 @@ class Kernel::Signal_receiver
|
||||||
/**
|
/**
|
||||||
* Recognize that context 'c' has submits to deliver
|
* Recognize that context 'c' has submits to deliver
|
||||||
*/
|
*/
|
||||||
void _add_deliverable(Signal_context * const c)
|
void _add_deliverable(Signal_context * const c);
|
||||||
{
|
|
||||||
if (!c->_deliver_fe.is_enqueued()) {
|
|
||||||
_deliver.enqueue(&c->_deliver_fe);
|
|
||||||
}
|
|
||||||
_listen();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deliver as much submits as possible
|
* Deliver as much submits as possible
|
||||||
*/
|
*/
|
||||||
void _listen()
|
void _listen();
|
||||||
{
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
/* check for deliverable signals and waiting handlers */
|
|
||||||
if (_deliver.empty() || _handlers.empty()) { return; }
|
|
||||||
|
|
||||||
/* create a signal data-object */
|
|
||||||
typedef Genode::Signal_context * Signal_imprint;
|
|
||||||
auto const context = _deliver.dequeue()->object();
|
|
||||||
auto const imprint =
|
|
||||||
reinterpret_cast<Signal_imprint>(context->_imprint);
|
|
||||||
Signal::Data data(imprint, context->_submits);
|
|
||||||
|
|
||||||
/* communicate signal data to handler */
|
|
||||||
auto const handler = _handlers.dequeue()->object();
|
|
||||||
handler->_receiver = 0;
|
|
||||||
handler->_receive_signal(&data, sizeof(data));
|
|
||||||
context->_delivered();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notice that a context of the receiver has been destructed
|
* Notice that a context of the receiver has been destructed
|
||||||
*
|
*
|
||||||
* \param c destructed context
|
* \param c destructed context
|
||||||
*/
|
*/
|
||||||
void _context_destructed(Signal_context * const c)
|
void _context_destructed(Signal_context * const c);
|
||||||
{
|
|
||||||
_contexts.remove(&c->_contexts_fe);
|
|
||||||
if (!c->_deliver_fe.is_enqueued()) { return; }
|
|
||||||
_deliver.remove(&c->_deliver_fe);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notice that handler 'h' has cancelled waiting
|
* Notice that handler 'h' has cancelled waiting
|
||||||
*/
|
*/
|
||||||
void _handler_cancelled(Signal_handler * const h)
|
void _handler_cancelled(Signal_handler * const h);
|
||||||
{
|
|
||||||
_handlers.remove(&h->_handlers_fe);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assign context 'c' to the receiver
|
* Assign context 'c' to the receiver
|
||||||
*/
|
*/
|
||||||
void _add_context(Signal_context * const c)
|
void _add_context(Signal_context * const c);
|
||||||
{
|
|
||||||
_contexts.enqueue(&c->_contexts_fe);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
~Signal_receiver();
|
||||||
* Destructor
|
|
||||||
*/
|
|
||||||
~Signal_receiver()
|
|
||||||
{
|
|
||||||
/* destruct all attached contexts */
|
|
||||||
while (Signal_context * c = _contexts.dequeue()->object()) {
|
|
||||||
c->~Signal_context();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Let a handler 'h' wait for signals of the receiver
|
* Let a handler 'h' wait for signals of the receiver
|
||||||
|
@ -441,20 +320,12 @@ class Kernel::Signal_receiver
|
||||||
* \retval 0 succeeded
|
* \retval 0 succeeded
|
||||||
* \retval -1 failed
|
* \retval -1 failed
|
||||||
*/
|
*/
|
||||||
int add_handler(Signal_handler * const h)
|
int add_handler(Signal_handler * const h);
|
||||||
{
|
|
||||||
if (h->_receiver) { return -1; }
|
|
||||||
_handlers.enqueue(&h->_handlers_fe);
|
|
||||||
h->_receiver = this;
|
|
||||||
h->_await_signal(this);
|
|
||||||
_listen();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return wether any of the contexts of this receiver is deliverable
|
* Return wether any of the contexts of this receiver is deliverable
|
||||||
*/
|
*/
|
||||||
bool deliverable() { return !_deliver.empty(); }
|
bool deliverable();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _KERNEL__SIGNAL_RECEIVER_ */
|
#endif /* _KERNEL__SIGNAL_RECEIVER_ */
|
||||||
|
|
|
@ -106,8 +106,6 @@ namespace Genode
|
||||||
using Level_1_stage_2_translation_table =
|
using Level_1_stage_2_translation_table =
|
||||||
Level_x_translation_table<Level_2_stage_2_translation_table,
|
Level_x_translation_table<Level_2_stage_2_translation_table,
|
||||||
STAGE2, SIZE_LOG2_256GB>;
|
STAGE2, SIZE_LOG2_256GB>;
|
||||||
|
|
||||||
using Translation_table = Level_1_stage_1_translation_table;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -520,4 +518,7 @@ class Genode::Level_x_translation_table :
|
||||||
this->_range_op(vo, 0, size, Remove_func(slab)); }
|
this->_range_op(vo, 0, size, Remove_func(slab)); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace Genode {
|
||||||
|
class Translation_table : public Level_1_stage_1_translation_table { }; }
|
||||||
|
|
||||||
#endif /* _ARM_V7__LONG_TRANSLATION_TABLE_H_ */
|
#endif /* _ARM_V7__LONG_TRANSLATION_TABLE_H_ */
|
||||||
|
|
|
@ -66,8 +66,6 @@ namespace Genode
|
||||||
Page_directory<Level_3_translation_table,
|
Page_directory<Level_3_translation_table,
|
||||||
SIZE_LOG2_1GB, SIZE_LOG2_512GB>;
|
SIZE_LOG2_1GB, SIZE_LOG2_512GB>;
|
||||||
|
|
||||||
using Translation_table = Pml4_table;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IA-32e common descriptor.
|
* IA-32e common descriptor.
|
||||||
*
|
*
|
||||||
|
@ -683,4 +681,7 @@ class Genode::Pml4_table
|
||||||
}
|
}
|
||||||
} __attribute__((aligned(1 << ALIGNM_LOG2)));
|
} __attribute__((aligned(1 << ALIGNM_LOG2)));
|
||||||
|
|
||||||
|
namespace Genode {
|
||||||
|
class Translation_table : public Pml4_table { }; }
|
||||||
|
|
||||||
#endif /* _TRANSLATION_TABLE_H_ */
|
#endif /* _TRANSLATION_TABLE_H_ */
|
||||||
|
|
|
@ -64,12 +64,6 @@ namespace Kernel
|
||||||
** Cpu_job **
|
** Cpu_job **
|
||||||
*************/
|
*************/
|
||||||
|
|
||||||
Cpu_job::~Cpu_job()
|
|
||||||
{
|
|
||||||
if (!_cpu) { return; }
|
|
||||||
_cpu->scheduler()->remove(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Cpu_job::_activate_own_share() { _cpu->schedule(this); }
|
void Cpu_job::_activate_own_share() { _cpu->schedule(this); }
|
||||||
|
|
||||||
|
|
||||||
|
@ -121,6 +115,17 @@ void Cpu_job::quota(unsigned const q)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Cpu_job::Cpu_job(Cpu_priority const p, unsigned const q)
|
||||||
|
: Cpu_share(p, q), _cpu(0) { }
|
||||||
|
|
||||||
|
|
||||||
|
Cpu_job::~Cpu_job()
|
||||||
|
{
|
||||||
|
if (!_cpu) { return; }
|
||||||
|
_cpu->scheduler()->remove(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**************
|
/**************
|
||||||
** Cpu_idle **
|
** Cpu_idle **
|
||||||
**************/
|
**************/
|
||||||
|
@ -128,6 +133,9 @@ void Cpu_job::quota(unsigned const q)
|
||||||
void Cpu_idle::proceed(unsigned const cpu) { mtc()->switch_to_user(this, cpu); }
|
void Cpu_idle::proceed(unsigned const cpu) { mtc()->switch_to_user(this, cpu); }
|
||||||
|
|
||||||
|
|
||||||
|
void Cpu_idle::_main() { while (1) { Genode::Cpu::wait_for_interrupt(); } }
|
||||||
|
|
||||||
|
|
||||||
/*********
|
/*********
|
||||||
** Cpu **
|
** Cpu **
|
||||||
*********/
|
*********/
|
||||||
|
@ -158,6 +166,50 @@ void Cpu::Ipi::trigger(unsigned const cpu_id)
|
||||||
Cpu::Ipi::Ipi(Irq::Pool &p) : Irq(Pic::IPI, p) { }
|
Cpu::Ipi::Ipi(Irq::Pool &p) : Irq(Pic::IPI, p) { }
|
||||||
|
|
||||||
|
|
||||||
|
bool Cpu::interrupt(unsigned const irq_id)
|
||||||
|
{
|
||||||
|
Irq * const irq = object(irq_id);
|
||||||
|
if (!irq) return false;
|
||||||
|
irq->occurred();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Cpu::exception()
|
||||||
|
{
|
||||||
|
/* update old job */
|
||||||
|
Job * const old_job = scheduled_job();
|
||||||
|
old_job->exception(_id);
|
||||||
|
|
||||||
|
/* update scheduler */
|
||||||
|
unsigned const old_time = _scheduler.head_quota();
|
||||||
|
unsigned const new_time = _timer->value(_id);
|
||||||
|
unsigned quota = old_time > new_time ? old_time - new_time : 1;
|
||||||
|
_scheduler.update(quota);
|
||||||
|
|
||||||
|
/* get new job */
|
||||||
|
Job * const new_job = scheduled_job();
|
||||||
|
quota = _scheduler.head_quota();
|
||||||
|
assert(quota);
|
||||||
|
_timer->start_one_shot(quota, _id);
|
||||||
|
|
||||||
|
/* switch between lazy state of old and new job */
|
||||||
|
Cpu_lazy_state * const old_state = old_job->lazy_state();
|
||||||
|
Cpu_lazy_state * const new_state = new_job->lazy_state();
|
||||||
|
prepare_proceeding(old_state, new_state);
|
||||||
|
|
||||||
|
/* resume new job */
|
||||||
|
new_job->proceed(_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Cpu::Cpu(unsigned const id, Timer * const timer)
|
||||||
|
: _id(id), _idle(this), _timer(timer),
|
||||||
|
_scheduler(&_idle, _quota(), _fill()),
|
||||||
|
_ipi_irq(*this),
|
||||||
|
_timer_irq(_timer->interrupt_id(_id), *this) { }
|
||||||
|
|
||||||
|
|
||||||
/***********************
|
/***********************
|
||||||
** Cpu_domain_update **
|
** Cpu_domain_update **
|
||||||
***********************/
|
***********************/
|
||||||
|
@ -198,3 +250,30 @@ bool Cpu_domain_update::_do_global(unsigned const domain_id)
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Cpu_domain_update::_domain_update() {
|
||||||
|
Genode::Cpu::flush_tlb_by_pid(_domain_id); }
|
||||||
|
|
||||||
|
|
||||||
|
Cpu_domain_update::Cpu_domain_update() {
|
||||||
|
for (unsigned i = 0; i < NR_OF_CPUS; i++) { _pending[i] = false; } }
|
||||||
|
|
||||||
|
|
||||||
|
/**************
|
||||||
|
** Cpu_pool **
|
||||||
|
**************/
|
||||||
|
|
||||||
|
Cpu * Cpu_pool::cpu(unsigned const id) const
|
||||||
|
{
|
||||||
|
assert(id < NR_OF_CPUS);
|
||||||
|
char * const p = const_cast<char *>(_cpus[id]);
|
||||||
|
return reinterpret_cast<Cpu *>(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Cpu_pool::Cpu_pool()
|
||||||
|
{
|
||||||
|
for (unsigned id = 0; id < NR_OF_CPUS; id++) {
|
||||||
|
new (_cpus[id]) Cpu(id, &_timer); }
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,212 @@
|
||||||
|
/*
|
||||||
|
* \brief Schedules CPU shares for the execution time of a CPU
|
||||||
|
* \author Martin Stein
|
||||||
|
* \date 2014-10-09
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2014 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* core includes */
|
||||||
|
#include <kernel/cpu_scheduler.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
using namespace Kernel;
|
||||||
|
|
||||||
|
|
||||||
|
void Cpu_scheduler::_reset(Claim * const c) {
|
||||||
|
_share(c)->_claim = _share(c)->_quota; }
|
||||||
|
|
||||||
|
|
||||||
|
void Cpu_scheduler::_reset_claims(unsigned const p)
|
||||||
|
{
|
||||||
|
_rcl[p].for_each([&] (Claim * const c) { _reset(c); });
|
||||||
|
_ucl[p].for_each([&] (Claim * const c) { _reset(c); });
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Cpu_scheduler::_next_round()
|
||||||
|
{
|
||||||
|
_residual = _quota;
|
||||||
|
_for_each_prio([&] (unsigned const p) { _reset_claims(p); });
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Cpu_scheduler::_consumed(unsigned const q)
|
||||||
|
{
|
||||||
|
if (_residual > q) { _residual -= q; }
|
||||||
|
else { _next_round(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Cpu_scheduler::_set_head(Share * const s, unsigned const q, bool const c)
|
||||||
|
{
|
||||||
|
_head_quota = q;
|
||||||
|
_head_claims = c;
|
||||||
|
_head = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Cpu_scheduler::_next_fill()
|
||||||
|
{
|
||||||
|
_head->_fill = _fill;
|
||||||
|
_fills.head_to_tail();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Cpu_scheduler::_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 Cpu_scheduler::_head_filled(unsigned const r)
|
||||||
|
{
|
||||||
|
if (_fills.head() != _head) { return; }
|
||||||
|
if (r) { _head->_fill = r; }
|
||||||
|
else { _next_fill(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Cpu_scheduler::_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 Cpu_scheduler::_fill_for_head()
|
||||||
|
{
|
||||||
|
Share * const s = _share(_fills.head());
|
||||||
|
if (!s) { return 0; }
|
||||||
|
_set_head(s, s->_fill, 0);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned Cpu_scheduler::_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 Cpu_scheduler::_quota_introduction(Share * const s)
|
||||||
|
{
|
||||||
|
if (s->_ready) { _rcl[s->_prio].insert_tail(s); }
|
||||||
|
else { _ucl[s->_prio].insert_tail(s); }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Cpu_scheduler::_quota_revokation(Share * const s)
|
||||||
|
{
|
||||||
|
if (s->_ready) { _rcl[s->_prio].remove(s); }
|
||||||
|
else { _ucl[s->_prio].remove(s); }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Cpu_scheduler::_quota_adaption(Share * const s, unsigned const q)
|
||||||
|
{
|
||||||
|
if (q) { if (s->_claim > q) { s->_claim = q; } }
|
||||||
|
else { _quota_revokation(s); }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Cpu_scheduler::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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Cpu_scheduler::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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Cpu_scheduler::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 Cpu_scheduler::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 Cpu_scheduler::yield() { _head_yields = 1; }
|
||||||
|
|
||||||
|
|
||||||
|
void Cpu_scheduler::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 Cpu_scheduler::insert(Share * const s)
|
||||||
|
{
|
||||||
|
assert(!s->_ready);
|
||||||
|
if (!s->_quota) { return; }
|
||||||
|
s->_claim = s->_quota;
|
||||||
|
_ucl[s->_prio].insert_head(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Cpu_scheduler::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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Cpu_scheduler::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); }
|
|
@ -0,0 +1,86 @@
|
||||||
|
/*
|
||||||
|
* \brief List of double connected items
|
||||||
|
* \author Martin Stein
|
||||||
|
* \date 2012-11-30
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012-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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* core includes */
|
||||||
|
#include <kernel/double_list.h>
|
||||||
|
|
||||||
|
using namespace Kernel;
|
||||||
|
|
||||||
|
|
||||||
|
void Double_list::_connect_neighbors(Item * const i)
|
||||||
|
{
|
||||||
|
i->_prev->_next = i->_next;
|
||||||
|
i->_next->_prev = i->_prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Double_list::_to_tail(Item * const i)
|
||||||
|
{
|
||||||
|
if (i == _tail) { return; }
|
||||||
|
_connect_neighbors(i);
|
||||||
|
i->_prev = _tail;
|
||||||
|
i->_next = 0;
|
||||||
|
_tail->_next = i;
|
||||||
|
_tail = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Double_list::Double_list(): _head(0), _tail(0) { }
|
||||||
|
|
||||||
|
|
||||||
|
void Double_list::to_tail(Item * const i)
|
||||||
|
{
|
||||||
|
if (i == _head) { head_to_tail(); }
|
||||||
|
else { _to_tail(i); }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Double_list::insert_tail(Item * const i)
|
||||||
|
{
|
||||||
|
if (_tail) { _tail->_next = i; }
|
||||||
|
else { _head = i; }
|
||||||
|
i->_prev = _tail;
|
||||||
|
i->_next = 0;
|
||||||
|
_tail = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Double_list::insert_head(Item * const i)
|
||||||
|
{
|
||||||
|
if (_head) { _head->_prev = i; }
|
||||||
|
else { _tail = i; }
|
||||||
|
i->_next = _head;
|
||||||
|
i->_prev = 0;
|
||||||
|
_head = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Double_list::remove(Item * const i)
|
||||||
|
{
|
||||||
|
if (i == _tail) { _tail = i->_prev; }
|
||||||
|
else { i->_next->_prev = i->_prev; }
|
||||||
|
if (i == _head) { _head = i->_next; }
|
||||||
|
else { i->_prev->_next = i->_next; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Double_list::head_to_tail()
|
||||||
|
{
|
||||||
|
if (!_head || _head == _tail) { return; }
|
||||||
|
_head->_prev = _tail;
|
||||||
|
_tail->_next = _head;
|
||||||
|
_head = _head->_next;
|
||||||
|
_head->_prev = 0;
|
||||||
|
_tail = _tail->_next;
|
||||||
|
_tail->_next = 0;
|
||||||
|
}
|
|
@ -0,0 +1,235 @@
|
||||||
|
/*
|
||||||
|
* \brief Backend for end points of synchronous interprocess communication
|
||||||
|
* \author Martin Stein
|
||||||
|
* \date 2012-11-30
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012-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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Genode includes */
|
||||||
|
#include <util/string.h>
|
||||||
|
|
||||||
|
/* core includes */
|
||||||
|
#include <kernel/ipc_node.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
using namespace Kernel;
|
||||||
|
|
||||||
|
|
||||||
|
void Ipc_node::_receive_request(Message_buf * const r)
|
||||||
|
{
|
||||||
|
/* FIXME: invalid requests should be discarded */
|
||||||
|
if (r->size > _inbuf.size) {
|
||||||
|
PWRN("oversized request");
|
||||||
|
r->size = _inbuf.size;
|
||||||
|
}
|
||||||
|
/* fetch message */
|
||||||
|
Genode::memcpy(_inbuf.base, r->base, r->size);
|
||||||
|
_inbuf.size = r->size;
|
||||||
|
_inbuf.src = r->src;
|
||||||
|
|
||||||
|
/* update state */
|
||||||
|
_state = PREPARE_REPLY;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Ipc_node::_receive_reply(void * const base, size_t const size)
|
||||||
|
{
|
||||||
|
/* FIXME: when discard awaited replies userland must get a hint */
|
||||||
|
if (size > _inbuf.size) {
|
||||||
|
PDBG("discard invalid IPC reply");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* receive reply */
|
||||||
|
Genode::memcpy(_inbuf.base, base, size);
|
||||||
|
_inbuf.size = size;
|
||||||
|
|
||||||
|
/* update state */
|
||||||
|
if (_state != PREPARE_AND_AWAIT_REPLY) { _state = INACTIVE; }
|
||||||
|
else { _state = PREPARE_REPLY; }
|
||||||
|
_send_request_succeeded();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Ipc_node::_announce_request(Message_buf * const r)
|
||||||
|
{
|
||||||
|
/* directly receive request if we've awaited it */
|
||||||
|
if (_state == AWAIT_REQUEST) {
|
||||||
|
_receive_request(r);
|
||||||
|
_await_request_succeeded();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* cannot receive yet, so queue request */
|
||||||
|
_request_queue.enqueue(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Ipc_node::_cancel_request_queue()
|
||||||
|
{
|
||||||
|
while (1) {
|
||||||
|
Message_buf * const r = _request_queue.dequeue();
|
||||||
|
if (!r) { return; }
|
||||||
|
r->src->_outbuf_request_cancelled();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Ipc_node::_cancel_outbuf_request()
|
||||||
|
{
|
||||||
|
if (_outbuf_dst) {
|
||||||
|
_outbuf_dst->_announced_request_cancelled(&_outbuf);
|
||||||
|
_outbuf_dst = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Ipc_node::_cancel_inbuf_request()
|
||||||
|
{
|
||||||
|
if (_inbuf.src) {
|
||||||
|
_inbuf.src->_outbuf_request_cancelled();
|
||||||
|
_inbuf.src = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Ipc_node::_announced_request_cancelled(Message_buf * const r)
|
||||||
|
{
|
||||||
|
if (_inbuf.src == r->src) {
|
||||||
|
_inbuf.src = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_request_queue.remove(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Ipc_node::_outbuf_request_cancelled()
|
||||||
|
{
|
||||||
|
if (_outbuf_dst) {
|
||||||
|
_outbuf_dst = 0;
|
||||||
|
if (!_inbuf.src) { _state = INACTIVE; }
|
||||||
|
else { _state = PREPARE_REPLY; }
|
||||||
|
_send_request_failed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Ipc_node::_helps_outbuf_dst()
|
||||||
|
{
|
||||||
|
return (_state == PREPARE_AND_AWAIT_REPLY ||
|
||||||
|
_state == AWAIT_REPLY) && _outbuf_dst_help;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Ipc_node::send_request(Ipc_node * const dst, void * const buf_base,
|
||||||
|
size_t const buf_size, size_t const msg_size,
|
||||||
|
bool help)
|
||||||
|
{
|
||||||
|
/* assertions */
|
||||||
|
assert(_state == INACTIVE || _state == PREPARE_REPLY);
|
||||||
|
|
||||||
|
/* prepare transmission of request message */
|
||||||
|
_outbuf.base = buf_base;
|
||||||
|
_outbuf.size = msg_size;
|
||||||
|
_outbuf.src = this;
|
||||||
|
_outbuf_dst = dst;
|
||||||
|
_outbuf_dst_help = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prepare reception of reply message but don't clear
|
||||||
|
* '_inbuf.origin' because we might also prepare a reply.
|
||||||
|
*/
|
||||||
|
_inbuf.base = buf_base;
|
||||||
|
_inbuf.size = buf_size;
|
||||||
|
|
||||||
|
/* update state */
|
||||||
|
if (_state != PREPARE_REPLY) { _state = AWAIT_REPLY; }
|
||||||
|
else { _state = PREPARE_AND_AWAIT_REPLY; }
|
||||||
|
|
||||||
|
/* announce request */
|
||||||
|
dst->_announce_request(&_outbuf);
|
||||||
|
|
||||||
|
/* set help relation after announcement to simplify scheduling */
|
||||||
|
_outbuf_dst_help = help;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Ipc_node * Ipc_node::helping_sink() {
|
||||||
|
return _helps_outbuf_dst() ? _outbuf_dst->helping_sink() : this; }
|
||||||
|
|
||||||
|
|
||||||
|
bool Ipc_node::await_request(void * const buf_base,
|
||||||
|
size_t const buf_size)
|
||||||
|
{
|
||||||
|
/* assertions */
|
||||||
|
assert(_state == INACTIVE);
|
||||||
|
|
||||||
|
/* prepare receipt of request */
|
||||||
|
_inbuf.base = buf_base;
|
||||||
|
_inbuf.size = buf_size;
|
||||||
|
_inbuf.src = 0;
|
||||||
|
|
||||||
|
/* if anybody already announced a request receive it */
|
||||||
|
if (!_request_queue.empty()) {
|
||||||
|
_receive_request(_request_queue.dequeue());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/* no request announced, so wait */
|
||||||
|
_state = AWAIT_REQUEST;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Ipc_node::send_reply(void * const msg_base,
|
||||||
|
size_t const msg_size)
|
||||||
|
{
|
||||||
|
/* reply to the last request if we have to */
|
||||||
|
if (_state == PREPARE_REPLY) {
|
||||||
|
if (_inbuf.src) {
|
||||||
|
_inbuf.src->_receive_reply(msg_base, msg_size);
|
||||||
|
_inbuf.src = 0;
|
||||||
|
}
|
||||||
|
_state = INACTIVE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Ipc_node::cancel_waiting()
|
||||||
|
{
|
||||||
|
switch (_state) {
|
||||||
|
case AWAIT_REPLY:
|
||||||
|
_cancel_outbuf_request();
|
||||||
|
_state = INACTIVE;
|
||||||
|
_send_request_failed();
|
||||||
|
return;
|
||||||
|
case AWAIT_REQUEST:
|
||||||
|
_state = INACTIVE;
|
||||||
|
_await_request_failed();
|
||||||
|
return;
|
||||||
|
case PREPARE_AND_AWAIT_REPLY:
|
||||||
|
_cancel_outbuf_request();
|
||||||
|
_state = PREPARE_REPLY;
|
||||||
|
_send_request_failed();
|
||||||
|
return;
|
||||||
|
default: return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Ipc_node::Ipc_node() : _state(INACTIVE)
|
||||||
|
{
|
||||||
|
_inbuf.src = 0;
|
||||||
|
_outbuf_dst = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Ipc_node::~Ipc_node()
|
||||||
|
{
|
||||||
|
_cancel_request_queue();
|
||||||
|
_cancel_inbuf_request();
|
||||||
|
_cancel_outbuf_request();
|
||||||
|
}
|
|
@ -24,6 +24,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* core includes */
|
/* core includes */
|
||||||
|
#include <kernel/lock.h>
|
||||||
#include <kernel/pd.h>
|
#include <kernel/pd.h>
|
||||||
#include <platform_pd.h>
|
#include <platform_pd.h>
|
||||||
#include <trustzone.h>
|
#include <trustzone.h>
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* core includes */
|
/* core includes */
|
||||||
|
#include <kernel/lock.h>
|
||||||
#include <kernel/pd.h>
|
#include <kernel/pd.h>
|
||||||
|
|
||||||
/* Genode includes */
|
/* Genode includes */
|
||||||
|
@ -20,6 +21,75 @@
|
||||||
|
|
||||||
using namespace Kernel;
|
using namespace Kernel;
|
||||||
|
|
||||||
|
/* structure of the mode transition */
|
||||||
|
extern int _mt_begin;
|
||||||
|
extern int _mt_end;
|
||||||
|
extern int _mt_user_entry_pic;
|
||||||
|
extern Genode::addr_t _mt_client_context_ptr;
|
||||||
|
extern Genode::addr_t _mt_master_context_begin;
|
||||||
|
extern Genode::addr_t _mt_master_context_end;
|
||||||
|
|
||||||
|
|
||||||
|
size_t Mode_transition_control::_size() {
|
||||||
|
return (addr_t)&_mt_end - (addr_t)&_mt_begin; }
|
||||||
|
|
||||||
|
|
||||||
|
size_t Mode_transition_control::_master_context_size()
|
||||||
|
{
|
||||||
|
addr_t const begin = (addr_t)&_mt_master_context_begin;
|
||||||
|
addr_t const end = (addr_t)&_mt_master_context_end;
|
||||||
|
return end - begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
addr_t Mode_transition_control::_virt_user_entry()
|
||||||
|
{
|
||||||
|
addr_t const phys = (addr_t)&_mt_user_entry_pic;
|
||||||
|
addr_t const phys_base = (addr_t)&_mt_begin;
|
||||||
|
return VIRT_BASE + (phys - phys_base);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Mode_transition_control::map(Genode::Translation_table * tt,
|
||||||
|
Genode::Page_slab * alloc)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
addr_t const phys_base = (addr_t)&_mt_begin;
|
||||||
|
tt->insert_translation(VIRT_BASE, phys_base, SIZE,
|
||||||
|
Page_flags::mode_transition(), alloc);
|
||||||
|
} catch(...) {
|
||||||
|
PERR("Inserting exception vector in page table failed!"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Mode_transition_control::switch_to(Cpu::Context * const context,
|
||||||
|
unsigned const cpu,
|
||||||
|
addr_t const entry_raw,
|
||||||
|
addr_t const context_ptr_base)
|
||||||
|
{
|
||||||
|
/* override client-context pointer of the executing CPU */
|
||||||
|
size_t const context_ptr_offset = cpu * sizeof(context);
|
||||||
|
addr_t const context_ptr = context_ptr_base + context_ptr_offset;
|
||||||
|
*(void * *)context_ptr = context;
|
||||||
|
|
||||||
|
/* unlock kernel data */
|
||||||
|
data_lock().unlock();
|
||||||
|
|
||||||
|
/* call assembly code that applies the virtual-machine context */
|
||||||
|
typedef void (* Entry)();
|
||||||
|
Entry __attribute__((noreturn)) const entry = (Entry)entry_raw;
|
||||||
|
entry();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Mode_transition_control::switch_to_user(Cpu::Context * const context,
|
||||||
|
unsigned const cpu)
|
||||||
|
{
|
||||||
|
switch_to(context, cpu, _virt_user_entry(),
|
||||||
|
(addr_t)&_mt_client_context_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Mode_transition_control::Mode_transition_control()
|
Mode_transition_control::Mode_transition_control()
|
||||||
: _slab(&_allocator), _master(&_table)
|
: _slab(&_allocator), _master(&_table)
|
||||||
{
|
{
|
||||||
|
|
|
@ -31,7 +31,7 @@ Signal_ack_handler::~Signal_ack_handler()
|
||||||
** Signal_handler **
|
** Signal_handler **
|
||||||
********************/
|
********************/
|
||||||
|
|
||||||
void Signal_handler::_cancel_waiting()
|
void Signal_handler::cancel_waiting()
|
||||||
{
|
{
|
||||||
if (_receiver) {
|
if (_receiver) {
|
||||||
_receiver->_handler_cancelled(this);
|
_receiver->_handler_cancelled(this);
|
||||||
|
@ -40,16 +40,29 @@ void Signal_handler::_cancel_waiting()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Signal_handler::Signal_handler()
|
||||||
|
: _handlers_fe(this), _receiver(0) { }
|
||||||
|
|
||||||
|
|
||||||
|
Signal_handler::~Signal_handler() { cancel_waiting(); }
|
||||||
|
|
||||||
|
|
||||||
/***************************
|
/***************************
|
||||||
** Signal_context_killer **
|
** Signal_context_killer **
|
||||||
***************************/
|
***************************/
|
||||||
|
|
||||||
void Signal_context_killer::_cancel_waiting()
|
void Signal_context_killer::cancel_waiting()
|
||||||
{
|
{
|
||||||
if (_context) { _context->_killer_cancelled(); }
|
if (_context) { _context->_killer_cancelled(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Signal_context_killer::Signal_context_killer() : _context(0) { }
|
||||||
|
|
||||||
|
|
||||||
|
Signal_context_killer::~Signal_context_killer() { cancel_waiting(); }
|
||||||
|
|
||||||
|
|
||||||
/********************
|
/********************
|
||||||
** Signal_context **
|
** Signal_context **
|
||||||
********************/
|
********************/
|
||||||
|
@ -60,6 +73,70 @@ void Signal_context::_deliverable()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Signal_context::_delivered()
|
||||||
|
{
|
||||||
|
_submits = 0;
|
||||||
|
_ack = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Signal_context::_killer_cancelled() { _killer = 0; }
|
||||||
|
|
||||||
|
|
||||||
|
void Signal_context::ack_handler(Signal_ack_handler * const h)
|
||||||
|
{
|
||||||
|
_ack_handler = h ? h : &_default_ack_handler;
|
||||||
|
_ack_handler->_signal_context = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int Signal_context::submit(unsigned const n)
|
||||||
|
{
|
||||||
|
if (_killed || _submits >= (unsigned)~0 - n) { return -1; }
|
||||||
|
_submits += n;
|
||||||
|
if (_ack) { _deliverable(); }
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Signal_context::ack()
|
||||||
|
{
|
||||||
|
_ack_handler->_signal_acknowledged();
|
||||||
|
if (_ack) { return; }
|
||||||
|
if (!_killed) {
|
||||||
|
_ack = 1;
|
||||||
|
_deliverable();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_killer) {
|
||||||
|
_killer->_context = 0;
|
||||||
|
_killer->_signal_context_kill_done();
|
||||||
|
_killer = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int Signal_context::kill(Signal_context_killer * const k)
|
||||||
|
{
|
||||||
|
/* check if in a kill operation or already killed */
|
||||||
|
if (_killed) {
|
||||||
|
if (_ack) { return 0; }
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* kill directly if there is no unacknowledged delivery */
|
||||||
|
if (_ack) {
|
||||||
|
_killed = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* wait for delivery acknowledgement */
|
||||||
|
_killer = k;
|
||||||
|
_killed = 1;
|
||||||
|
_killer->_context = this;
|
||||||
|
_killer->_signal_context_kill_pending();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Signal_context::~Signal_context()
|
Signal_context::~Signal_context()
|
||||||
{
|
{
|
||||||
if (_killer) { _killer->_signal_context_kill_failed(); }
|
if (_killer) { _killer->_signal_context_kill_failed(); }
|
||||||
|
@ -81,3 +158,78 @@ Signal_context::Signal_context(Signal_receiver * const r, unsigned const imprint
|
||||||
{
|
{
|
||||||
r->_add_context(this);
|
r->_add_context(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
** Signal_receiver **
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
void Signal_receiver::_add_deliverable(Signal_context * const c)
|
||||||
|
{
|
||||||
|
if (!c->_deliver_fe.is_enqueued()) {
|
||||||
|
_deliver.enqueue(&c->_deliver_fe);
|
||||||
|
}
|
||||||
|
_listen();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Signal_receiver::_listen()
|
||||||
|
{
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
/* check for deliverable signals and waiting handlers */
|
||||||
|
if (_deliver.empty() || _handlers.empty()) { return; }
|
||||||
|
|
||||||
|
/* create a signal data-object */
|
||||||
|
typedef Genode::Signal_context * Signal_imprint;
|
||||||
|
auto const context = _deliver.dequeue()->object();
|
||||||
|
auto const imprint =
|
||||||
|
reinterpret_cast<Signal_imprint>(context->_imprint);
|
||||||
|
Signal::Data data(imprint, context->_submits);
|
||||||
|
|
||||||
|
/* communicate signal data to handler */
|
||||||
|
auto const handler = _handlers.dequeue()->object();
|
||||||
|
handler->_receiver = 0;
|
||||||
|
handler->_receive_signal(&data, sizeof(data));
|
||||||
|
context->_delivered();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Signal_receiver::_context_destructed(Signal_context * const c)
|
||||||
|
{
|
||||||
|
_contexts.remove(&c->_contexts_fe);
|
||||||
|
if (!c->_deliver_fe.is_enqueued()) { return; }
|
||||||
|
_deliver.remove(&c->_deliver_fe);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Signal_receiver::_handler_cancelled(Signal_handler * const h) {
|
||||||
|
_handlers.remove(&h->_handlers_fe); }
|
||||||
|
|
||||||
|
|
||||||
|
void Signal_receiver::_add_context(Signal_context * const c) {
|
||||||
|
_contexts.enqueue(&c->_contexts_fe); }
|
||||||
|
|
||||||
|
|
||||||
|
int Signal_receiver::add_handler(Signal_handler * const h)
|
||||||
|
{
|
||||||
|
if (h->_receiver) { return -1; }
|
||||||
|
_handlers.enqueue(&h->_handlers_fe);
|
||||||
|
h->_receiver = this;
|
||||||
|
h->_await_signal(this);
|
||||||
|
_listen();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Signal_receiver::deliverable() { return !_deliver.empty(); }
|
||||||
|
|
||||||
|
|
||||||
|
Signal_receiver::~Signal_receiver()
|
||||||
|
{
|
||||||
|
/* destruct all attached contexts */
|
||||||
|
while (Signal_context * c = _contexts.dequeue()->object()) {
|
||||||
|
c->~Signal_context();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -45,6 +45,7 @@ extern void * _vt_vm_entry;
|
||||||
extern void * _vt_host_entry;
|
extern void * _vt_host_entry;
|
||||||
extern Genode::addr_t _vt_vm_context_ptr;
|
extern Genode::addr_t _vt_vm_context_ptr;
|
||||||
extern Genode::addr_t _vt_host_context_ptr;
|
extern Genode::addr_t _vt_host_context_ptr;
|
||||||
|
extern Genode::addr_t _mt_master_context_begin;
|
||||||
|
|
||||||
|
|
||||||
struct Kernel::Vm_irq : Kernel::Irq
|
struct Kernel::Vm_irq : Kernel::Irq
|
||||||
|
|
Loading…
Reference in New Issue