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 * Blocks the caller until the last delivered signal of the targeted
* context is acknowledged. Then the context gets destructed, losing * context is acknowledged. Then the context gets destructed, losing
* all submits that were not delivered when this syscall occured. * all submits that were not delivered when this syscall occured.
*
* Restricted to core threads.
*/ */
inline bool kill_signal_context(unsigned context_id) { inline bool kill_signal_context(unsigned context_id) {
return syscall(KILL_SIGNAL_CONTEXT, (Syscall_arg)context_id); } return syscall(KILL_SIGNAL_CONTEXT, (Syscall_arg)context_id); }

View File

@ -54,16 +54,17 @@ namespace Genode
virtual ~Signal_session() { } 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 * \return a cap that acts as reference to the created object
* *
* \throw Out_of_metadata * \throw Out_of_metadata
* \throw Exception
*/ */
virtual Signal_receiver_capability alloc_receiver() = 0; 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 * \param r names the signal receiver that shall provide
* the new context * the new context
@ -73,29 +74,35 @@ namespace Genode
* \return a cap that acts as reference to the created object * \return a cap that acts as reference to the created object
* *
* \throw Out_of_metadata * \throw Out_of_metadata
* \throw Exception
*/ */
virtual Signal_context_capability virtual Signal_context_capability
alloc_context(Signal_receiver_capability const r, alloc_context(Signal_receiver_capability r,
unsigned const imprint) = 0; unsigned const imprint) = 0;
/** /**
* Free signal-context * Free a signal context
* *
* \param cap capability of signal-context to release * \param cap capability of signal-context to release
*
* \throw Exception
*/ */
virtual void free_context(Signal_context_capability cap) = 0; virtual void free_context(Signal_context_capability cap) = 0;
/********************* /*********************
** RPC declaration ** ** RPC declaration **
*********************/ *********************/
GENODE_RPC_THROW(Rpc_alloc_receiver, Signal_receiver_capability, 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, GENODE_RPC_THROW(Rpc_alloc_context, Signal_context_capability,
alloc_context, GENODE_TYPE_LIST(Out_of_metadata), alloc_context, GENODE_TYPE_LIST(Out_of_metadata,
Signal_receiver_capability, unsigned); Exception), Signal_receiver_capability, unsigned);
GENODE_RPC(Rpc_free_context, void, free_context, GENODE_RPC_THROW(Rpc_free_context, void, free_context,
Signal_context_capability); GENODE_TYPE_LIST(Exception),
Signal_context_capability);
GENODE_RPC_INTERFACE(Rpc_alloc_receiver, Rpc_alloc_context, GENODE_RPC_INTERFACE(Rpc_alloc_receiver, Rpc_alloc_context,
Rpc_free_context); Rpc_free_context);

View File

@ -111,21 +111,7 @@ Signal_receiver::Signal_receiver()
void Signal_receiver::_unsynchronized_dissolve(Signal_context * c) void Signal_receiver::_unsynchronized_dissolve(Signal_context * c)
{ {
/* /* release core resources */
* 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.
*/
signal_connection()->free_context(c->_cap); signal_connection()->free_context(c->_cap);
/* reset the context */ /* reset the context */

View File

@ -19,6 +19,7 @@
#include <base/rpc_server.h> #include <base/rpc_server.h>
#include <base/slab.h> #include <base/slab.h>
#include <base/allocator_guard.h> #include <base/allocator_guard.h>
#include <base/object_pool.h>
namespace Genode namespace Genode
{ {
@ -36,9 +37,17 @@ namespace Genode
private: private:
/**
* Maps a signal-context name to related core and kernel resources
*/
class Context;
typedef Object_pool<Context> Context_pool;
Allocator_guard _md_alloc; Allocator_guard _md_alloc;
Slab _receivers_slab; Slab _receivers_slab;
Slab _contexts_slab; Slab _contexts_slab;
Context_pool _contexts;
char _initial_receivers_sb [RECEIVERS_SB_SIZE]; char _initial_receivers_sb [RECEIVERS_SB_SIZE];
char _initial_contexts_sb [CONTEXTS_SB_SIZE]; char _initial_contexts_sb [CONTEXTS_SB_SIZE];
@ -70,11 +79,41 @@ namespace Genode
Signal_receiver_capability alloc_receiver(); Signal_receiver_capability alloc_receiver();
Signal_context_capability Signal_context_capability
alloc_context(Signal_receiver_capability const r, alloc_context(Signal_receiver_capability, unsigned const);
unsigned const imprint);
void free_context(Signal_context_capability context_cap); 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) void do_kill_signal_context(Thread * const user)
{ {
/* check permissions */
assert(user->pd_id() == core_id());
unsigned id = user->user_arg_1(); unsigned id = user->user_arg_1();
Signal_context * const c = Signal_context::pool()->object(id); Signal_context * const c = Signal_context::pool()->object(id);
if (!c) { return; } if (!c) { return; }

View File

@ -13,6 +13,7 @@
/* Genode includes */ /* Genode includes */
#include <base/printf.h> #include <base/printf.h>
#include <base/sleep.h>
#include <kernel/syscalls.h> #include <kernel/syscalls.h>
/* core includes */ /* core includes */
@ -21,12 +22,18 @@
using namespace Genode; using namespace Genode;
/**
* Placement new
*/
void * operator new (size_t, void * p) { return p; }
Signal_session_component::Signal_session_component(Allocator * const md, Signal_session_component::Signal_session_component(Allocator * const md,
size_t const ram_quota) : size_t const ram_quota) :
_md_alloc(md, ram_quota), _md_alloc(md, ram_quota),
_receivers_slab(Kernel::signal_receiver_size(), RECEIVERS_SB_SIZE, _receivers_slab(Kernel::signal_receiver_size(), RECEIVERS_SB_SIZE,
(Slab_block *)&_initial_receivers_sb, &_md_alloc), (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) (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() Signal_receiver_capability Signal_session_component::alloc_receiver()
{ {
/* create receiver kernel-object */ /* allocate resources for receiver */
size_t const s = Kernel::signal_receiver_size(); size_t const s = Kernel::signal_receiver_size();
void * p; 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); unsigned const id = Kernel::new_signal_receiver(p);
if (!id) throw Out_of_metadata(); if (!id) {
PERR("failed to create signal receiver");
/* return reference to the new kernel-object */ throw Exception();
Native_capability c(id, 0); }
/* return receiver capability */
Native_capability c(id, id);
return reinterpret_cap_cast<Signal_receiver>(c); return reinterpret_cap_cast<Signal_receiver>(c);
} }
Signal_context_capability Signal_context_capability
Signal_session_component::alloc_context(Signal_receiver_capability r, Signal_session_component::alloc_context(Signal_receiver_capability r,
unsigned imprint) unsigned const imprint)
{ {
/* create context kernel-object */ /* allocate resources for context */
size_t const s = Kernel::signal_context_size();
void * p; void * p;
if (!_contexts_slab.alloc(s, &p)) throw Out_of_metadata(); if (!_contexts_slab.alloc(Context::slab_size(), &p)) {
unsigned const id = Kernel::new_signal_context(p, r.dst(), imprint); PERR("failed to allocate signal-context resources");
if (!id) throw Out_of_metadata(); 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 */ /* return context capability */
Native_capability c(id, 0); return reinterpret_cap_cast<Signal_context>(cap);
return reinterpret_cap_cast<Signal_context>(c);
} }
/**
* 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());
}