From e33ea2a8b74a41bf28e171f0414e7429cebec7d4 Mon Sep 17 00:00:00 2001 From: Martin Stein Date: Wed, 11 Sep 2013 23:30:57 +0200 Subject: [PATCH] hw: completely release signal-context resources ref #589 --- base-hw/include/kernel/syscalls.h | 2 + .../include/signal_session/signal_session.h | 25 ++++-- base-hw/src/base/signal/signal.cc | 16 +--- .../core/include/signal_session_component.h | 47 ++++++++++- base-hw/src/core/kernel.cc | 3 + base-hw/src/core/signal_session_component.cc | 83 ++++++++++++++----- 6 files changed, 127 insertions(+), 49 deletions(-) diff --git a/base-hw/include/kernel/syscalls.h b/base-hw/include/kernel/syscalls.h index 1c6fa1245..d1a37e246 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 fbaddfbd9..d2290e7d3 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 a04b27102..3ca2e759d 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 84c2c8030..566437e3e 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 4f3d928db..c8d377020 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 370f0cb2a..ddf3ec7fe 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()); +}