mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-02 20:16:48 +00:00
parent
0f8803245a
commit
438b8be2fa
@ -1,236 +0,0 @@
|
|||||||
/*
|
|
||||||
* \brief Delivery and reception of asynchronous notifications on HW-core
|
|
||||||
* \author Martin Stein
|
|
||||||
* \date 2012-05-05
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _INCLUDE__BASE__SIGNAL_H__
|
|
||||||
#define _INCLUDE__BASE__SIGNAL_H__
|
|
||||||
|
|
||||||
/* Genode includes */
|
|
||||||
#include <signal_session/signal_session.h>
|
|
||||||
#include <base/lock.h>
|
|
||||||
#include <util/list.h>
|
|
||||||
|
|
||||||
namespace Genode
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* A bunch of asynchronuosly triggered events that target the same context
|
|
||||||
*
|
|
||||||
* Because a signal can trigger asynchronously at a context,
|
|
||||||
* the kernel accumulates them and provides them as such a bunch,
|
|
||||||
* once the receiver indicates that he is ready to receive.
|
|
||||||
*/
|
|
||||||
class Signal
|
|
||||||
{
|
|
||||||
unsigned _imprint; /* receiver-local signal-context pointer */
|
|
||||||
int _num; /* how often this signal has been triggered */
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct valid signal
|
|
||||||
*/
|
|
||||||
Signal(unsigned const imprint, int const num) :
|
|
||||||
_imprint(imprint), _num(num) { }
|
|
||||||
|
|
||||||
/***************
|
|
||||||
** Accessors **
|
|
||||||
***************/
|
|
||||||
|
|
||||||
Signal_context * context() { return (Signal_context *)_imprint; }
|
|
||||||
|
|
||||||
int num() { return _num; }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
typedef List<Signal_context> Context_list;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A specific signal type that a transmitter can target when it submits
|
|
||||||
*
|
|
||||||
* One receiver might handle multiple signal contexts,
|
|
||||||
* but a signal context is owned by exactly one signal receiver.
|
|
||||||
*/
|
|
||||||
class Signal_context : public Context_list::Element
|
|
||||||
{
|
|
||||||
friend class Signal_receiver;
|
|
||||||
|
|
||||||
Signal_receiver * _receiver; /* receiver that manages us */
|
|
||||||
Lock _lock; /* serialize object access */
|
|
||||||
Signal_context_capability _cap; /* holds the name of our context
|
|
||||||
* kernel-object as 'dst' */
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct context that is not yet managed by a receiver
|
|
||||||
*/
|
|
||||||
Signal_context() : _receiver(0), _lock(Lock::UNLOCKED) { }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destructor
|
|
||||||
*/
|
|
||||||
virtual ~Signal_context() { }
|
|
||||||
|
|
||||||
/* solely needed to enable one to type a capability with us */
|
|
||||||
GENODE_RPC_INTERFACE();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* To submit signals to one specific context
|
|
||||||
*
|
|
||||||
* Multiple transmitters can submit to the same context.
|
|
||||||
*/
|
|
||||||
class Signal_transmitter
|
|
||||||
{
|
|
||||||
/* names the targeted context kernel-object with its 'dst' field */
|
|
||||||
Signal_context_capability _context;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*/
|
|
||||||
Signal_transmitter(Signal_context_capability const c =
|
|
||||||
Signal_context_capability())
|
|
||||||
: _context(c) { }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Trigger a signal 'num' times at the context we target
|
|
||||||
*/
|
|
||||||
void submit(int const num = 1)
|
|
||||||
{ Kernel::submit_signal(_context.dst(), num); }
|
|
||||||
|
|
||||||
/***************
|
|
||||||
** Accessors **
|
|
||||||
***************/
|
|
||||||
|
|
||||||
void context(Signal_context_capability const c) { _context = c; }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Manage multiple signal contexts and receive signals targeted to them
|
|
||||||
*/
|
|
||||||
class Signal_receiver
|
|
||||||
{
|
|
||||||
Context_list _contexts; /* contexts that we manage */
|
|
||||||
Lock _contexts_lock; /* serialize access to
|
|
||||||
* 'contexts' */
|
|
||||||
Signal_receiver_capability _cap; /* holds name of our receiver
|
|
||||||
* kernel-object as 'dst' */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Let a context 'c' no longer be managed by us
|
|
||||||
*
|
|
||||||
* Doesn't serialize any member access.
|
|
||||||
*/
|
|
||||||
void _unsync_dissolve(Signal_context * const c);
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
class Context_already_in_use : public Exception { };
|
|
||||||
class Context_not_associated : public Exception { };
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*/
|
|
||||||
Signal_receiver();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destructor
|
|
||||||
*/
|
|
||||||
~Signal_receiver();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Let a context 'c' be managed by us
|
|
||||||
*
|
|
||||||
* \return Capability wich names the context kernel-object in its
|
|
||||||
* 'dst' field . Can be used as target for transmitters.
|
|
||||||
*/
|
|
||||||
Signal_context_capability manage(Signal_context * const c);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If any of our signal contexts is pending
|
|
||||||
*/
|
|
||||||
bool pending();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Let a context 'c' no longer be managed by us
|
|
||||||
*/
|
|
||||||
void dissolve(Signal_context * const c);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Block on any signal that is triggered at one of our contexts
|
|
||||||
*/
|
|
||||||
Signal wait_for_signal();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Abstract interface to be implemented by signal dispatchers
|
|
||||||
*/
|
|
||||||
struct Signal_dispatcher_base : Signal_context
|
|
||||||
{
|
|
||||||
virtual void dispatch(unsigned num) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adapter for directing signals to member functions
|
|
||||||
*
|
|
||||||
* This utility associates member functions with signals. It is intended to
|
|
||||||
* be used as a member variable of the class that handles incoming signals
|
|
||||||
* of a certain type. The constructor takes a pointer-to-member to the
|
|
||||||
* signal handling function as argument. If a signal is received at the
|
|
||||||
* common signal reception code, this function will be invoked by calling
|
|
||||||
* 'Signal_dispatcher_base::dispatch'.
|
|
||||||
*
|
|
||||||
* \param T type of signal-handling class
|
|
||||||
*/
|
|
||||||
template <typename T>
|
|
||||||
class Signal_dispatcher : private Signal_dispatcher_base,
|
|
||||||
public Signal_context_capability
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
|
|
||||||
T &obj;
|
|
||||||
void (T::*member) (unsigned);
|
|
||||||
Signal_receiver &sig_rec;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* \param sig_rec signal receiver to associate the signal
|
|
||||||
* handler with
|
|
||||||
* \param obj,member object and member function to call when
|
|
||||||
* the signal occurs
|
|
||||||
*/
|
|
||||||
Signal_dispatcher(Signal_receiver &sig_rec,
|
|
||||||
T &obj, void (T::*member)(unsigned))
|
|
||||||
:
|
|
||||||
Signal_context_capability(sig_rec.manage(this)),
|
|
||||||
obj(obj), member(member),
|
|
||||||
sig_rec(sig_rec)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
~Signal_dispatcher() { sig_rec.dissolve(this); }
|
|
||||||
|
|
||||||
void dispatch(unsigned num) { (obj.*member)(num); }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* _INCLUDE__BASE__SIGNAL_H__ */
|
|
||||||
|
|
@ -71,9 +71,11 @@ namespace Kernel
|
|||||||
/* asynchronous signalling */
|
/* asynchronous signalling */
|
||||||
NEW_SIGNAL_RECEIVER = 20,
|
NEW_SIGNAL_RECEIVER = 20,
|
||||||
NEW_SIGNAL_CONTEXT = 21,
|
NEW_SIGNAL_CONTEXT = 21,
|
||||||
|
KILL_SIGNAL_CONTEXT = 30,
|
||||||
AWAIT_SIGNAL = 22,
|
AWAIT_SIGNAL = 22,
|
||||||
SUBMIT_SIGNAL = 23,
|
SUBMIT_SIGNAL = 23,
|
||||||
SIGNAL_PENDING = 27,
|
SIGNAL_PENDING = 27,
|
||||||
|
ACK_SIGNAL = 29,
|
||||||
|
|
||||||
/* vm specific */
|
/* vm specific */
|
||||||
NEW_VM = 24,
|
NEW_VM = 24,
|
||||||
@ -455,13 +457,14 @@ namespace Kernel
|
|||||||
*
|
*
|
||||||
* \param receiver_id ID of the targeted receiver kernel-object
|
* \param receiver_id ID of the targeted receiver kernel-object
|
||||||
*
|
*
|
||||||
* When this call returns, an instance of 'Signal' is located at the base
|
* When this call returns, an instance of 'Signal::Data' is located at the
|
||||||
* of the callers UTCB. It holds information about wich context was
|
* base of the callers UTCB. It's granted that every occurence of a signal
|
||||||
* triggered how often. It is granted that every occurence of a signal is
|
* is provided through this function, exactly till it gets delivered through
|
||||||
* provided through this function, exactly till it gets delivered through
|
* this function. If multiple threads listen at the same receiver, and/or
|
||||||
* this function. If multiple threads listen at the same receiver and/or
|
* multiple contexts of the receiver trigger simultanously, there is no
|
||||||
* multiple contexts trigger simultanously there is no assertion about
|
* assertion about wich thread receives, and from wich context. But
|
||||||
* wich thread receives the 'Signal' instance of wich context.
|
* 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 void await_signal(unsigned receiver_id) {
|
||||||
syscall(AWAIT_SIGNAL, (Syscall_arg)receiver_id); }
|
syscall(AWAIT_SIGNAL, (Syscall_arg)receiver_id); }
|
||||||
@ -485,6 +488,29 @@ namespace Kernel
|
|||||||
inline void submit_signal(unsigned context_id, int num) {
|
inline void submit_signal(unsigned context_id, int num) {
|
||||||
syscall(SUBMIT_SIGNAL, (Syscall_arg)context_id, (Syscall_arg)num); }
|
syscall(SUBMIT_SIGNAL, (Syscall_arg)context_id, (Syscall_arg)num); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Acknowledge the processing of the last signal 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.
|
||||||
|
*/
|
||||||
|
inline void ack_signal(unsigned context_id) {
|
||||||
|
syscall(ACK_SIGNAL, (Syscall_arg)context_id); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destruct a signal context
|
||||||
|
*
|
||||||
|
* \param context_id kernel name of the targeted signal context
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
inline void kill_signal_context(unsigned context_id) {
|
||||||
|
syscall(KILL_SIGNAL_CONTEXT, (Syscall_arg)context_id); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new virtual-machine that is stopped initially
|
* Create a new virtual-machine that is stopped initially
|
||||||
|
@ -45,6 +45,9 @@ namespace Genode
|
|||||||
alloc_context(Signal_receiver_capability const r,
|
alloc_context(Signal_receiver_capability const r,
|
||||||
unsigned const imprint) {
|
unsigned const imprint) {
|
||||||
return call<Rpc_alloc_context>(r, imprint); }
|
return call<Rpc_alloc_context>(r, imprint); }
|
||||||
|
|
||||||
|
void free_context(Signal_context_capability cap) {
|
||||||
|
call<Rpc_free_context>(cap); }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,6 +78,13 @@ namespace Genode
|
|||||||
alloc_context(Signal_receiver_capability const r,
|
alloc_context(Signal_receiver_capability const r,
|
||||||
unsigned const imprint) = 0;
|
unsigned const imprint) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free signal-context
|
||||||
|
*
|
||||||
|
* \param cap capability of signal-context to release
|
||||||
|
*/
|
||||||
|
virtual void free_context(Signal_context_capability cap) = 0;
|
||||||
|
|
||||||
/*********************
|
/*********************
|
||||||
** RPC declaration **
|
** RPC declaration **
|
||||||
*********************/
|
*********************/
|
||||||
@ -87,8 +94,11 @@ namespace Genode
|
|||||||
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);
|
Signal_receiver_capability, unsigned);
|
||||||
|
GENODE_RPC(Rpc_free_context, void, free_context,
|
||||||
|
Signal_context_capability);
|
||||||
|
|
||||||
GENODE_RPC_INTERFACE(Rpc_alloc_receiver, Rpc_alloc_context);
|
GENODE_RPC_INTERFACE(Rpc_alloc_receiver, Rpc_alloc_context,
|
||||||
|
Rpc_free_context);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ SRC_CC += process/process.cc
|
|||||||
SRC_CC += elf/elf_binary.cc
|
SRC_CC += elf/elf_binary.cc
|
||||||
SRC_CC += console/console.cc
|
SRC_CC += console/console.cc
|
||||||
SRC_CC += lock/lock.cc
|
SRC_CC += lock/lock.cc
|
||||||
SRC_CC += signal/signal.cc
|
SRC_CC += signal/signal.cc signal/common.cc
|
||||||
SRC_CC += server/server.cc server/common.cc
|
SRC_CC += server/server.cc server/common.cc
|
||||||
SRC_CC += thread/thread_bootstrap_empty.cc
|
SRC_CC += thread/thread_bootstrap_empty.cc
|
||||||
|
|
||||||
|
@ -30,11 +30,60 @@ static Signal_connection * signal_connection()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/************
|
||||||
|
** Signal **
|
||||||
|
************/
|
||||||
|
|
||||||
|
void Signal::_dec_ref_and_unlock()
|
||||||
|
{
|
||||||
|
if (_data.context) {
|
||||||
|
Lock::Guard lock_guard(_data.context->_lock);
|
||||||
|
_data.context->_ref_cnt--;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We must ack a signal context to receive the next one,
|
||||||
|
* so new signals are received only when ref_cnt = 0.
|
||||||
|
*/
|
||||||
|
if (_data.context->_ref_cnt == 0)
|
||||||
|
Kernel::ack_signal(_data.context->_cap.dst());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Signal::_inc_ref()
|
||||||
|
{
|
||||||
|
if (_data.context) {
|
||||||
|
Lock::Guard lock_guard(_data.context->_lock);
|
||||||
|
_data.context->_ref_cnt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Signal::Signal(Signal::Data data) : _data(data)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* We assume that a kernel signal-context doesn't deliver
|
||||||
|
* multiple signals simultaneously.
|
||||||
|
*/
|
||||||
|
if (_data.context) _data.context->_ref_cnt = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/************************
|
||||||
|
** Signal transmitter **
|
||||||
|
************************/
|
||||||
|
|
||||||
|
void Signal_transmitter::submit(unsigned cnt)
|
||||||
|
{
|
||||||
|
/* submits to invalid signal contexts get ignored */
|
||||||
|
Kernel::submit_signal(_context.dst(), cnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*********************
|
/*********************
|
||||||
** Signal_receiver **
|
** Signal_receiver **
|
||||||
*********************/
|
*********************/
|
||||||
|
|
||||||
|
|
||||||
Signal_receiver::Signal_receiver()
|
Signal_receiver::Signal_receiver()
|
||||||
{
|
{
|
||||||
/* create a kernel object that corresponds to the receiver */
|
/* create a kernel object that corresponds to the receiver */
|
||||||
@ -59,16 +108,27 @@ Signal_receiver::Signal_receiver()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Signal_receiver::~Signal_receiver()
|
void Signal_receiver::_unsynchronized_dissolve(Signal_context * c)
|
||||||
{
|
{
|
||||||
/* dissolve all contexts that are managed by us */
|
/*
|
||||||
Lock::Guard contexts_guard(_contexts_lock);
|
* We first destroy the kernel object. This also ensures
|
||||||
while (1) {
|
* that no delivered but unacked signals of this context exist
|
||||||
Signal_context * const c = _contexts.first();
|
* in userland anymore.
|
||||||
if (!c) break;
|
*/
|
||||||
Lock::Guard context_guard(c->_lock);
|
Kernel::kill_signal_context(c->_cap.dst());
|
||||||
_unsync_dissolve(c);
|
|
||||||
}
|
/*
|
||||||
|
* Now we can tell core to regain the memory of the
|
||||||
|
* destructed kernel object.
|
||||||
|
*/
|
||||||
|
signal_connection()->free_context(c->_cap);
|
||||||
|
|
||||||
|
/* reset the context */
|
||||||
|
c->_receiver = 0;
|
||||||
|
c->_cap = Signal_context_capability();
|
||||||
|
|
||||||
|
/* forget the context */
|
||||||
|
_contexts.remove(&c->_receiver_le);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -97,17 +157,40 @@ Signal_context_capability Signal_receiver::manage(Signal_context * const c)
|
|||||||
}
|
}
|
||||||
/* assign the context to us */
|
/* assign the context to us */
|
||||||
c->_receiver = this;
|
c->_receiver = this;
|
||||||
_contexts.insert(c);
|
_contexts.insert(&c->_receiver_le);
|
||||||
return c->_cap;
|
return c->_cap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Signal_receiver::dissolve(Signal_context *context)
|
||||||
|
{
|
||||||
|
if (context->_receiver != this)
|
||||||
|
throw Context_not_associated();
|
||||||
|
|
||||||
|
Lock::Guard list_lock_guard(_contexts_lock);
|
||||||
|
|
||||||
|
_unsynchronized_dissolve(context);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We assume that dissolve is always called before the context destructor.
|
||||||
|
* On other platforms a 'context->_destroy_lock' is locked and unlocked at
|
||||||
|
* this point to block until all remaining signals of this context get
|
||||||
|
* destructed and prevent the context from beeing destructed to early.
|
||||||
|
* However on this platform we don't have to wait because
|
||||||
|
* 'kill_signal_context' in '_unsynchronized_dissolve' already does it.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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());
|
Kernel::await_signal(_cap.dst());
|
||||||
Signal s = *(Signal *)Thread_base::myself()->utcb();
|
Signal s(*(Signal::Data *)Thread_base::myself()->utcb());
|
||||||
Signal_context * c = s.context();
|
Signal_context * const c = s.context();
|
||||||
|
|
||||||
/* check if the context of the signal is managed by us */
|
/* check if the context of the signal is managed by us */
|
||||||
Lock::Guard context_guard(c->_lock);
|
Lock::Guard context_guard(c->_lock);
|
||||||
@ -121,28 +204,6 @@ Signal Signal_receiver::wait_for_signal()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Signal_receiver::pending() { return Kernel::signal_pending(_cap.dst()); }
|
void Signal_receiver::local_submit(Signal::Data signal) {
|
||||||
|
PDBG("Not implemented"); };
|
||||||
|
|
||||||
void Signal_receiver::dissolve(Signal_context * const c)
|
|
||||||
{
|
|
||||||
/* check if the context is managed by us */
|
|
||||||
Lock::Guard contexts_guard(_contexts_lock);
|
|
||||||
Lock::Guard context_guard(c->_lock);
|
|
||||||
if (c->_receiver != this) throw Context_not_associated();
|
|
||||||
|
|
||||||
/* unassign the context */
|
|
||||||
_unsync_dissolve(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Signal_receiver::_unsync_dissolve(Signal_context * const c)
|
|
||||||
{
|
|
||||||
/* reset the context */
|
|
||||||
c->_receiver = 0;
|
|
||||||
c->_cap = Signal_context_capability();
|
|
||||||
|
|
||||||
/* forget the context */
|
|
||||||
_contexts.remove(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -61,6 +61,7 @@ namespace Genode
|
|||||||
Signal_context_capability
|
Signal_context_capability
|
||||||
alloc_context(Signal_receiver_capability const r,
|
alloc_context(Signal_receiver_capability const r,
|
||||||
unsigned const imprint);
|
unsigned const imprint);
|
||||||
|
void free_context(Signal_context_capability context_cap);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -487,9 +487,9 @@ void Kernel::Thread::await_signal()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Kernel::Thread::receive_signal(Signal const s)
|
void Kernel::Thread::received_signal()
|
||||||
{
|
{
|
||||||
*(Signal *)phys_utcb()->base() = s;
|
assert(_state == AWAIT_IRQ);
|
||||||
_activate();
|
_activate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -555,24 +555,51 @@ namespace Kernel
|
|||||||
friend class Signal_receiver;
|
friend class Signal_receiver;
|
||||||
|
|
||||||
Signal_receiver * const _receiver; /* the receiver that owns us */
|
Signal_receiver * const _receiver; /* the receiver that owns us */
|
||||||
unsigned const _imprint; /* every of our signals gets signed with */
|
unsigned const _imprint; /* every outgoing signals gets
|
||||||
unsigned _number; /* how often we got triggered */
|
* signed with this */
|
||||||
|
unsigned _submits; /* accumul. undelivered submits */
|
||||||
|
bool _await_ack; /* delivery ack pending */
|
||||||
|
Thread * _killer; /* awaits our destruction if >0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility to deliver all remaining submits
|
||||||
|
*/
|
||||||
|
void _deliver();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
Signal_context(Signal_receiver * const r,
|
Signal_context(Signal_receiver * const r, unsigned const imprint) :
|
||||||
unsigned const imprint)
|
_receiver(r), _imprint(imprint),
|
||||||
: _receiver(r), _imprint(imprint), _number(0) { }
|
_submits(0), _await_ack(0), _killer(0) { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trigger this context
|
* Submit the signal
|
||||||
*
|
*
|
||||||
* \param number how often this call triggers us at once
|
* \param n number of submits
|
||||||
*/
|
*/
|
||||||
void trigger_signal(unsigned const number);
|
void submit(unsigned const n);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Acknowledge delivery of signal
|
||||||
|
*/
|
||||||
|
void ack();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destruct or prepare to do it at next call of 'ack'
|
||||||
|
*/
|
||||||
|
void kill(Thread * const killer)
|
||||||
|
{
|
||||||
|
assert(!_killer);
|
||||||
|
_killer = killer;
|
||||||
|
if (_await_ack) {
|
||||||
|
_killer->kill_signal_context_blocks();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this->~Signal_context();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -602,10 +629,13 @@ namespace Kernel
|
|||||||
}
|
}
|
||||||
/* awake a listener and transmit signal info to it */
|
/* awake a listener and transmit signal info to it */
|
||||||
Thread * const t = _listeners.dequeue();
|
Thread * const t = _listeners.dequeue();
|
||||||
t->receive_signal(Signal(c->_imprint, c->_number));
|
Signal::Data data((Genode::Signal_context *)c->_imprint,
|
||||||
|
c->_submits);
|
||||||
|
*(Signal::Data *)t->phys_utcb()->base() = data;
|
||||||
|
t->received_signal();
|
||||||
|
|
||||||
/* reset context */
|
/* reset context */
|
||||||
c->_number = 0;
|
c->_submits = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -627,12 +657,12 @@ namespace Kernel
|
|||||||
bool pending() { return !_pending_contexts.empty(); }
|
bool pending() { return !_pending_contexts.empty(); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recognize that one of our contexts was triggered
|
* Recognize that 'c' wants to deliver
|
||||||
*/
|
*/
|
||||||
void add_pending_context(Signal_context * const c)
|
void deliver(Signal_context * const c)
|
||||||
{
|
{
|
||||||
assert(c->_receiver == this);
|
assert(c->_receiver == this);
|
||||||
if(!c->is_enqueued()) _pending_contexts.enqueue(c);
|
if (!c->is_enqueued()) _pending_contexts.enqueue(c);
|
||||||
_listen();
|
_listen();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -674,7 +704,7 @@ namespace Kernel
|
|||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
cpu_scheduler()->remove(this);
|
cpu_scheduler()->remove(this);
|
||||||
_context->trigger_signal(1);
|
_context->submit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1193,13 +1223,38 @@ namespace Kernel
|
|||||||
/* lookup context */
|
/* lookup context */
|
||||||
Signal_context * const c =
|
Signal_context * const c =
|
||||||
Signal_context::pool()->object(user->user_arg_1());
|
Signal_context::pool()->object(user->user_arg_1());
|
||||||
assert(c);
|
if(!c) {
|
||||||
|
PDBG("invalid signal-context capability");
|
||||||
|
return;
|
||||||
|
}
|
||||||
/* trigger signal at context */
|
/* trigger signal at context */
|
||||||
c->trigger_signal(user->user_arg_2());
|
c->submit(user->user_arg_2());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do specific syscall for 'user', for details see 'syscall.h'
|
||||||
|
*/
|
||||||
|
void do_ack_signal(Thread * const user)
|
||||||
|
{
|
||||||
|
Signal_context * const c =
|
||||||
|
Signal_context::pool()->object(user->user_arg_1());
|
||||||
|
assert(c);
|
||||||
|
c->ack();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do specific syscall for 'user', for details see 'syscall.h'
|
||||||
|
*/
|
||||||
|
void do_kill_signal_context(Thread * const user)
|
||||||
|
{
|
||||||
|
Signal_context * const c =
|
||||||
|
Signal_context::pool()->object(user->user_arg_1());
|
||||||
|
assert(c);
|
||||||
|
c->kill(user);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Do specific syscall for 'user', for details see 'syscall.h'
|
* Do specific syscall for 'user', for details see 'syscall.h'
|
||||||
*/
|
*/
|
||||||
@ -1283,6 +1338,8 @@ namespace Kernel
|
|||||||
/* 26 */ do_delete_thread,
|
/* 26 */ do_delete_thread,
|
||||||
/* 27 */ do_signal_pending,
|
/* 27 */ do_signal_pending,
|
||||||
/* 28 */ do_resume_faulter,
|
/* 28 */ do_resume_faulter,
|
||||||
|
/* 29 */ do_ack_signal,
|
||||||
|
/* 30 */ do_kill_signal_context,
|
||||||
};
|
};
|
||||||
enum { MAX_SYSCALL = sizeof(handle_sysc)/sizeof(handle_sysc[0]) - 1 };
|
enum { MAX_SYSCALL = sizeof(handle_sysc)/sizeof(handle_sysc[0]) - 1 };
|
||||||
|
|
||||||
@ -1385,8 +1442,7 @@ int Thread::start(void *ip, void *sp, unsigned cpu_no,
|
|||||||
user_arg_0((unsigned)_virt_utcb);
|
user_arg_0((unsigned)_virt_utcb);
|
||||||
|
|
||||||
/* start thread */
|
/* start thread */
|
||||||
cpu_scheduler()->insert(this);
|
_activate();
|
||||||
_state = ACTIVE;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1420,19 +1476,50 @@ void Thread::pagefault(addr_t const va, bool const w)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Thread::kill_signal_context_blocks()
|
||||||
|
{
|
||||||
|
cpu_scheduler()->remove(this);
|
||||||
|
_state = KILL_SIGNAL_CONTEXT_BLOCKS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Thread::kill_signal_context_done()
|
||||||
|
{
|
||||||
|
assert(_state == KILL_SIGNAL_CONTEXT_BLOCKS)
|
||||||
|
_activate();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/****************************
|
/****************************
|
||||||
** Kernel::Signal_context **
|
** Kernel::Signal_context **
|
||||||
****************************/
|
****************************/
|
||||||
|
|
||||||
|
void Signal_context::_deliver()
|
||||||
void Signal_context::trigger_signal(unsigned const number)
|
|
||||||
{
|
{
|
||||||
/* raise our number */
|
if (!_submits) return;
|
||||||
unsigned const old_nr = _number;
|
_receiver->deliver(this);
|
||||||
_number += number;
|
_await_ack = 1;
|
||||||
assert(old_nr <= _number);
|
}
|
||||||
|
|
||||||
/* notify our receiver */
|
|
||||||
if (_number) _receiver->add_pending_context(this);
|
void Signal_context::ack()
|
||||||
|
{
|
||||||
|
_await_ack = 0;
|
||||||
|
if (!_killer) {
|
||||||
|
_deliver();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_killer->kill_signal_context_done();
|
||||||
|
this->~Signal_context();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Signal_context::submit(unsigned const n)
|
||||||
|
{
|
||||||
|
assert(_submits < -1 - n);
|
||||||
|
if (_killer) return;
|
||||||
|
_submits += n;
|
||||||
|
if (_await_ack) return;
|
||||||
|
_deliver();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -775,7 +775,7 @@ namespace Kernel
|
|||||||
public Irq_owner
|
public Irq_owner
|
||||||
{
|
{
|
||||||
enum State { STOPPED, ACTIVE, AWAIT_IPC, AWAIT_RESUMPTION,
|
enum State { STOPPED, ACTIVE, AWAIT_IPC, AWAIT_RESUMPTION,
|
||||||
AWAIT_IRQ, AWAIT_SIGNAL };
|
AWAIT_IRQ, AWAIT_SIGNAL, KILL_SIGNAL_CONTEXT_BLOCKS };
|
||||||
|
|
||||||
Platform_thread * const _platform_thread; /* userland object wich
|
Platform_thread * const _platform_thread; /* userland object wich
|
||||||
* addresses this thread */
|
* addresses this thread */
|
||||||
@ -897,7 +897,7 @@ namespace Kernel
|
|||||||
/**
|
/**
|
||||||
* Gets called when we have received a signal at a signal receiver
|
* Gets called when we have received a signal at a signal receiver
|
||||||
*/
|
*/
|
||||||
void receive_signal(Signal const s);
|
void received_signal();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle the exception that currently blocks this thread
|
* Handle the exception that currently blocks this thread
|
||||||
@ -909,6 +909,9 @@ namespace Kernel
|
|||||||
*/
|
*/
|
||||||
void scheduled_next();
|
void scheduled_next();
|
||||||
|
|
||||||
|
void kill_signal_context_blocks();
|
||||||
|
|
||||||
|
void kill_signal_context_done();
|
||||||
|
|
||||||
/***************
|
/***************
|
||||||
** Accessors **
|
** Accessors **
|
||||||
|
@ -77,3 +77,9 @@ Signal_session_component::alloc_context(Signal_receiver_capability r,
|
|||||||
return reinterpret_cap_cast<Signal_context>(c);
|
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"); }
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user