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; }
};
}