hw: destruct signal receivers

ref #589
This commit is contained in:
Martin Stein 2013-09-12 00:48:27 +02:00 committed by Norman Feske
parent e07781dc1c
commit 84c31a7ea1
11 changed files with 632 additions and 310 deletions

View File

@ -73,6 +73,7 @@ namespace Kernel
/* asynchronous signalling */ /* asynchronous signalling */
NEW_SIGNAL_RECEIVER = 20, NEW_SIGNAL_RECEIVER = 20,
KILL_SIGNAL_RECEIVER = 33,
NEW_SIGNAL_CONTEXT = 21, NEW_SIGNAL_CONTEXT = 21,
KILL_SIGNAL_CONTEXT = 30, KILL_SIGNAL_CONTEXT = 30,
AWAIT_SIGNAL = 22, AWAIT_SIGNAL = 22,
@ -438,105 +439,129 @@ namespace Kernel
/** /**
* Create a kernel object that acts as receiver for asynchronous signals * Create a kernel object that acts as receiver for asynchronous signals
* *
* \param dst physical base of an appropriate portion of memory * \param p appropriate memory donation for the kernel object
* that is thereupon allocated to the kernel
* *
* \return ID of the new kernel object * \retval >0 kernel name of the new signal receiver
* \retval 0 failed
* *
* Restricted to core threads. Regaining of the supplied memory is not * Restricted to core threads.
* supported by now.
*/ */
inline unsigned new_signal_receiver(void * dst) { inline unsigned new_signal_receiver(addr_t const p)
return syscall(NEW_SIGNAL_RECEIVER, (Syscall_arg)dst); }
/**
* Create a kernel object that acts as a distinct signal type at a receiver
*
* \param dst physical base of an appropriate portion of memory
* that is thereupon allocated to the kernel
* \param receiver_id ID of the receiver kernel-object that shall
* provide the new signal context
* \param imprint Every signal, one receives at the new context,
* will hold this imprint. This enables the receiver
* to interrelate signals with the context.
*
* \return ID of the new kernel object
*
* Core-only syscall. Regaining of the supplied memory is not
* supported by now.
*/
inline unsigned new_signal_context(void * dst, unsigned receiver_id,
unsigned imprint)
{ {
return syscall(NEW_SIGNAL_CONTEXT, (Syscall_arg)dst, return syscall(NEW_SIGNAL_RECEIVER, p);
(Syscall_arg)receiver_id, (Syscall_arg)imprint);
} }
/** /**
* Wait for occurence of at least one signal at any context of a receiver * Create a kernel object that acts as a signal context at a receiver
* *
* \param receiver_id ID of the targeted receiver kernel-object * \param p appropriate memory donation for the kernel object
* \param receiver kernel name of targeted signal receiver
* \param imprint userland name of the new signal context
* *
* When this call returns, an instance of 'Signal::Data' is located at the * \retval >0 kernel name of the new signal context
* base of the callers UTCB. It's granted that every occurence of a signal * \retval 0 failed
* is provided through this function, exactly till it gets delivered through *
* this function. If multiple threads listen at the same receiver, and/or * Restricted to core threads.
* multiple contexts of the receiver trigger simultanously, there is no
* assertion about wich thread receives, and from wich context. But
* deliveries belonging to the same context are serialized through
* 'ack_signal', to enable synchronization in 'kill_signal'.
*/ */
inline void await_signal(unsigned receiver_id) { inline unsigned new_signal_context(addr_t const p,
syscall(AWAIT_SIGNAL, (Syscall_arg)receiver_id); } unsigned const receiver,
unsigned const imprint)
{
return syscall(NEW_SIGNAL_CONTEXT, p, receiver, imprint);
}
/** /**
* Get summarized state of all contexts of a signal receiver * Wait for the occurence of any context of a receiver
* *
* \param receiver_id ID of the targeted receiver kernel-object * \param receiver kernel name of the targeted signal receiver
*
* \retval 0 suceeded
* \retval -1 failed
*
* If this call returns 0, an instance of 'Signal::Data' is located at the
* base of the callers UTCB. Every occurence of a signal is provided
* through this function until it gets delivered through this function.
* If multiple threads listen at the same receiver, and/or
* multiple contexts of the receiver trigger simultanously, there is no
* assertion about wich thread receives, and from wich context. A context
* that delivered once doesn't deliver again unless its last delivery has
* been acknowledged via 'ack_signal'.
*/ */
inline bool signal_pending(unsigned receiver_id) { inline int await_signal(unsigned const receiver)
return syscall(SIGNAL_PENDING, (Syscall_arg)receiver_id); } {
return syscall(AWAIT_SIGNAL, receiver);
}
/**
* Return wether any context of a receiver is pending
*
* \param receiver kernel name of the targeted signal receiver
*
* \retval 0 none of the contexts is pending or the receiver doesn't exist
* \retval 1 a context of the signal receiver is pending
*/
inline bool signal_pending(unsigned const receiver)
{
return syscall(SIGNAL_PENDING, receiver);
}
/** /**
* Trigger a specific signal context * Trigger a specific signal context
* *
* \param context_id ID of the targeted context kernel-object * \param context kernel name of the targeted signal context
* \param num how often the context shall be triggered by this call * \param num how often the context shall be triggered by this call
*
* \retval 0 suceeded
* \retval -1 failed
*/ */
inline void submit_signal(unsigned context_id, int num) { inline int submit_signal(unsigned const context, unsigned const num)
syscall(SUBMIT_SIGNAL, (Syscall_arg)context_id, (Syscall_arg)num); } {
return syscall(SUBMIT_SIGNAL, context, num);
}
/** /**
* Acknowledge the processing of the last signal of a signal context * Acknowledge the processing of the last delivery of a signal context
* *
* \param context_id kernel name of the targeted signal context * \param context kernel name of the targeted signal context
*
* Should be called after all signal objects, that reference the targeted
* signal context in userland are destructed. The signal context wont
* deliver a new signal until the old signal is acknowledged.
*/ */
inline void ack_signal(unsigned context_id) { inline void ack_signal(unsigned const context)
syscall(ACK_SIGNAL, (Syscall_arg)context_id); } {
syscall(ACK_SIGNAL, context);
}
/** /**
* Destruct a signal context * Destruct a signal context
* *
* \param context_id kernel name of the targeted signal context * \param context kernel name of the targeted signal context
* *
* \return wether the context could be destructed * \retval 0 suceeded
* * \retval -1 failed
* 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. * Restricted to core threads.
*/ */
inline bool kill_signal_context(unsigned context_id) { inline int kill_signal_context(unsigned const context)
return syscall(KILL_SIGNAL_CONTEXT, (Syscall_arg)context_id); } {
return syscall(KILL_SIGNAL_CONTEXT, context);
}
/**
* Destruct a signal receiver
*
* \param receiver kernel name of the targeted signal receiver
*
* \retval 0 suceeded
* \retval -1 failed
*
* Restricted to core threads.
*/
inline int kill_signal_receiver(unsigned const receiver)
{
return syscall(KILL_SIGNAL_RECEIVER, receiver);
}
/** /**
* Create a new virtual-machine that is stopped initially * Create a new virtual-machine that is stopped initially

View File

@ -46,6 +46,9 @@ namespace Genode
unsigned const imprint) { unsigned const imprint) {
return call<Rpc_alloc_context>(r, imprint); } return call<Rpc_alloc_context>(r, imprint); }
void free_receiver(Signal_receiver_capability cap) {
call<Rpc_free_receiver>(cap); }
void free_context(Signal_context_capability cap) { void free_context(Signal_context_capability cap) {
call<Rpc_free_context>(cap); } call<Rpc_free_context>(cap); }
}; };

View File

@ -80,10 +80,19 @@ namespace Genode
alloc_context(Signal_receiver_capability r, alloc_context(Signal_receiver_capability r,
unsigned const imprint) = 0; unsigned const imprint) = 0;
/**
* Free a signal receiver
*
* \param cap capability of targeted signal receiver
*
* \throw Exception
*/
virtual void free_receiver(Signal_receiver_capability cap) = 0;
/** /**
* Free a signal context * Free a signal context
* *
* \param cap capability of signal-context to release * \param cap capability of targeted signal context
* *
* \throw Exception * \throw Exception
*/ */
@ -97,15 +106,21 @@ namespace Genode
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)); 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,
Exception), Signal_receiver_capability, unsigned); Exception), Signal_receiver_capability, unsigned);
GENODE_RPC_THROW(Rpc_free_receiver, void, free_receiver,
GENODE_TYPE_LIST(Exception),
Signal_receiver_capability);
GENODE_RPC_THROW(Rpc_free_context, void, free_context, GENODE_RPC_THROW(Rpc_free_context, void, free_context,
GENODE_TYPE_LIST(Exception), GENODE_TYPE_LIST(Exception),
Signal_context_capability); 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_receiver, Rpc_free_context);
}; };
} }

