diff --git a/base-hw/src/core/kernel.cc b/base-hw/src/core/kernel.cc index 7ba97fd99..aea960a8b 100644 --- a/base-hw/src/core/kernel.cc +++ b/base-hw/src/core/kernel.cc @@ -23,7 +23,6 @@ */ /* Genode includes */ -#include #include #include @@ -56,7 +55,7 @@ namespace Kernel { /* import Genode types */ typedef Genode::Thread_state Thread_state; - typedef Genode::umword_t umword_t; + typedef Genode::umword_t umword_t; class Schedule_context; @@ -297,13 +296,6 @@ void Kernel::Thread::await_signal(Kernel::Signal_receiver * receiver) } -void Kernel::Thread::received_signal() -{ - assert(_state == AWAIT_SIGNAL); - _schedule(); -} - - void Kernel::Thread::_received_irq() { assert(_state == AWAIT_IRQ); @@ -361,145 +353,13 @@ void Kernel::Thread::_awaits_irq() namespace Kernel { - class Signal_receiver; - /** - * Specific signal type, owned by a receiver, can be triggered asynchr. - */ - class Signal_context : public Object, - public Fifo::Element + void deliver_signal(Signal_handler * const dst, + void * const base, + size_t const size) { - friend class Signal_receiver; - - Signal_receiver * const _receiver; /* the receiver that owns us */ - unsigned const _imprint; /* every outgoing signals gets - * signed with this */ - unsigned _submits; /* accumul. undelivered submits */ - bool _await_ack; /* delivery ack pending */ - Thread * _killer; /* awaits our destruction if >0 */ - - /** - * Utility to deliver all remaining submits - */ - void _deliver(); - - /** - * Called by receiver when all submits have been delivered - */ - void _delivered() - { - _submits = 0; - _await_ack = 1; - } - - public: - - /** - * Constructor - */ - Signal_context(Signal_receiver * const r, unsigned const imprint) : - _receiver(r), _imprint(imprint), - _submits(0), _await_ack(0), _killer(0) { } - - /** - * Submit the signal - * - * \param n number of submits - */ - void submit(unsigned const n); - - /** - * Acknowledge delivery of signal - */ - void ack(); - - /** - * Destruct or prepare to do it at next call of 'ack' - * - * \return wether destruction is done - */ - bool kill(Thread * const killer) - { - assert(!_killer); - _killer = killer; - if (_await_ack) { - _killer->kill_signal_context_blocks(); - return 0; - } - this->~Signal_context(); - return 1; - } - }; - - /** - * Manage signal contexts and enable threads to trigger and await them - */ - class Signal_receiver : - public Object - { - Fifo _listeners; - Fifo _pending_contexts; - - /** - * Deliver as much submitted signals to listening threads as possible - */ - void _listen() - { - while (1) - { - /* any pending context? */ - if (_pending_contexts.empty()) return; - Signal_context * const c = _pending_contexts.dequeue(); - - /* if there is no listener, enqueue context again and return */ - if (_listeners.empty()) { - _pending_contexts.enqueue(c); - return; - } - /* awake a listener and transmit signal info to it */ - Thread * const t = _listeners.dequeue(); - Signal::Data data((Genode::Signal_context *)c->_imprint, - c->_submits); - *(Signal::Data *)t->phys_utcb()->base() = data; - t->received_signal(); - c->_delivered(); - } - } - - public: - - /** - * Let a thread listen to our contexts - */ - void add_listener(Thread * const t) - { - t->await_signal(this); - _listeners.enqueue(t); - _listen(); - } - - /** - * Stop a thread from listening to our contexts - */ - void remove_listener(Thread * const t) { - _listeners.remove(t); } - - /** - * If any of our contexts is pending - */ - bool pending() { return !_pending_contexts.empty(); } - - /** - * Recognize that 'c' wants to deliver - */ - void deliver(Signal_context * const c) - { - assert(c->_receiver == this); - if (!c->is_enqueued()) _pending_contexts.enqueue(c); - _listen(); - } - }; - + ((Thread *)dst->id())->receive_signal(base, size); + } class Vm : public Object, public Schedule_context @@ -1053,7 +913,8 @@ namespace Kernel assert(r); /* let user listen to receiver */ - r->add_listener(user); + user->await_signal(r); + r->add_handler(user->signal_handler()); } @@ -1068,7 +929,7 @@ namespace Kernel assert(r); /* set return value */ - user->user_arg_0(r->pending()); + user->user_arg_0(r->deliverable()); } @@ -1094,10 +955,11 @@ namespace Kernel */ void do_ack_signal(Thread * const user) { - Signal_context * const c = - Signal_context::pool()->object(user->user_arg_1()); - assert(c); - c->ack(); + unsigned id = user->user_arg_1(); + Signal_context * const c = Signal_context::pool()->object(id); + if (!c) return; + Thread * const t = (Thread *)c->ack(); + if (t) { t->kill_signal_context_done(); } } @@ -1106,10 +968,11 @@ namespace Kernel */ void do_kill_signal_context(Thread * const user) { - Signal_context * const c = - Signal_context::pool()->object(user->user_arg_1()); - assert(c); - user->user_arg_0(c->kill(user)); + unsigned id = user->user_arg_1(); + Signal_context * const c = Signal_context::pool()->object(id); + if (!c) { return; } + if (c->kill((unsigned)user)) { return; } + user->kill_signal_context_blocks(); } /** @@ -1319,7 +1182,7 @@ int Kernel::Thread::resume() return 0; case AWAIT_SIGNAL: PDBG("cancel signal receipt"); - _signal_receiver->remove_listener(this); + _signal_receiver->remove_handler(signal_handler()); _schedule(); return 0; case AWAIT_SIGNAL_CONTEXT_DESTRUCT: @@ -1409,38 +1272,3 @@ void Thread::kill_signal_context_done() user_arg_0(1); _schedule(); } - - -/**************************** - ** Kernel::Signal_context ** - ****************************/ - -void Signal_context::_deliver() -{ - if (!_submits) return; - _receiver->deliver(this); -} - - -void Signal_context::ack() -{ - assert(_await_ack); - _await_ack = 0; - if (!_killer) { - _deliver(); - return; - } - _killer->kill_signal_context_done(); - this->~Signal_context(); -} - - -void Signal_context::submit(unsigned const n) -{ - assert(_submits < (unsigned)~0 - n); - if (_killer) return; - _submits += n; - if (_await_ack) return; - _deliver(); -} - diff --git a/base-hw/src/core/kernel/signal_receiver.h b/base-hw/src/core/kernel/signal_receiver.h index eb0d53846..725b70a22 100644 --- a/base-hw/src/core/kernel/signal_receiver.h +++ b/base-hw/src/core/kernel/signal_receiver.h @@ -21,48 +21,83 @@ /* core include */ #include #include -#include namespace Kernel { - typedef Genode::Signal Signal; - - class Signal_receiver; - - template class Fifo : public Genode::Fifo { }; - - class Signal_listener : public Fifo::Element - { - public: - - virtual void receive_signal(void * const signal_base, - size_t const signal_size) = 0; - }; + /** + * Enables external components to act as a signal handler + */ + class Signal_handler; /** - * Specific signal type, owned by a receiver, can be triggered asynchr. + * Signal types that are assigned to a signal receiver each */ - class Signal_context : public Object, - public Fifo::Element - { - friend class Signal_receiver; + class Signal_context; - Signal_receiver * const _receiver; /* the receiver that owns us */ - unsigned const _imprint; /* every outgoing signals gets - * signed with this */ - unsigned _submits; /* accumul. undelivered submits */ - bool _await_ack; /* delivery ack pending */ + /** + * Combines signal contexts to an entity that handlers can listen to + */ + class Signal_receiver; - /* - * if not zero, _killer_id holds the ID of the actor - * that awaits the destruction of the signal context - */ - unsigned _killer_id; + /** + * Signal delivery backend + * + * \param dst destination + * \param base signal-data base + * \param size signal-data size + */ + void deliver_signal(Signal_handler * const dst, + void * const base, + size_t const size); +} + +class Kernel::Signal_handler +{ + friend class Signal_receiver; + + private: + + typedef Genode::Fifo_element Fifo_element; + + Fifo_element _fe; + unsigned const _id; + + public: /** - * Utility to deliver all remaining submits + * Constructor */ - inline void _deliver(); + Signal_handler(unsigned id) : _fe(this), _id(id) { } + + + /*************** + ** Accessors ** + ***************/ + + unsigned id() { return _id; } +}; + +class Kernel::Signal_context +: + public Object +{ + friend class Signal_receiver; + + private: + + typedef Genode::Fifo_element Fifo_element; + + Fifo_element _fe; + Signal_receiver * const _receiver; + unsigned const _imprint; + unsigned _submits; + bool _ack; + unsigned _killer; + + /** + * Tell receiver about the submits of the context if any + */ + inline void _deliverable(); /** * Called by receiver when all submits have been delivered @@ -70,139 +105,162 @@ namespace Kernel void _delivered() { _submits = 0; - _await_ack = 1; + _ack = 0; } - public: - - /** - * Constructor - */ - Signal_context(Signal_receiver * const r, unsigned const imprint) : - _receiver(r), _imprint(imprint), - _submits(0), _await_ack(0), _killer_id(0) { } - - /** - * Submit the signal - * - * \param n number of submits - */ - void submit(unsigned const n) - { - assert(_submits < (unsigned)~0 - n); - if (_killer_id) { return; } - _submits += n; - if (_await_ack) { return; } - _deliver(); - } - - /** - * Acknowledge delivery of signal - * - * \retval 0 no kill request finished - * \retval > 0 name of finished kill request - */ - unsigned ack() - { - assert(_await_ack); - _await_ack = 0; - if (!_killer_id) { - _deliver(); - return 0; - } - this->~Signal_context(); - return _killer_id; - } - - /** - * Destruct or prepare to do it at next call of 'ack' - * - * \param killer_id name of the kill request - * - * \return wether destruction is done - */ - bool kill(unsigned const killer_id) - { - assert(!_killer_id); - _killer_id = killer_id; - if (_await_ack) { return 0; } - this->~Signal_context(); - return 1; - } - }; - - /** - * Manage signal contexts & enable external actors to trigger & await them - */ - class Signal_receiver : - public Object - { - Fifo _listeners; - Fifo _pending_contexts; + public: /** - * Deliver as much submitted signals to listeners as possible + * Constructor + */ + Signal_context(Signal_receiver * const r, unsigned const imprint) + : + _fe(this), _receiver(r), _imprint(imprint), _submits(0), _ack(1), + _killer(0) + { } + + /** + * Submit the signal + * + * \param n number of submits + */ + void submit(unsigned const n) + { + if (_submits >= (unsigned)~0 - n) { + PERR("overflow at signal-submit count"); + return; + } + if (_killer) { + PERR("signal context already in destruction"); + return; + } + _submits += n; + if (!_ack) { return; } + _deliverable(); + } + + /** + * Acknowledge delivery of signal + * + * \retval 0 no kill request finished + * \retval > 0 name of finished kill request + */ + unsigned ack() + { + if (_ack) { + PERR("unexpected signal acknowledgment"); + return 0; + } + if (!_killer) { + _ack = 1; + _deliverable(); + return 0; + } + this->~Signal_context(); + return _killer; + } + + /** + * Destruct context or prepare to do it as soon as delivery is done + * + * \param killer name of the kill request + * + * \retval 1 destruction is done + * \retval 0 destruction is initiated, will be done with the next ack + */ + bool kill(unsigned const killer) + { + /* FIXME: aggregate or avoid multiple kill requests */ + if (_killer) { + PERR("multiple kill requests"); + while (1) { } + } + _killer = killer; + if (!_ack) { return 0; } + this->~Signal_context(); + return 1; + } +}; + +class Kernel::Signal_receiver +: + public Object +{ + friend class Signal_context; + + private: + + typedef Genode::Signal Signal; + + template class Fifo : public Genode::Fifo { }; + + Fifo _handlers; + Fifo _deliverable; + + /** + * Recognize that context 'c' has submits to deliver + */ + void _add_deliverable(Signal_context * const c) + { + if (!c->_fe.is_enqueued()) _deliverable.enqueue(&c->_fe); + _listen(); + } + + /** + * Deliver as much submits as possible */ void _listen() { while (1) { - /* any pending context? */ - if (_pending_contexts.empty()) return; - Signal_context * const c = _pending_contexts.dequeue(); + /* check if there are deliverable signal */ + if (_deliverable.empty()) return; + Signal_context * const c = _deliverable.dequeue()->object(); - /* if there is no listener, enqueue context again and return */ - if (_listeners.empty()) { - _pending_contexts.enqueue(c); + /* if there is no handler re-enqueue context and exit */ + if (_handlers.empty()) { + _deliverable.enqueue(&c->_fe); return; } - /* awake a listener and transmit signal info to it */ - Signal_listener * const l = _listeners.dequeue(); + /* delivery from context to handler */ + Signal_handler * const h = _handlers.dequeue()->object(); Signal::Data data((Genode::Signal_context *)c->_imprint, - c->_submits); - l->receive_signal(&data, sizeof(data)); + c->_submits); + deliver_signal(h, &data, sizeof(data)); c->_delivered(); } } - public: + public: - /** - * Let a listener listen to the contexts of the receiver - */ - void add_listener(Signal_listener * const l) - { - _listeners.enqueue(l); - _listen(); - } + /** + * Let a handler wait for signals of the receiver + */ + void add_handler(Signal_handler * const h) + { + _handlers.enqueue(&h->_fe); + _listen(); + } - /** - * Stop a listener from listen to the contexts of the receiver - */ - void remove_listener(Signal_listener * const l) { _listeners.remove(l); } + /** + * Stop a handler from waiting for signals of the receiver + */ + void remove_handler(Signal_handler * const h) + { + _handlers.remove(&h->_fe); + } - /** - * Return wether any of the contexts of this receiver is pending - */ - bool pending() { return !_pending_contexts.empty(); } + /** + * Return wether any of the contexts of this receiver is deliverable + */ + bool deliverable() { return !_deliverable.empty(); } +}; - /** - * Recognize that context 'c' wants to be delivered - */ - void deliver(Signal_context * const c) - { - assert(c->_receiver == this); - if (!c->is_enqueued()) _pending_contexts.enqueue(c); - _listen(); - } - }; -} -void Kernel::Signal_context::_deliver() +void Kernel::Signal_context::_deliverable() { if (!_submits) return; - _receiver->deliver(this); + _receiver->_add_deliverable(this); } - #endif /* _KERNEL__SIGNAL_RECEIVER_ */ diff --git a/base-hw/src/core/kernel/thread.h b/base-hw/src/core/kernel/thread.h index 33c05c0a8..0ee8f6400 100644 --- a/base-hw/src/core/kernel/thread.h +++ b/base-hw/src/core/kernel/thread.h @@ -15,6 +15,7 @@ #define _CORE__KERNEL__THREAD_H_ /* core includes */ +#include #include #include #include @@ -34,7 +35,6 @@ namespace Kernel typedef Genode::Cpu Cpu; typedef Genode::Page_flags Page_flags; typedef Genode::Core_tlb Core_tlb; - typedef Genode::Signal Signal; typedef Genode::Pagefault Pagefault; typedef Genode::Native_utcb Native_utcb; @@ -52,15 +52,12 @@ namespace Kernel virtual void proceed() = 0; }; - template class Fifo : public Genode::Fifo { }; - /** * Kernel representation of a user thread */ class Thread : public Cpu::User_context, public Object, public Schedule_context, - public Fifo::Element, public Ipc_node, public Irq_receiver { @@ -84,8 +81,8 @@ namespace Kernel unsigned _pd_id; /* ID of the PD this thread runs on */ Native_utcb * _phys_utcb; /* physical UTCB base */ Native_utcb * _virt_utcb; /* virtual UTCB base */ - Signal_receiver * _signal_receiver; /* receiver we are currently - * listen to */ + Signal_receiver * _signal_receiver; + Signal_handler _signal_handler; /** * Resume execution @@ -112,15 +109,24 @@ namespace Kernel public: + void receive_signal(void * const base, size_t const size) + { + assert(_state == AWAIT_SIGNAL); + assert(size <= phys_utcb()->size()) + Genode::memcpy(phys_utcb()->base(), base, size); + _schedule(); + } + void * operator new (size_t, void * p) { return p; } /** * Constructor */ - Thread(Platform_thread * const platform_thread) : - _platform_thread(platform_thread), - _state(AWAIT_START), _pager(0), _pd_id(0), - _phys_utcb(0), _virt_utcb(0), _signal_receiver(0) + Thread(Platform_thread * const platform_thread) + : + _platform_thread(platform_thread), _state(AWAIT_START), + _pager(0), _pd_id(0), _phys_utcb(0), _virt_utcb(0), + _signal_receiver(0), _signal_handler((unsigned)this) { } /** @@ -210,11 +216,6 @@ namespace Kernel */ void await_signal(Kernel::Signal_receiver * receiver); - /** - * Gets called when we have received a signal at a signal receiver - */ - void received_signal(); - /** * Handle the exception that currently blocks this thread */ @@ -241,6 +242,8 @@ namespace Kernel unsigned pd_id() const { return _pd_id; } Native_utcb * phys_utcb() const { return _phys_utcb; } + + Signal_handler * signal_handler() { return &_signal_handler; } }; }