mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-20 06:07:59 +00:00
parent
e07781dc1c
commit
84c31a7ea1
@ -73,6 +73,7 @@ namespace Kernel
|
||||
|
||||
/* asynchronous signalling */
|
||||
NEW_SIGNAL_RECEIVER = 20,
|
||||
KILL_SIGNAL_RECEIVER = 33,
|
||||
NEW_SIGNAL_CONTEXT = 21,
|
||||
KILL_SIGNAL_CONTEXT = 30,
|
||||
AWAIT_SIGNAL = 22,
|
||||
@ -438,105 +439,129 @@ namespace Kernel
|
||||
/**
|
||||
* Create a kernel object that acts as receiver for asynchronous signals
|
||||
*
|
||||
* \param dst physical base of an appropriate portion of memory
|
||||
* that is thereupon allocated to the kernel
|
||||
* \param p appropriate memory donation for the kernel object
|
||||
*
|
||||
* \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
|
||||
* supported by now.
|
||||
* Restricted to core threads.
|
||||
*/
|
||||
inline unsigned new_signal_receiver(void * dst) {
|
||||
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)
|
||||
inline unsigned new_signal_receiver(addr_t const p)
|
||||
{
|
||||
return syscall(NEW_SIGNAL_CONTEXT, (Syscall_arg)dst,
|
||||
(Syscall_arg)receiver_id, (Syscall_arg)imprint);
|
||||
return syscall(NEW_SIGNAL_RECEIVER, p);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
* base of the callers UTCB. It's granted that every occurence of a signal
|
||||
* is provided through this function, exactly till 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. But
|
||||
* deliveries belonging to the same context are serialized through
|
||||
* 'ack_signal', to enable synchronization in 'kill_signal'.
|
||||
* \retval >0 kernel name of the new signal context
|
||||
* \retval 0 failed
|
||||
*
|
||||
* Restricted to core threads.
|
||||
*/
|
||||
inline void await_signal(unsigned receiver_id) {
|
||||
syscall(AWAIT_SIGNAL, (Syscall_arg)receiver_id); }
|
||||
inline unsigned new_signal_context(addr_t const p,
|
||||
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) {
|
||||
return syscall(SIGNAL_PENDING, (Syscall_arg)receiver_id); }
|
||||
inline int await_signal(unsigned const receiver)
|
||||
{
|
||||
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
|
||||
*
|
||||
* \param context_id ID of the targeted context kernel-object
|
||||
* \param num how often the context shall be triggered by this call
|
||||
* \param context kernel name of the targeted signal context
|
||||
* \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) {
|
||||
syscall(SUBMIT_SIGNAL, (Syscall_arg)context_id, (Syscall_arg)num); }
|
||||
inline int submit_signal(unsigned const context, unsigned const 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
|
||||
*
|
||||
* 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.
|
||||
* \param context kernel name of the targeted signal context
|
||||
*/
|
||||
inline void ack_signal(unsigned context_id) {
|
||||
syscall(ACK_SIGNAL, (Syscall_arg)context_id); }
|
||||
inline void ack_signal(unsigned const context)
|
||||
{
|
||||
syscall(ACK_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
|
||||
*
|
||||
* 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.
|
||||
* \retval 0 suceeded
|
||||
* \retval -1 failed
|
||||
*
|
||||
* Restricted to core threads.
|
||||
*/
|
||||
inline bool kill_signal_context(unsigned context_id) {
|
||||
return syscall(KILL_SIGNAL_CONTEXT, (Syscall_arg)context_id); }
|
||||
inline int kill_signal_context(unsigned const context)
|
||||
{
|
||||
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
|
||||
|
@ -46,6 +46,9 @@ namespace Genode
|
||||
unsigned const 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) {
|
||||
call<Rpc_free_context>(cap); }
|
||||
};
|
||||
|
@ -80,10 +80,19 @@ namespace Genode
|
||||
alloc_context(Signal_receiver_capability r,
|
||||
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
|
||||
*
|
||||
* \param cap capability of signal-context to release
|
||||
* \param cap capability of targeted signal context
|
||||
*
|
||||
* \throw Exception
|
||||
*/
|
||||
@ -97,15 +106,21 @@ namespace Genode
|
||||
GENODE_RPC_THROW(Rpc_alloc_receiver, Signal_receiver_capability,
|
||||
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,
|
||||
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_TYPE_LIST(Exception),
|
||||
Signal_context_capability);
|
||||
|
||||
GENODE_RPC_INTERFACE(Rpc_alloc_receiver, Rpc_alloc_context,
|
||||
Rpc_free_context);
|
||||
Rpc_free_receiver, Rpc_free_context);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
/* release core resources */
|
||||
/* release server resources of context */
|
||||
signal_connection()->free_context(c->_cap);
|
||||
|
||||
/* reset the context */
|
||||
@ -128,7 +135,7 @@ Signal_context_capability Signal_receiver::manage(Signal_context * const c)
|
||||
/* check if the context is already managed */
|
||||
Lock::Guard contexts_guard(_contexts_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 */
|
||||
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)
|
||||
throw Context_not_associated();
|
||||
|
||||
if (context->_receiver != this) { throw Context_not_associated(); }
|
||||
Lock::Guard list_lock_guard(_contexts_lock);
|
||||
|
||||
_unsynchronized_dissolve(context);
|
||||
|
||||
/*
|
||||
@ -180,24 +184,17 @@ bool Signal_receiver::pending() { return Kernel::signal_pending(_cap.dst()); }
|
||||
Signal Signal_receiver::wait_for_signal()
|
||||
{
|
||||
/* await a signal */
|
||||
Kernel::await_signal(_cap.dst());
|
||||
Signal s(*(Signal::Data *)Thread_base::myself()->utcb());
|
||||
Signal_context * const c = s.context();
|
||||
|
||||
/* 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) ;
|
||||
if (Kernel::await_signal(_cap.dst())) {
|
||||
PERR("failed to receive signal");
|
||||
throw Exception();
|
||||
}
|
||||
/* check attributes of the signal and return it */
|
||||
if (s.num() == 0) PWRN("Returning signal with num == 0");
|
||||
/* get signal data */
|
||||
Signal s(*(Signal::Data *)Thread_base::myself()->utcb());
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
void Signal_receiver::local_submit(Signal::Data signal) {
|
||||
PDBG("Not implemented"); };
|
||||
|
||||
|
||||
void Signal_receiver::_platform_destructor() { }
|
||||
void Signal_receiver::local_submit(Signal::Data signal)
|
||||
{
|
||||
PDBG("Not implemented");
|
||||
}
|
||||
|
@ -37,15 +37,22 @@ namespace Genode
|
||||
|
||||
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
|
||||
*/
|
||||
class Context;
|
||||
|
||||
typedef Object_pool<Context> Context_pool;
|
||||
typedef Object_pool<Receiver> Receiver_pool;
|
||||
typedef Object_pool<Context> Context_pool;
|
||||
|
||||
Allocator_guard _md_alloc;
|
||||
Slab _receivers_slab;
|
||||
Receiver_pool _receivers;
|
||||
Slab _contexts_slab;
|
||||
Context_pool _contexts;
|
||||
char _initial_receivers_sb [RECEIVERS_SB_SIZE];
|
||||
@ -81,10 +88,43 @@ namespace Genode
|
||||
Signal_context_capability
|
||||
alloc_context(Signal_receiver_capability, unsigned const);
|
||||
|
||||
void free_receiver(Signal_receiver_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
|
||||
{
|
||||
public:
|
||||
@ -110,9 +150,9 @@ class Genode::Signal_session_component::Context : public Context_pool::Entry
|
||||
/**
|
||||
* 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));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -91,13 +91,6 @@ 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>,
|
||||
public Execution_context
|
||||
{
|
||||
@ -601,15 +594,16 @@ namespace Kernel
|
||||
*/
|
||||
void do_new_signal_receiver(Thread * const user)
|
||||
{
|
||||
/* check permissions */
|
||||
assert(user->pd_id() == core_id());
|
||||
|
||||
/* create receiver */
|
||||
void * dst = (void *)user->user_arg_1();
|
||||
Signal_receiver * const r = new (dst) Signal_receiver();
|
||||
|
||||
/* return success */
|
||||
user->user_arg_0(r->id());
|
||||
/* check permissions */
|
||||
if (user->pd_id() != core_id()) {
|
||||
PERR("permission to create signal receiver denied");
|
||||
user->user_arg_0(0);
|
||||
return;
|
||||
}
|
||||
/* create receiver */
|
||||
void * p = (void *)user->user_arg_1();
|
||||
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)
|
||||
{
|
||||
/* 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 */
|
||||
unsigned rid = user->user_arg_2();
|
||||
Signal_receiver * const r = Signal_receiver::pool()->object(rid);
|
||||
assert(r);
|
||||
|
||||
/* create context */
|
||||
void * dst = (void *)user->user_arg_1();
|
||||
unsigned id = user->user_arg_2();
|
||||
Signal_receiver * const r = Signal_receiver::pool()->object(id);
|
||||
if (!r) {
|
||||
PERR("invalid signal receiver");
|
||||
user->user_arg_0(0);
|
||||
return;
|
||||
}
|
||||
/* create and assign context*/
|
||||
void * p = (void *)user->user_arg_1();
|
||||
unsigned imprint = user->user_arg_3();
|
||||
Signal_context * const c = new (dst) Signal_context(r, imprint);
|
||||
|
||||
/* return success */
|
||||
if (r->new_context(p, imprint)) {
|
||||
PERR("failed to create signal context");
|
||||
user->user_arg_0(0);
|
||||
return;
|
||||
}
|
||||
/* return context name */
|
||||
Signal_context * const c = (Signal_context *)p;
|
||||
user->user_arg_0(c->id());
|
||||
}
|
||||
|
||||
@ -642,13 +646,21 @@ namespace Kernel
|
||||
void do_await_signal(Thread * const user)
|
||||
{
|
||||
/* lookup receiver */
|
||||
unsigned rid = user->user_arg_2();
|
||||
Signal_receiver * const r = Signal_receiver::pool()->object(rid);
|
||||
assert(r);
|
||||
|
||||
/* let user listen to receiver */
|
||||
unsigned id = user->user_arg_1();
|
||||
Signal_receiver * const r = Signal_receiver::pool()->object(id);
|
||||
if (!r) {
|
||||
PERR("invalid signal receiver");
|
||||
user->user_arg_0(-1);
|
||||
return;
|
||||
}
|
||||
/* register handler at the receiver */
|
||||
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)
|
||||
{
|
||||
/* lookup receiver */
|
||||
unsigned rid = user->user_arg_2();
|
||||
Signal_receiver * const r = Signal_receiver::pool()->object(rid);
|
||||
assert(r);
|
||||
|
||||
/* set return value */
|
||||
/* lookup signal receiver */
|
||||
unsigned id = user->user_arg_1();
|
||||
Signal_receiver * const r = Signal_receiver::pool()->object(id);
|
||||
if (!r) {
|
||||
PERR("invalid signal receiver");
|
||||
user->user_arg_0(0);
|
||||
return;
|
||||
}
|
||||
/* get pending state */
|
||||
user->user_arg_0(r->deliverable());
|
||||
}
|
||||
|
||||
@ -672,15 +687,20 @@ namespace Kernel
|
||||
*/
|
||||
void do_submit_signal(Thread * const user)
|
||||
{
|
||||
/* lookup context */
|
||||
Signal_context * const c =
|
||||
Signal_context::pool()->object(user->user_arg_1());
|
||||
/* lookup signal context */
|
||||
unsigned const id = user->user_arg_1();
|
||||
Signal_context * const c = Signal_context::pool()->object(id);
|
||||
if(!c) {
|
||||
PDBG("invalid signal-context capability");
|
||||
PERR("invalid signal context");
|
||||
user->user_arg_0(-1);
|
||||
return;
|
||||
}
|
||||
/* trigger signal at context */
|
||||
c->submit(user->user_arg_2());
|
||||
/* trigger signal context */
|
||||
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)
|
||||
{
|
||||
/* lookup signal context */
|
||||
unsigned id = user->user_arg_1();
|
||||
Signal_context * const c = Signal_context::pool()->object(id);
|
||||
if (!c) return;
|
||||
Thread * const t = (Thread *)c->ack();
|
||||
if (t) { t->kill_signal_context_done(); }
|
||||
if (!c) {
|
||||
PWRN("invalid signal context");
|
||||
return;
|
||||
}
|
||||
/* acknowledge */
|
||||
c->ack();
|
||||
}
|
||||
|
||||
|
||||
@ -703,15 +727,55 @@ namespace Kernel
|
||||
void do_kill_signal_context(Thread * const user)
|
||||
{
|
||||
/* 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();
|
||||
Signal_context * const c = Signal_context::pool()->object(id);
|
||||
if (!c) { return; }
|
||||
if (c->kill((unsigned)user)) { return; }
|
||||
user->kill_signal_context_blocks();
|
||||
if (!c) {
|
||||
user->user_arg_0(0);
|
||||
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'
|
||||
*/
|
||||
@ -779,38 +843,39 @@ namespace Kernel
|
||||
{
|
||||
switch (user->user_arg_0())
|
||||
{
|
||||
case NEW_THREAD: do_new_thread(user); return;
|
||||
case DELETE_THREAD: do_delete_thread(user); return;
|
||||
case START_THREAD: do_start_thread(user); return;
|
||||
case PAUSE_THREAD: do_pause_thread(user); return;
|
||||
case RESUME_THREAD: do_resume_thread(user); return;
|
||||
case RESUME_FAULTER: do_resume_faulter(user); return;
|
||||
case GET_THREAD: do_get_thread(user); return;
|
||||
case CURRENT_THREAD_ID: do_current_thread_id(user); return;
|
||||
case YIELD_THREAD: do_yield_thread(user); return;
|
||||
case READ_THREAD_STATE: do_read_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 REPLY: do_reply(user); return;
|
||||
case WAIT_FOR_REQUEST: do_wait_for_request(user); return;
|
||||
case SET_PAGER: do_set_pager(user); return;
|
||||
case UPDATE_PD: do_update_pd(user); return;
|
||||
case UPDATE_REGION: do_update_region(user); return;
|
||||
case NEW_PD: do_new_pd(user); return;
|
||||
case ALLOCATE_IRQ: do_allocate_irq(user); return;
|
||||
case AWAIT_IRQ: do_await_irq(user); return;
|
||||
case FREE_IRQ: do_free_irq(user); return;
|
||||
case PRINT_CHAR: do_print_char(user); return;
|
||||
case NEW_SIGNAL_RECEIVER: do_new_signal_receiver(user); return;
|
||||
case NEW_SIGNAL_CONTEXT: do_new_signal_context(user); return;
|
||||
case KILL_SIGNAL_CONTEXT: do_kill_signal_context(user); return;
|
||||
case AWAIT_SIGNAL: do_await_signal(user); return;
|
||||
case SUBMIT_SIGNAL: do_submit_signal(user); return;
|
||||
case SIGNAL_PENDING: do_signal_pending(user); return;
|
||||
case ACK_SIGNAL: do_ack_signal(user); return;
|
||||
case NEW_VM: do_new_vm(user); return;
|
||||
case RUN_VM: do_run_vm(user); return;
|
||||
case PAUSE_VM: do_pause_vm(user); return;
|
||||
case NEW_THREAD: do_new_thread(user); return;
|
||||
case DELETE_THREAD: do_delete_thread(user); return;
|
||||
case START_THREAD: do_start_thread(user); return;
|
||||
case PAUSE_THREAD: do_pause_thread(user); return;
|
||||
case RESUME_THREAD: do_resume_thread(user); return;
|
||||
case RESUME_FAULTER: do_resume_faulter(user); return;
|
||||
case GET_THREAD: do_get_thread(user); return;
|
||||
case CURRENT_THREAD_ID: do_current_thread_id(user); return;
|
||||
case YIELD_THREAD: do_yield_thread(user); return;
|
||||
case READ_THREAD_STATE: do_read_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 REPLY: do_reply(user); return;
|
||||
case WAIT_FOR_REQUEST: do_wait_for_request(user); return;
|
||||
case SET_PAGER: do_set_pager(user); return;
|
||||
case UPDATE_PD: do_update_pd(user); return;
|
||||
case UPDATE_REGION: do_update_region(user); return;
|
||||
case NEW_PD: do_new_pd(user); return;
|
||||
case ALLOCATE_IRQ: do_allocate_irq(user); return;
|
||||
case AWAIT_IRQ: do_await_irq(user); return;
|
||||
case FREE_IRQ: do_free_irq(user); return;
|
||||
case PRINT_CHAR: do_print_char(user); return;
|
||||
case NEW_SIGNAL_RECEIVER: do_new_signal_receiver(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_RECEIVER: do_kill_signal_receiver(user); return;
|
||||
case AWAIT_SIGNAL: do_await_signal(user); return;
|
||||
case SUBMIT_SIGNAL: do_submit_signal(user); return;
|
||||
case SIGNAL_PENDING: do_signal_pending(user); return;
|
||||
case ACK_SIGNAL: do_ack_signal(user); return;
|
||||
case NEW_VM: do_new_vm(user); return;
|
||||
case RUN_VM: do_run_vm(user); return;
|
||||
case PAUSE_VM: do_pause_vm(user); return;
|
||||
default:
|
||||
PERR("invalid syscall");
|
||||
user->crash();
|
||||
|
25
base-hw/src/core/kernel/signal_receiver.cc
Normal file
25
base-hw/src/core/kernel/signal_receiver.cc
Normal 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); }
|
@ -25,10 +25,20 @@
|
||||
namespace Kernel
|
||||
{
|
||||
/**
|
||||
* Enables external components to act as a signal handler
|
||||
* Ability to receive from signal receivers
|
||||
*/
|
||||
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
|
||||
*/
|
||||
@ -38,17 +48,6 @@ namespace Kernel
|
||||
* Combines signal contexts to an entity that handlers can listen to
|
||||
*/
|
||||
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
|
||||
@ -59,22 +58,56 @@ class Kernel::Signal_handler
|
||||
|
||||
typedef Genode::Fifo_element<Signal_handler> Fifo_element;
|
||||
|
||||
Fifo_element _fe;
|
||||
unsigned const _id;
|
||||
Fifo_element _handlers_fe;
|
||||
|
||||
/**
|
||||
* 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:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Signal_handler(unsigned id) : _fe(this), _id(id) { }
|
||||
Signal_handler() : _handlers_fe(this) { }
|
||||
};
|
||||
|
||||
class Kernel::Signal_context_killer
|
||||
{
|
||||
friend class Signal_context;
|
||||
|
||||
/***************
|
||||
** Accessors **
|
||||
***************/
|
||||
private:
|
||||
|
||||
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
|
||||
@ -87,17 +120,18 @@ class Kernel::Signal_context
|
||||
|
||||
typedef Genode::Fifo_element<Signal_context> Fifo_element;
|
||||
|
||||
Fifo_element _fe;
|
||||
Fifo_element _deliver_fe;
|
||||
Fifo_element _contexts_fe;
|
||||
Signal_receiver * const _receiver;
|
||||
unsigned const _imprint;
|
||||
unsigned _submits;
|
||||
bool _ack;
|
||||
unsigned _killer;
|
||||
Signal_context_killer * _killer;
|
||||
|
||||
/**
|
||||
* Tell receiver about the submits of the context if any
|
||||
*/
|
||||
inline void _deliverable();
|
||||
void _deliverable();
|
||||
|
||||
/**
|
||||
* Called by receiver when all submits have been delivered
|
||||
@ -108,85 +142,87 @@ class Kernel::Signal_context
|
||||
_ack = 0;
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
~Signal_context();
|
||||
|
||||
/**
|
||||
* 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)
|
||||
:
|
||||
_fe(this), _receiver(r), _imprint(imprint), _submits(0), _ack(1),
|
||||
_killer(0)
|
||||
_deliver_fe(this), _contexts_fe(this), _receiver(r),
|
||||
_imprint(imprint), _submits(0), _ack(1), _killer(0)
|
||||
{ }
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Submit the signal
|
||||
*
|
||||
* \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) {
|
||||
PERR("overflow at signal-submit count");
|
||||
return;
|
||||
}
|
||||
if (_killer) {
|
||||
PERR("signal context already in destruction");
|
||||
return;
|
||||
}
|
||||
if (_killer || _submits >= (unsigned)~0 - n) { return -1; }
|
||||
_submits += n;
|
||||
if (!_ack) { return; }
|
||||
_deliverable();
|
||||
if (_ack) { _deliverable(); }
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Acknowledge delivery of signal
|
||||
*
|
||||
* \retval 0 no kill request finished
|
||||
* \retval > 0 name of finished kill request
|
||||
*/
|
||||
unsigned ack()
|
||||
void ack()
|
||||
{
|
||||
if (_ack) {
|
||||
PERR("unexpected signal acknowledgment");
|
||||
return 0;
|
||||
}
|
||||
if (_ack) { return; }
|
||||
if (!_killer) {
|
||||
_ack = 1;
|
||||
_deliverable();
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
this->~Signal_context();
|
||||
return _killer;
|
||||
_killer->_signal_context_kill_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 destruction is initiated, will be done with the next ack
|
||||
* \retval 0 succeeded
|
||||
* \retval -1 failed
|
||||
*/
|
||||
bool kill(unsigned const killer)
|
||||
int kill(Signal_context_killer * const k)
|
||||
{
|
||||
/* FIXME: aggregate or avoid multiple kill requests */
|
||||
if (_killer) {
|
||||
PERR("multiple kill requests");
|
||||
while (1) { }
|
||||
if (_killer) { return -1; }
|
||||
|
||||
/* destruct directly if there is no unacknowledged delivery */
|
||||
if (_ack) {
|
||||
this->~Signal_context();
|
||||
return 0;
|
||||
}
|
||||
_killer = killer;
|
||||
if (!_ack) { return 0; }
|
||||
this->~Signal_context();
|
||||
return 1;
|
||||
/* wait for delivery acknowledgement */
|
||||
_killer = k;
|
||||
_killer->_signal_context_kill_pending();
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
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 Context_killer;
|
||||
|
||||
private:
|
||||
|
||||
@ -195,14 +231,19 @@ class Kernel::Signal_receiver
|
||||
template <typename T> class Fifo : public Genode::Fifo<T> { };
|
||||
|
||||
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
|
||||
*/
|
||||
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();
|
||||
}
|
||||
|
||||
@ -214,53 +255,128 @@ class Kernel::Signal_receiver
|
||||
while (1)
|
||||
{
|
||||
/* check if there are deliverable signal */
|
||||
if (_deliverable.empty()) return;
|
||||
Signal_context * const c = _deliverable.dequeue()->object();
|
||||
if (_deliver.empty()) return;
|
||||
Signal_context * const c = _deliver.dequeue()->object();
|
||||
|
||||
/* if there is no handler re-enqueue context and exit */
|
||||
if (_handlers.empty()) {
|
||||
_deliverable.enqueue(&c->_fe);
|
||||
_deliver.enqueue(&c->_deliver_fe);
|
||||
return;
|
||||
}
|
||||
/* delivery from context to handler */
|
||||
Signal_handler * const h = _handlers.dequeue()->object();
|
||||
Signal::Data data((Genode::Signal_context *)c->_imprint,
|
||||
c->_submits);
|
||||
deliver_signal(h, &data, sizeof(data));
|
||||
h->_signal_handler(&data, sizeof(data));
|
||||
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:
|
||||
|
||||
/**
|
||||
* 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();
|
||||
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)
|
||||
{
|
||||
_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
|
||||
*/
|
||||
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_ */
|
||||
|
@ -81,7 +81,10 @@ class Kernel::Thread
|
||||
public Object<Thread, MAX_THREADS>,
|
||||
public Execution_context,
|
||||
public Ipc_node,
|
||||
public Irq_receiver
|
||||
public Irq_receiver,
|
||||
public Signal_context_killer,
|
||||
public Signal_receiver_killer,
|
||||
public Signal_handler
|
||||
{
|
||||
private:
|
||||
|
||||
@ -93,7 +96,7 @@ class Kernel::Thread
|
||||
AWAIT_RESUMPTION,
|
||||
AWAIT_IRQ,
|
||||
AWAIT_SIGNAL,
|
||||
AWAIT_SIGNAL_CONTEXT_DESTRUCT,
|
||||
AWAIT_SIGNAL_CONTEXT_KILL,
|
||||
CRASHED,
|
||||
};
|
||||
|
||||
@ -105,7 +108,6 @@ class Kernel::Thread
|
||||
Native_utcb * _phys_utcb;
|
||||
Native_utcb * _virt_utcb;
|
||||
Signal_receiver * _signal_receiver;
|
||||
Signal_handler _signal_handler;
|
||||
|
||||
/**
|
||||
* Resume execution
|
||||
@ -116,6 +118,47 @@ class Kernel::Thread
|
||||
_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 **
|
||||
@ -161,7 +204,7 @@ class Kernel::Thread
|
||||
:
|
||||
_platform_thread(platform_thread), _state(AWAIT_START),
|
||||
_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;
|
||||
case AWAIT_SIGNAL:
|
||||
PDBG("cancel signal receipt");
|
||||
_signal_receiver->remove_handler(signal_handler());
|
||||
_signal_receiver->remove_handler(this);
|
||||
_schedule();
|
||||
return 0;
|
||||
case AWAIT_SIGNAL_CONTEXT_DESTRUCT:
|
||||
case AWAIT_SIGNAL_CONTEXT_KILL:
|
||||
PDBG("cancel signal context destruction");
|
||||
_schedule();
|
||||
return 0;
|
||||
@ -361,41 +404,6 @@ class Kernel::Thread
|
||||
_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 **
|
||||
@ -441,8 +449,6 @@ class Kernel::Thread
|
||||
unsigned pd_id() const { return _pd_id; }
|
||||
|
||||
Native_utcb * phys_utcb() const { return _phys_utcb; }
|
||||
|
||||
Signal_handler * signal_handler() { return &_signal_handler; }
|
||||
};
|
||||
|
||||
#endif /* _CORE__KERNEL__THREAD_H_ */
|
||||
|
@ -13,7 +13,6 @@
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/printf.h>
|
||||
#include <base/sleep.h>
|
||||
#include <kernel/syscalls.h>
|
||||
|
||||
/* core includes */
|
||||
@ -31,7 +30,7 @@ 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,
|
||||
_receivers_slab(Receiver::slab_size(), RECEIVERS_SB_SIZE,
|
||||
(Slab_block *)&_initial_receivers_sb, &_md_alloc),
|
||||
_contexts_slab(Context::slab_size(), CONTEXTS_SB_SIZE,
|
||||
(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()
|
||||
{
|
||||
/* allocate resources for receiver */
|
||||
size_t const s = Kernel::signal_receiver_size();
|
||||
void * p;
|
||||
if (!_receivers_slab.alloc(s, &p)) {
|
||||
PERR("failed to allocate signal receiver");
|
||||
if (!_receivers_slab.alloc(Receiver::slab_size(), &p)) {
|
||||
PERR("failed to allocate signal-receiver resources");
|
||||
throw Out_of_metadata();
|
||||
}
|
||||
/* create kernel object for receiver */
|
||||
unsigned const id = Kernel::new_signal_receiver(p);
|
||||
if (!id) {
|
||||
addr_t donation = Receiver::kernel_donation(p);
|
||||
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");
|
||||
throw Exception();
|
||||
}
|
||||
/* remember receiver ressources */
|
||||
Native_capability cap(id, id);
|
||||
Receiver * const r = new (p) Receiver(cap);
|
||||
_receivers.insert(r);
|
||||
|
||||
/* return receiver capability */
|
||||
Native_capability c(id, id);
|
||||
return reinterpret_cap_cast<Signal_receiver>(c);
|
||||
return reinterpret_cap_cast<Signal_receiver>(cap);
|
||||
}
|
||||
|
||||
|
||||
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();
|
||||
}
|
||||
/* 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);
|
||||
if (!id)
|
||||
{
|
||||
@ -104,7 +133,7 @@ void Signal_session_component::free_context(Signal_context_capability cap)
|
||||
throw Exception();
|
||||
}
|
||||
/* release kernel resources */
|
||||
if (!Kernel::kill_signal_context(c->id()))
|
||||
if (Kernel::kill_signal_context(c->id()))
|
||||
{
|
||||
/* clean-up */
|
||||
c->release();
|
||||
|
@ -47,6 +47,7 @@ SRC_CC += console.cc \
|
||||
trace_session_component.cc \
|
||||
thread.cc \
|
||||
kernel.cc \
|
||||
kernel/signal_receiver.cc \
|
||||
rm_session_support.cc \
|
||||
kernel_support.cc \
|
||||
trustzone.cc \
|
||||
|
Loading…
Reference in New Issue
Block a user