View File

@ -109,9 +109,16 @@ Signal_receiver::Signal_receiver()
} }
void Signal_receiver::_platform_destructor()
{
/* release server resources of receiver */
signal_connection()->free_receiver(_cap);
}
void Signal_receiver::_unsynchronized_dissolve(Signal_context * c) void Signal_receiver::_unsynchronized_dissolve(Signal_context * c)
{ {
/* release core resources */ /* release server resources of context */
signal_connection()->free_context(c->_cap); signal_connection()->free_context(c->_cap);
/* reset the context */ /* reset the context */
@ -128,7 +135,7 @@ Signal_context_capability Signal_receiver::manage(Signal_context * const c)
/* check if the context is already managed */ /* check if the context is already managed */
Lock::Guard contexts_guard(_contexts_lock); Lock::Guard contexts_guard(_contexts_lock);
Lock::Guard context_guard(c->_lock); Lock::Guard context_guard(c->_lock);
if (c->_receiver) throw Context_already_in_use(); if (c->_receiver) { throw Context_already_in_use(); }
/* create a kernel object that corresponds to the context */ /* create a kernel object that corresponds to the context */
bool session_upgraded = 0; bool session_upgraded = 0;
@ -154,13 +161,10 @@ Signal_context_capability Signal_receiver::manage(Signal_context * const c)
} }
void Signal_receiver::dissolve(Signal_context *context) void Signal_receiver::dissolve(Signal_context * const context)
{ {
if (context->_receiver != this) if (context->_receiver != this) { throw Context_not_associated(); }
throw Context_not_associated();
Lock::Guard list_lock_guard(_contexts_lock); Lock::Guard list_lock_guard(_contexts_lock);
_unsynchronized_dissolve(context); _unsynchronized_dissolve(context);
/* /*
@ -180,24 +184,17 @@ bool Signal_receiver::pending() { return Kernel::signal_pending(_cap.dst()); }
Signal Signal_receiver::wait_for_signal() Signal Signal_receiver::wait_for_signal()
{ {
/* await a signal */ /* await a signal */
Kernel::await_signal(_cap.dst()); if (Kernel::await_signal(_cap.dst())) {
Signal s(*(Signal::Data *)Thread_base::myself()->utcb()); PERR("failed to receive signal");
Signal_context * const c = s.context(); throw Exception();
/* check if the context of the signal is managed by us */
Lock::Guard context_guard(c->_lock);
if (c->_receiver != this) {
PERR("%s: Context not managed by this receiver", __PRETTY_FUNCTION__);
while (1) ;
} }
/* check attributes of the signal and return it */ /* get signal data */
if (s.num() == 0) PWRN("Returning signal with num == 0"); Signal s(*(Signal::Data *)Thread_base::myself()->utcb());
return s; return s;
} }
void Signal_receiver::local_submit(Signal::Data signal) { void Signal_receiver::local_submit(Signal::Data signal)
PDBG("Not implemented"); }; {
PDBG("Not implemented");
}
void Signal_receiver::_platform_destructor() { }

