hw: completely release signal-context resources

ref #589
This commit is contained in:
Martin Stein 2013-09-11 23:30:57 +02:00 committed by Norman Feske
parent 2223e72c7f
commit e33ea2a8b7
6 changed files with 127 additions and 49 deletions

View File

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

View File

@ -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);

View File

@ -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 */

View File

@ -19,6 +19,7 @@
#include <base/rpc_server.h>
#include <base/slab.h>
#include <base/allocator_guard.h>
#include <base/object_pool.h>
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> 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_ */

View File

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

View File

@ -13,6 +13,7 @@
/* Genode includes */
#include <base/printf.h>
#include <base/sleep.h>
#include <kernel/syscalls.h>
/* 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<Signal_receiver>(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<Signal_context>(c);
/* return context capability */
return reinterpret_cap_cast<Signal_context>(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());
}