diff --git a/base-hw/include/kernel/syscalls.h b/base-hw/include/kernel/syscalls.h
index 1c6fa1245e..d1a37e2462 100644
--- a/base-hw/include/kernel/syscalls.h
+++ b/base-hw/include/kernel/syscalls.h
@@ -532,6 +532,8 @@ namespace Kernel
* Blocks the caller until the last delivered signal of the targeted
* context is acknowledged. Then the context gets destructed, losing
* all submits that were not delivered when this syscall occured.
+ *
+ * Restricted to core threads.
*/
inline bool kill_signal_context(unsigned context_id) {
return syscall(KILL_SIGNAL_CONTEXT, (Syscall_arg)context_id); }
diff --git a/base-hw/include/signal_session/signal_session.h b/base-hw/include/signal_session/signal_session.h
index fbaddfbd9a..d2290e7d31 100644
--- a/base-hw/include/signal_session/signal_session.h
+++ b/base-hw/include/signal_session/signal_session.h
@@ -54,16 +54,17 @@ namespace Genode
virtual ~Signal_session() { }
/**
- * Create a new signal-receiver kernel-object
+ * Create and manage a new signal receiver
*
* \return a cap that acts as reference to the created object
*
* \throw Out_of_metadata
+ * \throw Exception
*/
virtual Signal_receiver_capability alloc_receiver() = 0;
/**
- * Create a new signal-context kernel-object
+ * Create and manage a new signal context
*
* \param r names the signal receiver that shall provide
* the new context
@@ -73,29 +74,35 @@ namespace Genode
* \return a cap that acts as reference to the created object
*
* \throw Out_of_metadata
+ * \throw Exception
*/
virtual Signal_context_capability
- alloc_context(Signal_receiver_capability const r,
+ alloc_context(Signal_receiver_capability r,
unsigned const imprint) = 0;
/**
- * Free signal-context
+ * Free a signal context
*
* \param cap capability of signal-context to release
+ *
+ * \throw Exception
*/
virtual void free_context(Signal_context_capability cap) = 0;
+
/*********************
** RPC declaration **
*********************/
GENODE_RPC_THROW(Rpc_alloc_receiver, Signal_receiver_capability,
- alloc_receiver, GENODE_TYPE_LIST(Out_of_metadata));
+ alloc_receiver, GENODE_TYPE_LIST(Out_of_metadata,
+ Exception));
GENODE_RPC_THROW(Rpc_alloc_context, Signal_context_capability,
- alloc_context, GENODE_TYPE_LIST(Out_of_metadata),
- Signal_receiver_capability, unsigned);
- GENODE_RPC(Rpc_free_context, void, free_context,
- Signal_context_capability);
+ alloc_context, GENODE_TYPE_LIST(Out_of_metadata,
+ Exception), Signal_receiver_capability, unsigned);
+ GENODE_RPC_THROW(Rpc_free_context, void, free_context,
+ GENODE_TYPE_LIST(Exception),
+ Signal_context_capability);
GENODE_RPC_INTERFACE(Rpc_alloc_receiver, Rpc_alloc_context,
Rpc_free_context);
diff --git a/base-hw/src/base/signal/signal.cc b/base-hw/src/base/signal/signal.cc
index a04b27102b..3ca2e759d5 100644
--- a/base-hw/src/base/signal/signal.cc
+++ b/base-hw/src/base/signal/signal.cc
@@ -111,21 +111,7 @@ Signal_receiver::Signal_receiver()
void Signal_receiver::_unsynchronized_dissolve(Signal_context * c)
{
- /*
- * We first destroy the kernel object. This also ensures
- * that no delivered but unacked signals of this context exist
- * in userland anymore.
- */
- if (!Kernel::kill_signal_context(c->_cap.dst())) {
- PERR("failed to kill signal context");
-
- /* we have to keep the signal context alive for other */
- while (1) ;
- }
- /*
- * Now we can tell core to regain the memory of the
- * destructed kernel object.
- */
+ /* release core resources */
signal_connection()->free_context(c->_cap);
/* reset the context */
diff --git a/base-hw/src/core/include/signal_session_component.h b/base-hw/src/core/include/signal_session_component.h
index 84c2c8030e..566437e3ed 100644
--- a/base-hw/src/core/include/signal_session_component.h
+++ b/base-hw/src/core/include/signal_session_component.h
@@ -19,6 +19,7 @@
#include
#include
#include
+#include
namespace Genode
{
@@ -36,9 +37,17 @@ namespace Genode
private:
+ /**
+ * Maps a signal-context name to related core and kernel resources
+ */
+ class Context;
+
+ typedef Object_pool Context_pool;
+
Allocator_guard _md_alloc;
Slab _receivers_slab;
Slab _contexts_slab;
+ Context_pool _contexts;
char _initial_receivers_sb [RECEIVERS_SB_SIZE];
char _initial_contexts_sb [CONTEXTS_SB_SIZE];
@@ -70,11 +79,41 @@ namespace Genode
Signal_receiver_capability alloc_receiver();
Signal_context_capability
- alloc_context(Signal_receiver_capability const r,
- unsigned const imprint);
- void free_context(Signal_context_capability context_cap);
+ alloc_context(Signal_receiver_capability, unsigned const);
+
+ void free_context(Signal_context_capability);
};
}
-#endif /* _CORE__INCLUDE__CAP_SESSION_COMPONENT_H_ */
+class Genode::Signal_session_component::Context : public Context_pool::Entry
+{
+ public:
+ /**
+ * Constructor
+ */
+ Context(Untyped_capability cap) : Entry(cap) { }
+
+ /**
+ * Name of signal context
+ */
+ unsigned id() const { return Context_pool::Entry::cap().dst(); }
+
+ /**
+ * Size of SLAB block occupied by resources and this resource info
+ */
+ static size_t slab_size()
+ {
+ return sizeof(Context) + Kernel::signal_context_size();
+ }
+
+ /**
+ * Base of region donated to the kernel
+ */
+ static void * kernel_donation(void * const slab_addr)
+ {
+ return (void *)((addr_t)slab_addr + sizeof(Context));
+ }
+};
+
+#endif /* _CORE__INCLUDE__CAP_SESSION_COMPONENT_H_ */
diff --git a/base-hw/src/core/kernel.cc b/base-hw/src/core/kernel.cc
index 4f3d928db5..c8d377020c 100644
--- a/base-hw/src/core/kernel.cc
+++ b/base-hw/src/core/kernel.cc
@@ -702,6 +702,9 @@ namespace Kernel
*/
void do_kill_signal_context(Thread * const user)
{
+ /* check permissions */
+ assert(user->pd_id() == core_id());
+
unsigned id = user->user_arg_1();
Signal_context * const c = Signal_context::pool()->object(id);
if (!c) { return; }
diff --git a/base-hw/src/core/signal_session_component.cc b/base-hw/src/core/signal_session_component.cc
index 370f0cb2ac..ddf3ec7fec 100644
--- a/base-hw/src/core/signal_session_component.cc
+++ b/base-hw/src/core/signal_session_component.cc
@@ -13,6 +13,7 @@
/* Genode includes */
#include
+#include
#include
/* core includes */
@@ -21,12 +22,18 @@
using namespace Genode;
+/**
+ * Placement new
+ */
+void * operator new (size_t, void * p) { return p; }
+
+
Signal_session_component::Signal_session_component(Allocator * const md,
size_t const ram_quota) :
_md_alloc(md, ram_quota),
_receivers_slab(Kernel::signal_receiver_size(), RECEIVERS_SB_SIZE,
(Slab_block *)&_initial_receivers_sb, &_md_alloc),
- _contexts_slab(Kernel::signal_context_size(), CONTEXTS_SB_SIZE,
+ _contexts_slab(Context::slab_size(), CONTEXTS_SB_SIZE,
(Slab_block *)&_initial_contexts_sb, &_md_alloc)
{ }
@@ -40,38 +47,72 @@ Signal_session_component::~Signal_session_component()
Signal_receiver_capability Signal_session_component::alloc_receiver()
{
- /* create receiver kernel-object */
+ /* allocate resources for receiver */
size_t const s = Kernel::signal_receiver_size();
void * p;
- if (!_receivers_slab.alloc(s, &p)) throw Out_of_metadata();
+ if (!_receivers_slab.alloc(s, &p)) {
+ PERR("failed to allocate signal receiver");
+ throw Out_of_metadata();
+ }
+ /* create kernel object for receiver */
unsigned const id = Kernel::new_signal_receiver(p);
- if (!id) throw Out_of_metadata();
-
- /* return reference to the new kernel-object */
- Native_capability c(id, 0);
+ if (!id) {
+ PERR("failed to create signal receiver");
+ throw Exception();
+ }
+ /* return receiver capability */
+ Native_capability c(id, id);
return reinterpret_cap_cast(c);
}
Signal_context_capability
Signal_session_component::alloc_context(Signal_receiver_capability r,
- unsigned imprint)
+ unsigned const imprint)
{
- /* create context kernel-object */
- size_t const s = Kernel::signal_context_size();
+ /* allocate resources for context */
void * p;
- if (!_contexts_slab.alloc(s, &p)) throw Out_of_metadata();
- unsigned const id = Kernel::new_signal_context(p, r.dst(), imprint);
- if (!id) throw Out_of_metadata();
+ if (!_contexts_slab.alloc(Context::slab_size(), &p)) {
+ PERR("failed to allocate signal-context resources");
+ throw Out_of_metadata();
+ }
+ /* create kernel object for context */
+ void * donation = Context::kernel_donation(p);
+ unsigned const id = Kernel::new_signal_context(donation, r.dst(), imprint);
+ if (!id)
+ {
+ /* clean up */
+ _contexts_slab.free(p, Context::slab_size());
+ PERR("failed to create signal context");
+ throw Exception();
+ }
+ /* remember context ressources */
+ Native_capability cap(id, id);
+ _contexts.insert(new (p) Context(cap));
- /* return reference to the new kernel-object */
- Native_capability c(id, 0);
- return reinterpret_cap_cast(c);
+ /* return context capability */
+ return reinterpret_cap_cast(cap);
}
-/**
- * FIXME should regain the kernel-object memory from kernel
- */
-void Signal_session_component::free_context(Signal_context_capability cap) {
- PDBG("Not implemented"); }
+void Signal_session_component::free_context(Signal_context_capability cap)
+{
+ /* lookup ressource info */
+ Context * const c = _contexts.lookup_and_lock(cap);
+ if (!c) {
+ PERR("unknown signal context");
+ throw Exception();
+ }
+ /* release kernel resources */
+ if (!Kernel::kill_signal_context(c->id()))
+ {
+ /* clean-up */
+ c->release();
+ PERR("failed to kill signal context");
+ throw Exception();
+ }
+ /* release core resources */
+ _contexts.remove_locked(c);
+ c->~Context();
+ _contexts_slab.free(c, Context::slab_size());
+}