View File

@ -37,15 +37,22 @@ namespace Genode
private: private:
/**
* Maps a signal-receiver name to related core and kernel resources
*/
class Receiver;
/** /**
* Maps a signal-context name to related core and kernel resources * Maps a signal-context name to related core and kernel resources
*/ */
class Context; class Context;
typedef Object_pool<Context> Context_pool; typedef Object_pool<Receiver> Receiver_pool;
typedef Object_pool<Context> Context_pool;
Allocator_guard _md_alloc; Allocator_guard _md_alloc;
Slab _receivers_slab; Slab _receivers_slab;
Receiver_pool _receivers;
Slab _contexts_slab; Slab _contexts_slab;
Context_pool _contexts; Context_pool _contexts;
char _initial_receivers_sb [RECEIVERS_SB_SIZE]; char _initial_receivers_sb [RECEIVERS_SB_SIZE];
@ -81,10 +88,43 @@ namespace Genode
Signal_context_capability Signal_context_capability
alloc_context(Signal_receiver_capability, unsigned const); alloc_context(Signal_receiver_capability, unsigned const);
void free_receiver(Signal_receiver_capability);
void free_context(Signal_context_capability); void free_context(Signal_context_capability);
}; };
} }
class Genode::Signal_session_component::Receiver : public Receiver_pool::Entry
{
public:
/**
* Constructor
*/
Receiver(Untyped_capability cap) : Entry(cap) { }
/**
* Name of signal receiver
*/
unsigned id() const { return Receiver_pool::Entry::cap().dst(); }
/**
* Size of SLAB block occupied by resources and this resource info
*/
static size_t slab_size()
{
return sizeof(Receiver) + Kernel::signal_receiver_size();
}
/**
* Base of region donated to the kernel
*/
static addr_t kernel_donation(void * const slab_addr)
{
return ((addr_t)slab_addr + sizeof(Receiver));
}
};
class Genode::Signal_session_component::Context : public Context_pool::Entry class Genode::Signal_session_component::Context : public Context_pool::Entry
{ {
public: public:
@ -110,9 +150,9 @@ class Genode::Signal_session_component::Context : public Context_pool::Entry
/** /**
* Base of region donated to the kernel * Base of region donated to the kernel
*/ */
static void * kernel_donation(void * const slab_addr) static addr_t kernel_donation(void * const slab_addr)
{ {
return (void *)((addr_t)slab_addr + sizeof(Context)); return ((addr_t)slab_addr + sizeof(Context));
} }
}; };

View File

@ -91,13 +91,6 @@ namespace Kernel
namespace Kernel namespace Kernel
{ {
void deliver_signal(Signal_handler * const dst,
void * const base,
size_t const size)
{
((Thread *)dst->id())->receive_signal(base, size);
}
class Vm : public Object<Vm, MAX_VMS>, class Vm : public Object<Vm, MAX_VMS>,
public Execution_context public Execution_context
{ {
@ -601,15 +594,16 @@ namespace Kernel
*/ */
void do_new_signal_receiver(Thread * const user) void do_new_signal_receiver(Thread * const user)
{ {
/* check permissions */ /* check permissions */
assert(user->pd_id() == core_id()); if (user->pd_id() != core_id()) {
PERR("permission to create signal receiver denied");
/* create receiver */ user->user_arg_0(0);
void * dst = (void *)user->user_arg_1(); return;
Signal_receiver * const r = new (dst) Signal_receiver(); }
/* create receiver */
/* return success */ void * p = (void *)user->user_arg_1();
user->user_arg_0(r->id()); Signal_receiver * const r = new (p) Signal_receiver();
user->user_arg_0(r->id());
} }
@ -619,19 +613,29 @@ namespace Kernel
void do_new_signal_context(Thread * const user) void do_new_signal_context(Thread * const user)
{ {
/* check permissions */ /* check permissions */
assert(user->pd_id() == core_id()); if (user->pd_id() != core_id()) {
PERR("not entitled to create signal context");
user->user_arg_0(0);
return;
}
/* lookup receiver */ /* lookup receiver */
unsigned rid = user->user_arg_2(); unsigned id = user->user_arg_2();
Signal_receiver * const r = Signal_receiver::pool()->object(rid); Signal_receiver * const r = Signal_receiver::pool()->object(id);
assert(r); if (!r) {
PERR("invalid signal receiver");
/* create context */ user->user_arg_0(0);
void * dst = (void *)user->user_arg_1(); return;
}
/* create and assign context*/
void * p = (void *)user->user_arg_1();
unsigned imprint = user->user_arg_3(); unsigned imprint = user->user_arg_3();
Signal_context * const c = new (dst) Signal_context(r, imprint); if (r->new_context(p, imprint)) {
PERR("failed to create signal context");
/* return success */ user->user_arg_0(0);
return;
}
/* return context name */
Signal_context * const c = (Signal_context *)p;
user->user_arg_0(c->id()); user->user_arg_0(c->id());
} }
@ -642,13 +646,21 @@ namespace Kernel
void do_await_signal(Thread * const user) void do_await_signal(Thread * const user)
{ {
/* lookup receiver */ /* lookup receiver */
unsigned rid = user->user_arg_2(); unsigned id = user->user_arg_1();
Signal_receiver * const r = Signal_receiver::pool()->object(rid); Signal_receiver * const r = Signal_receiver::pool()->object(id);
assert(r); if (!r) {
PERR("invalid signal receiver");
/* let user listen to receiver */ user->user_arg_0(-1);
return;
}
/* register handler at the receiver */
user->await_signal(r); user->await_signal(r);
r->add_handler(user->signal_handler()); if (r->add_handler(user)) {
PERR("failed to register handler at signal receiver");
user->user_arg_0(-1);
return;
}
user->user_arg_0(0);
} }
@ -657,12 +669,15 @@ namespace Kernel
*/ */
void do_signal_pending(Thread * const user) void do_signal_pending(Thread * const user)
{ {
/* lookup receiver */ /* lookup signal receiver */
unsigned rid = user->user_arg_2(); unsigned id = user->user_arg_1();
Signal_receiver * const r = Signal_receiver::pool()->object(rid); Signal_receiver * const r = Signal_receiver::pool()->object(id);
assert(r); if (!r) {
PERR("invalid signal receiver");
/* set return value */ user->user_arg_0(0);
return;
}
/* get pending state */
user->user_arg_0(r->deliverable()); user->user_arg_0(r->deliverable());
} }
@ -672,15 +687,20 @@ namespace Kernel
*/ */
void do_submit_signal(Thread * const user) void do_submit_signal(Thread * const user)
{ {
/* lookup context */ /* lookup signal context */
Signal_context * const c = unsigned const id = user->user_arg_1();
Signal_context::pool()->object(user->user_arg_1()); Signal_context * const c = Signal_context::pool()->object(id);
if(!c) { if(!c) {
PDBG("invalid signal-context capability"); PERR("invalid signal context");
user->user_arg_0(-1);
return; return;
} }
/* trigger signal at context */ /* trigger signal context */
c->submit(user->user_arg_2()); if (c->submit(user->user_arg_2())) {
user->user_arg_0(-1);
return;
}
user->user_arg_0(0);
} }
@ -689,11 +709,15 @@ namespace Kernel
*/ */
void do_ack_signal(Thread * const user) void do_ack_signal(Thread * const user)
{ {
/* lookup signal context */
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) {
Thread * const t = (Thread *)c->ack(); PWRN("invalid signal context");
if (t) { t->kill_signal_context_done(); } return;
}
/* acknowledge */
c->ack();
} }
@ -703,15 +727,55 @@ namespace Kernel
void do_kill_signal_context(Thread * const user) void do_kill_signal_context(Thread * const user)
{ {
/* check permissions */ /* check permissions */
assert(user->pd_id() == core_id()); if (user->pd_id() != core_id()) {
PERR("not entitled to kill signal context");
user->user_arg_0(-1);
return;
}
/* lookup signal context */
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) {
if (c->kill((unsigned)user)) { return; } user->user_arg_0(0);
user->kill_signal_context_blocks(); return;
}
/* kill signal context */
if (c->kill(user)) {
user->user_arg_0(-1);
return;
}
user->user_arg_0(0);
} }
/**
* Do specific syscall for 'user', for details see 'syscall.h'
*/
void do_kill_signal_receiver(Thread * const user)
{
/* check permissions */
if (user->pd_id() != core_id()) {
PERR("not entitled to kill signal receiver");
user->user_arg_0(-1);
return;
}
/* lookup signal receiver */
user->user_arg_0(1);
unsigned id = user->user_arg_1();
Signal_receiver * const r = Signal_receiver::pool()->object(id);
if (!r) {
user->user_arg_0(0);
return;
}
/* kill signal receiver */
if (r->kill(user)) {
user->user_arg_0(-1);
return;
}
user->user_arg_0(0);
}
/** /**
* Do specific syscall for 'user', for details see 'syscall.h' * Do specific syscall for 'user', for details see 'syscall.h'
*/ */
@ -779,38 +843,39 @@ namespace Kernel
{ {
switch (user->user_arg_0()) switch (user->user_arg_0())
{ {
case NEW_THREAD: do_new_thread(user); return; case NEW_THREAD: do_new_thread(user); return;
case DELETE_THREAD: do_delete_thread(user); return; case DELETE_THREAD: do_delete_thread(user); return;
case START_THREAD: do_start_thread(user); return; case START_THREAD: do_start_thread(user); return;
case PAUSE_THREAD: do_pause_thread(user); return; case PAUSE_THREAD: do_pause_thread(user); return;
case RESUME_THREAD: do_resume_thread(user); return; case RESUME_THREAD: do_resume_thread(user); return;
case RESUME_FAULTER: do_resume_faulter(user); return; case RESUME_FAULTER: do_resume_faulter(user); return;
case GET_THREAD: do_get_thread(user); return; case GET_THREAD: do_get_thread(user); return;
case CURRENT_THREAD_ID: do_current_thread_id(user); return; case CURRENT_THREAD_ID: do_current_thread_id(user); return;
case YIELD_THREAD: do_yield_thread(user); return; case YIELD_THREAD: do_yield_thread(user); return;
case READ_THREAD_STATE: do_read_thread_state(user); return; case READ_THREAD_STATE: do_read_thread_state(user); return;
case WRITE_THREAD_STATE: do_write_thread_state(user); return; case WRITE_THREAD_STATE: do_write_thread_state(user); return;
case REQUEST_AND_WAIT: do_request_and_wait(user); return; case REQUEST_AND_WAIT: do_request_and_wait(user); return;
case REPLY: do_reply(user); return; case REPLY: do_reply(user); return;
case WAIT_FOR_REQUEST: do_wait_for_request(user); return; case WAIT_FOR_REQUEST: do_wait_for_request(user); return;
case SET_PAGER: do_set_pager(user); return; case SET_PAGER: do_set_pager(user); return;
case UPDATE_PD: do_update_pd(user); return; case UPDATE_PD: do_update_pd(user); return;
case UPDATE_REGION: do_update_region(user); return; case UPDATE_REGION: do_update_region(user); return;
case NEW_PD: do_new_pd(user); return; case NEW_PD: do_new_pd(user); return;
case ALLOCATE_IRQ: do_allocate_irq(user); return; case ALLOCATE_IRQ: do_allocate_irq(user); return;
case AWAIT_IRQ: do_await_irq(user); return; case AWAIT_IRQ: do_await_irq(user); return;
case FREE_IRQ: do_free_irq(user); return; case FREE_IRQ: do_free_irq(user); return;
case PRINT_CHAR: do_print_char(user); return; case PRINT_CHAR: do_print_char(user); return;
case NEW_SIGNAL_RECEIVER: do_new_signal_receiver(user); return; case NEW_SIGNAL_RECEIVER: do_new_signal_receiver(user); return;
case NEW_SIGNAL_CONTEXT: do_new_signal_context(user); return; case NEW_SIGNAL_CONTEXT: do_new_signal_context(user); return;
case KILL_SIGNAL_CONTEXT: do_kill_signal_context(user); return; case KILL_SIGNAL_CONTEXT: do_kill_signal_context(user); return;
case AWAIT_SIGNAL: do_await_signal(user); return; case KILL_SIGNAL_RECEIVER: do_kill_signal_receiver(user); return;
case SUBMIT_SIGNAL: do_submit_signal(user); return; case AWAIT_SIGNAL: do_await_signal(user); return;
case SIGNAL_PENDING: do_signal_pending(user); return; case SUBMIT_SIGNAL: do_submit_signal(user); return;
case ACK_SIGNAL: do_ack_signal(user); return; case SIGNAL_PENDING: do_signal_pending(user); return;
case NEW_VM: do_new_vm(user); return; case ACK_SIGNAL: do_ack_signal(user); return;
case RUN_VM: do_run_vm(user); return; case NEW_VM: do_new_vm(user); return;
case PAUSE_VM: do_pause_vm(user); return; case RUN_VM: do_run_vm(user); return;
case PAUSE_VM: do_pause_vm(user); return;
default: default:
PERR("invalid syscall"); PERR("invalid syscall");
user->crash(); user->crash();

View File

@ -0,0 +1,25 @@
/*
* \brief Kernel backend for asynchronous inter-process communication
* \author Martin Stein
* \date 2012-11-30
*/
/*
* Copyright (C) 2012-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* core includes */
#include <kernel/signal_receiver.h>
void Kernel::Signal_context::_deliverable()
{
if (!_submits) return;
_receiver->_add_deliverable(this);
}
Kernel::Signal_context::~Signal_context() { _receiver->_context_killed(this); }

View File

@ -25,10 +25,20 @@
namespace Kernel namespace Kernel
{ {
/** /**
* Enables external components to act as a signal handler * Ability to receive from signal receivers
*/ */
class Signal_handler; class Signal_handler;
/**
* Ability to destruct signal contexts
*/
class Signal_context_killer;
/**
* Ability to destruct signal receivers
*/
class Signal_receiver_killer;
/** /**
* Signal types that are assigned to a signal receiver each * Signal types that are assigned to a signal receiver each
*/ */
@ -38,17 +48,6 @@ namespace Kernel
* Combines signal contexts to an entity that handlers can listen to * Combines signal contexts to an entity that handlers can listen to
*/ */
class Signal_receiver; class Signal_receiver;
/**
* 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 class Kernel::Signal_handler
@ -59,22 +58,56 @@ class Kernel::Signal_handler
typedef Genode::Fifo_element<Signal_handler> Fifo_element; typedef Genode::Fifo_element<Signal_handler> Fifo_element;
Fifo_element _fe; Fifo_element _handlers_fe;
unsigned const _id;
/**
* Signal delivery backend
*
* \param base signal-data base
* \param size signal-data size
*/
virtual void _signal_handler(void * const base, size_t const size) = 0;
public: public:
/** /**
* Constructor * Constructor
*/ */
Signal_handler(unsigned id) : _fe(this), _id(id) { } Signal_handler() : _handlers_fe(this) { }
};
class Kernel::Signal_context_killer
{
friend class Signal_context;
/*************** private:
** Accessors **
***************/
unsigned id() { return _id; } /**
* Notice that the destruction is pending
*/
virtual void _signal_context_kill_pending() = 0;
/**
* Notice that pending destruction is done
*/
virtual void _signal_context_kill_done() = 0;
};
class Kernel::Signal_receiver_killer
{
friend class Signal_receiver;
private:
/**
* Notice that the destruction is pending
*/
virtual void _signal_receiver_kill_pending() = 0;
/**
* Notice that pending destruction is done
*/
virtual void _signal_receiver_kill_done() = 0;
}; };
class Kernel::Signal_context class Kernel::Signal_context
@ -87,17 +120,18 @@ class Kernel::Signal_context
typedef Genode::Fifo_element<Signal_context> Fifo_element; typedef Genode::Fifo_element<Signal_context> Fifo_element;
Fifo_element _fe; Fifo_element _deliver_fe;
Fifo_element _contexts_fe;
Signal_receiver * const _receiver; Signal_receiver * const _receiver;
unsigned const _imprint; unsigned const _imprint;
unsigned _submits; unsigned _submits;
bool _ack; bool _ack;
unsigned _killer; Signal_context_killer * _killer;
/** /**
* Tell receiver about the submits of the context if any * Tell receiver about the submits of the context if any
*/ */
inline void _deliverable(); void _deliverable();
/** /**
* Called by receiver when all submits have been delivered * Called by receiver when all submits have been delivered
@ -108,85 +142,87 @@ class Kernel::Signal_context
_ack = 0; _ack = 0;
} }
public: /**
* Destructor
*/
~Signal_context();
/** /**
* Constructor * Constructor
*
* \param r receiver that the context is assigned to
* \param imprint userland identification of the context
*/ */
Signal_context(Signal_receiver * const r, unsigned const imprint) Signal_context(Signal_receiver * const r, unsigned const imprint)
: :
_fe(this), _receiver(r), _imprint(imprint), _submits(0), _ack(1), _deliver_fe(this), _contexts_fe(this), _receiver(r),
_killer(0) _imprint(imprint), _submits(0), _ack(1), _killer(0)
{ } { }
public:
/** /**
* Submit the signal * Submit the signal
* *
* \param n number of submits * \param n number of submits
*
* \retval 0 succeeded
* \retval -1 failed
*/ */
void submit(unsigned const n) int submit(unsigned const n)
{ {
if (_submits >= (unsigned)~0 - n) { if (_killer || _submits >= (unsigned)~0 - n) { return -1; }
PERR("overflow at signal-submit count");
return;
}
if (_killer) {
PERR("signal context already in destruction");
return;
}
_submits += n; _submits += n;
if (!_ack) { return; } if (_ack) { _deliverable(); }
_deliverable(); return 0;
} }
/** /**
* Acknowledge delivery of signal * Acknowledge delivery of signal
*
* \retval 0 no kill request finished
* \retval > 0 name of finished kill request
*/ */
unsigned ack() void ack()
{ {
if (_ack) { if (_ack) { return; }
PERR("unexpected signal acknowledgment");
return 0;
}
if (!_killer) { if (!_killer) {
_ack = 1; _ack = 1;
_deliverable(); _deliverable();
return 0; return;
} }
this->~Signal_context(); this->~Signal_context();
return _killer; _killer->_signal_context_kill_done();
} }
/** /**
* Destruct context or prepare to do it as soon as delivery is done * Destruct context or prepare to do it as soon as delivery is done
* *
* \param killer name of the kill request * \param killer object that shall receive progress reports
* *
* \retval 1 destruction is done * \retval 0 succeeded
* \retval 0 destruction is initiated, will be done with the next ack * \retval -1 failed
*/ */
bool kill(unsigned const killer) int kill(Signal_context_killer * const k)
{ {
/* FIXME: aggregate or avoid multiple kill requests */ if (_killer) { return -1; }
if (_killer) {
PERR("multiple kill requests"); /* destruct directly if there is no unacknowledged delivery */
while (1) { } if (_ack) {
this->~Signal_context();
return 0;
} }
_killer = killer; /* wait for delivery acknowledgement */
if (!_ack) { return 0; } _killer = k;
this->~Signal_context(); _killer->_signal_context_kill_pending();
return 1; return 0;
} }
}; };
class Kernel::Signal_receiver class Kernel::Signal_receiver
: :
public Object<Signal_receiver, MAX_SIGNAL_RECEIVERS> public Object<Signal_receiver, MAX_SIGNAL_RECEIVERS>,
public Signal_context_killer
{ {
friend class Signal_context; friend class Signal_context;
friend class Context_killer;
private: private:
@ -195,14 +231,19 @@ class Kernel::Signal_receiver
template <typename T> class Fifo : public Genode::Fifo<T> { }; template <typename T> class Fifo : public Genode::Fifo<T> { };
Fifo<Signal_handler::Fifo_element> _handlers; Fifo<Signal_handler::Fifo_element> _handlers;
Fifo<Signal_context::Fifo_element> _deliverable; Fifo<Signal_context::Fifo_element> _deliver;
Fifo<Signal_context::Fifo_element> _contexts;
unsigned _context_kills;
Signal_receiver_killer * _killer;
/** /**
* Recognize that context 'c' has submits to deliver * Recognize that context 'c' has submits to deliver
*/ */
void _add_deliverable(Signal_context * const c) void _add_deliverable(Signal_context * const c)
{ {
if (!c->_fe.is_enqueued()) _deliverable.enqueue(&c->_fe); if (!c->_deliver_fe.is_enqueued()) {
_deliver.enqueue(&c->_deliver_fe);
}
_listen(); _listen();
} }
@ -214,53 +255,128 @@ class Kernel::Signal_receiver
while (1) while (1)
{ {
/* check if there are deliverable signal */ /* check if there are deliverable signal */
if (_deliverable.empty()) return; if (_deliver.empty()) return;
Signal_context * const c = _deliverable.dequeue()->object(); Signal_context * const c = _deliver.dequeue()->object();
/* if there is no handler re-enqueue context and exit */ /* if there is no handler re-enqueue context and exit */
if (_handlers.empty()) { if (_handlers.empty()) {
_deliverable.enqueue(&c->_fe); _deliver.enqueue(&c->_deliver_fe);
return; return;
} }
/* delivery from context to handler */ /* delivery from context to handler */
Signal_handler * const h = _handlers.dequeue()->object(); Signal_handler * const h = _handlers.dequeue()->object();
Signal::Data data((Genode::Signal_context *)c->_imprint, Signal::Data data((Genode::Signal_context *)c->_imprint,
c->_submits); c->_submits);
deliver_signal(h, &data, sizeof(data)); h->_signal_handler(&data, sizeof(data));
c->_delivered(); c->_delivered();
} }
} }
/**
* Notice that a context of the receiver has been killed
*
* \param c killed context
*/
void _context_killed(Signal_context * const c)
{
if (c->_deliver_fe.is_enqueued()) {
_deliver.remove(&c->_deliver_fe);
}
_contexts.remove(&c->_contexts_fe);
}
/***************************
** Signal_context_killer **
***************************/
void _signal_context_kill_pending() { _context_kills++; }
void _signal_context_kill_done()
{
_context_kills--;
if (!_context_kills && _killer) {
this->~Signal_receiver();
_killer->_signal_receiver_kill_done();
}
}
public: public:
/** /**
* Let a handler wait for signals of the receiver * Constructor
*/ */
void add_handler(Signal_handler * const h)
/**
* Let a handler 'h' wait for signals of the receiver
*
* \retval 0 succeeded
* \retval -1 failed
*/
int add_handler(Signal_handler * const h)
{ {
_handlers.enqueue(&h->_fe); if (_killer) { return -1; }
_handlers.enqueue(&h->_handlers_fe);
_listen(); _listen();
return 0;
} }
/** /**
* Stop a handler from waiting for signals of the receiver * Stop a handler 'h' from waiting for signals of the receiver
*/ */
void remove_handler(Signal_handler * const h) void remove_handler(Signal_handler * const h)
{ {
_handlers.remove(&h->_fe); _handlers.remove(&h->_handlers_fe);
}
/**
* Create a context that is assigned to the receiver
*
* \retval 0 succeeded
* \retval -1 failed
*/
int new_context(void * p, unsigned imprint)
{
if (_killer) { return -1; }
new (p) Signal_context(this, imprint);
Signal_context * const c = (Signal_context *)p;
_contexts.enqueue(&c->_contexts_fe);
return 0;
} }
/** /**
* Return wether any of the contexts of this receiver is deliverable * Return wether any of the contexts of this receiver is deliverable
*/ */
bool deliverable() { return !_deliverable.empty(); } bool deliverable() { return !_deliver.empty(); }
/**
* Destruct receiver or prepare to do it as soon as delivery is done
*
* \param killer object that shall receive progress reports
*
* \retval 0 succeeded
* \retval -1 failed
*/
int kill(Signal_receiver_killer * const k)
{
if (_killer) { return -1; }
/* start killing at all contexts of the receiver */
Signal_context * c = _contexts.dequeue()->object();
while (c) {
c->kill(this);
c = _contexts.dequeue()->object();
}
/* destruct directly if no context kill is pending */
if (!_context_kills) {
this->~Signal_receiver();
return 0;
}
/* wait for pending context kills */
_killer = k;
_killer->_signal_receiver_kill_pending();
return 0;
}
}; };
void Kernel::Signal_context::_deliverable()
{
if (!_submits) return;
_receiver->_add_deliverable(this);
}
#endif /* _KERNEL__SIGNAL_RECEIVER_ */ #endif /* _KERNEL__SIGNAL_RECEIVER_ */

View File

@ -81,7 +81,10 @@ class Kernel::Thread
public Object<Thread, MAX_THREADS>, public Object<Thread, MAX_THREADS>,
public Execution_context, public Execution_context,
public Ipc_node, public Ipc_node,
public Irq_receiver public Irq_receiver,
public Signal_context_killer,
public Signal_receiver_killer,
public Signal_handler
{ {
private: private:
@ -93,7 +96,7 @@ class Kernel::Thread
AWAIT_RESUMPTION, AWAIT_RESUMPTION,
AWAIT_IRQ, AWAIT_IRQ,
AWAIT_SIGNAL, AWAIT_SIGNAL,
AWAIT_SIGNAL_CONTEXT_DESTRUCT, AWAIT_SIGNAL_CONTEXT_KILL,
CRASHED, CRASHED,
}; };
@ -105,7 +108,6 @@ class Kernel::Thread
Native_utcb * _phys_utcb; Native_utcb * _phys_utcb;
Native_utcb * _virt_utcb; Native_utcb * _virt_utcb;
Signal_receiver * _signal_receiver; Signal_receiver * _signal_receiver;
Signal_handler _signal_handler;
/** /**
* Resume execution * Resume execution
@ -116,6 +118,47 @@ class Kernel::Thread
_state = SCHEDULED; _state = SCHEDULED;
} }
/***************************
** Signal_context_killer **
***************************/
void _signal_context_kill_pending()
{
cpu_scheduler()->remove(this);
_state = AWAIT_SIGNAL_CONTEXT_KILL;
}
void _signal_context_kill_done()
{
if (_state != AWAIT_SIGNAL_CONTEXT_KILL) {
PDBG("ignore unexpected signal-context destruction");
return;
}
user_arg_0(0);
_schedule();
}
/********************
** Signal_handler **
********************/
void _signal_handler(void * const base, size_t const size)
{
assert(_state == AWAIT_SIGNAL && size <= phys_utcb()->size());
Genode::memcpy(phys_utcb()->base(), base, size);
_schedule();
}
/****************************
** Signal_receiver_killer **
****************************/
void _signal_receiver_kill_pending() { PERR("not implemented"); }
void _signal_receiver_kill_done() { PERR("not implemented"); }
/************** /**************
** Ipc_node ** ** Ipc_node **
@ -161,7 +204,7 @@ class Kernel::Thread
: :
_platform_thread(platform_thread), _state(AWAIT_START), _platform_thread(platform_thread), _state(AWAIT_START),
_pager(0), _pd_id(0), _phys_utcb(0), _virt_utcb(0), _pager(0), _pd_id(0), _phys_utcb(0), _virt_utcb(0),
_signal_receiver(0), _signal_handler((unsigned)this) _signal_receiver(0)
{ } { }
/** /**
@ -280,10 +323,10 @@ class Kernel::Thread
return 0; return 0;
case AWAIT_SIGNAL: case AWAIT_SIGNAL:
PDBG("cancel signal receipt"); PDBG("cancel signal receipt");
_signal_receiver->remove_handler(signal_handler()); _signal_receiver->remove_handler(this);
_schedule(); _schedule();
return 0; return 0;
case AWAIT_SIGNAL_CONTEXT_DESTRUCT: case AWAIT_SIGNAL_CONTEXT_KILL:
PDBG("cancel signal context destruction"); PDBG("cancel signal context destruction");
_schedule(); _schedule();
return 0; return 0;
@ -361,41 +404,6 @@ class Kernel::Thread
_signal_receiver = receiver; _signal_receiver = receiver;
} }
/**
* Let the thread receive signal data
*
* \param base signal-data base
* \param size signal-data size
*/
void receive_signal(void * const base, size_t const size)
{
assert(_state == AWAIT_SIGNAL && size <= phys_utcb()->size());
Genode::memcpy(phys_utcb()->base(), base, size);
_schedule();
}
/**
* Destructing a signal context blocks the thread for now
*/
void kill_signal_context_blocks()
{
cpu_scheduler()->remove(this);
_state = AWAIT_SIGNAL_CONTEXT_DESTRUCT;
}
/**
* A signal-context destruction that blocked the thread is done
*/
void kill_signal_context_done()
{
if (_state != AWAIT_SIGNAL_CONTEXT_DESTRUCT) {
PDBG("ignore unexpected signal-context destruction");
return;
}
user_arg_0(1);
_schedule();
}
/*********************** /***********************
** Execution_context ** ** Execution_context **
@ -441,8 +449,6 @@ class Kernel::Thread
unsigned pd_id() const { return _pd_id; } unsigned pd_id() const { return _pd_id; }
Native_utcb * phys_utcb() const { return _phys_utcb; } Native_utcb * phys_utcb() const { return _phys_utcb; }
Signal_handler * signal_handler() { return &_signal_handler; }
}; };
#endif /* _CORE__KERNEL__THREAD_H_ */ #endif /* _CORE__KERNEL__THREAD_H_ */

View File

@ -13,7 +13,6 @@
/* 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 */
@ -31,7 +30,7 @@ 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(Receiver::slab_size(), RECEIVERS_SB_SIZE,
(Slab_block *)&_initial_receivers_sb, &_md_alloc), (Slab_block *)&_initial_receivers_sb, &_md_alloc),
_contexts_slab(Context::slab_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)
@ -48,21 +47,51 @@ Signal_session_component::~Signal_session_component()
Signal_receiver_capability Signal_session_component::alloc_receiver() Signal_receiver_capability Signal_session_component::alloc_receiver()
{ {
/* allocate resources for receiver */ /* allocate resources for receiver */
size_t const s = Kernel::signal_receiver_size();
void * p; void * p;
if (!_receivers_slab.alloc(s, &p)) { if (!_receivers_slab.alloc(Receiver::slab_size(), &p)) {
PERR("failed to allocate signal receiver"); PERR("failed to allocate signal-receiver resources");
throw Out_of_metadata(); throw Out_of_metadata();
} }
/* create kernel object for receiver */ /* create kernel object for receiver */
unsigned const id = Kernel::new_signal_receiver(p); addr_t donation = Receiver::kernel_donation(p);
if (!id) { unsigned const id = Kernel::new_signal_receiver(donation);
if (!id)
{
/* clean up */
_receivers_slab.free(p, Receiver::slab_size());
PERR("failed to create signal receiver"); PERR("failed to create signal receiver");
throw Exception(); throw Exception();
} }
/* remember receiver ressources */
Native_capability cap(id, id);
Receiver * const r = new (p) Receiver(cap);
_receivers.insert(r);
/* return receiver capability */ /* return receiver capability */
Native_capability c(id, id); return reinterpret_cap_cast<Signal_receiver>(cap);
return reinterpret_cap_cast<Signal_receiver>(c); }
void Signal_session_component::free_receiver(Signal_receiver_capability cap)
{
/* lookup ressource info */
Receiver * const r = _receivers.lookup_and_lock(cap);
if (!r) {
PERR("unknown signal receiver");
throw Exception();
}
/* release kernel resources */
if (Kernel::kill_signal_receiver(r->id()))
{
/* clean-up */
r->release();
PERR("failed to kill signal receiver");
throw Exception();
}
/* release core resources */
_receivers.remove_locked(r);
r->~Receiver();
_receivers_slab.free(r, Receiver::slab_size());
} }
@ -77,7 +106,7 @@ Signal_session_component::alloc_context(Signal_receiver_capability r,
throw Out_of_metadata(); throw Out_of_metadata();
} }
/* create kernel object for context */ /* create kernel object for context */
void * donation = Context::kernel_donation(p); addr_t donation = Context::kernel_donation(p);
unsigned const id = Kernel::new_signal_context(donation, r.dst(), imprint); unsigned const id = Kernel::new_signal_context(donation, r.dst(), imprint);
if (!id) if (!id)
{ {
@ -104,7 +133,7 @@ void Signal_session_component::free_context(Signal_context_capability cap)
throw Exception(); throw Exception();
} }
/* release kernel resources */ /* release kernel resources */
if (!Kernel::kill_signal_context(c->id())) if (Kernel::kill_signal_context(c->id()))
{ {
/* clean-up */ /* clean-up */
c->release(); c->release();

View File

@ -47,6 +47,7 @@ SRC_CC += console.cc \
trace_session_component.cc \ trace_session_component.cc \
thread.cc \ thread.cc \
kernel.cc \ kernel.cc \
kernel/signal_receiver.cc \
rm_session_support.cc \ rm_session_support.cc \
kernel_support.cc \ kernel_support.cc \
trustzone.cc \ trustzone.cc \