base-hw: use signal context list for pending signals
'block_for_signal' and 'pending_signal' now set pending flag in signal context in order to determine pending signal. The context list is also used by the 'Signal_receiver' during destruction. Fixes #1738
This commit is contained in:
parent
18d24eec7b
commit
0c3dfbad65
|
@ -37,12 +37,11 @@ namespace Kernel
|
||||||
constexpr Call_arg call_id_kill_signal_context() { return 6; }
|
constexpr Call_arg call_id_kill_signal_context() { return 6; }
|
||||||
constexpr Call_arg call_id_submit_signal() { return 7; }
|
constexpr Call_arg call_id_submit_signal() { return 7; }
|
||||||
constexpr Call_arg call_id_await_signal() { return 8; }
|
constexpr Call_arg call_id_await_signal() { return 8; }
|
||||||
constexpr Call_arg call_id_signal_pending() { return 9; }
|
constexpr Call_arg call_id_ack_signal() { return 9; }
|
||||||
constexpr Call_arg call_id_ack_signal() { return 10; }
|
constexpr Call_arg call_id_print_char() { return 10; }
|
||||||
constexpr Call_arg call_id_print_char() { return 11; }
|
constexpr Call_arg call_id_update_data_region() { return 11; }
|
||||||
constexpr Call_arg call_id_update_data_region() { return 12; }
|
constexpr Call_arg call_id_update_instr_region() { return 12; }
|
||||||
constexpr Call_arg call_id_update_instr_region() { return 13; }
|
constexpr Call_arg call_id_delete_cap() { return 13; }
|
||||||
constexpr Call_arg call_id_delete_cap() { return 14; }
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************
|
/*****************************************************************
|
||||||
|
@ -228,20 +227,6 @@ namespace Kernel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return wether any context of a receiver is pending
|
|
||||||
*
|
|
||||||
* \param receiver capability id 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(capid_t const receiver)
|
|
||||||
{
|
|
||||||
return call(call_id_signal_pending(), receiver);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trigger a specific signal context
|
* Trigger a specific signal context
|
||||||
*
|
*
|
||||||
|
|
|
@ -21,67 +21,16 @@
|
||||||
|
|
||||||
using namespace Genode;
|
using namespace Genode;
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provide one signal connection per program
|
|
||||||
*/
|
|
||||||
static Signal_connection * signal_connection()
|
|
||||||
{
|
|
||||||
static Signal_connection _object;
|
|
||||||
return &_object;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/************
|
|
||||||
** Signal **
|
|
||||||
************/
|
|
||||||
|
|
||||||
void Signal::_dec_ref_and_unlock()
|
|
||||||
{
|
|
||||||
if (_data.context) {
|
|
||||||
Lock::Guard lock_guard(_data.context->_lock);
|
|
||||||
_data.context->_ref_cnt--;
|
|
||||||
|
|
||||||
/* acknowledge as soon as receipt is fully processed */
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
if (_data.context) { _data.context->_ref_cnt = 1; }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/********************
|
/********************
|
||||||
** Signal context **
|
** Signal context **
|
||||||
********************/
|
********************/
|
||||||
|
|
||||||
void Signal_context::submit(unsigned num)
|
void Signal_context::submit(unsigned) { PERR("not implemented"); }
|
||||||
{
|
|
||||||
Kernel::submit_signal(_cap.dst(), num);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/************************
|
/************************
|
||||||
** Signal transmitter **
|
** Signal transmitter **
|
||||||
************************/
|
************************/
|
||||||
|
|
||||||
Signal_connection * Signal_transmitter::connection() { return signal_connection(); }
|
|
||||||
|
|
||||||
|
|
||||||
void Signal_transmitter::submit(unsigned cnt)
|
void Signal_transmitter::submit(unsigned cnt)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
|
@ -127,22 +76,13 @@ void Signal_receiver::_platform_destructor()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Signal_receiver::_unsynchronized_dissolve(Signal_context * const c)
|
void Signal_receiver::_platform_begin_dissolve(Signal_context * const c)
|
||||||
{
|
{
|
||||||
/* wait untill all context references disappear and put context to sleep */
|
|
||||||
Kernel::kill_signal_context(c->_cap.dst());
|
Kernel::kill_signal_context(c->_cap.dst());
|
||||||
|
|
||||||
/* release server resources of context */
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Signal_receiver::_platform_finish_dissolve(Signal_context *) { }
|
||||||
|
|
||||||
|
|
||||||
Signal_context_capability Signal_receiver::manage(Signal_context * const c)
|
Signal_context_capability Signal_receiver::manage(Signal_context * const c)
|
||||||
{
|
{
|
||||||
|
@ -175,76 +115,27 @@ Signal_context_capability Signal_receiver::manage(Signal_context * const c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Signal_receiver::dissolve(Signal_context * const 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()); }
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Last signal received by 'block_for_signal'
|
|
||||||
*/
|
|
||||||
void Signal_receiver::block_for_signal()
|
void Signal_receiver::block_for_signal()
|
||||||
{
|
{
|
||||||
/* await a signal */
|
/* wait for a signal */
|
||||||
if (Kernel::await_signal(_cap.dst())) {
|
if (Kernel::await_signal(_cap.dst())) {
|
||||||
PERR("failed to receive signal");
|
PERR("failed to receive signal");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
/* read signal data */
|
||||||
/* get signal */
|
const void * const utcb = Thread_base::myself()->utcb()->base();
|
||||||
Signal::Data *data = (Signal::Data *)Thread_base::myself()->utcb()->base();
|
Signal::Data * const data = (Signal::Data *)utcb;
|
||||||
Signal s(*data);
|
Signal_context * const context = data->context;
|
||||||
|
{
|
||||||
/* save signal data in context list */
|
/* update signal context */
|
||||||
s.context()->_curr_signal = *data;
|
Lock::Guard lock_guard(context->_lock);
|
||||||
_contexts.insert(&s.context()->_receiver_le);
|
unsigned const num = context->_curr_signal.num + data->num;
|
||||||
}
|
context->_pending = true;
|
||||||
|
context->_curr_signal = Signal::Data(context, num);
|
||||||
|
|
||||||
Signal Signal_receiver::pending_signal()
|
|
||||||
{
|
|
||||||
List_element<Signal_context> *le = _contexts.first();
|
|
||||||
if (!le)
|
|
||||||
throw Signal_not_pending();
|
|
||||||
|
|
||||||
/* remove from context list */
|
|
||||||
Signal_context *context = le->object();
|
|
||||||
_contexts.remove(le);
|
|
||||||
|
|
||||||
return Signal(context->_curr_signal);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Signal Signal_receiver::wait_for_signal()
|
|
||||||
{
|
|
||||||
/* await a signal */
|
|
||||||
if (Kernel::await_signal(_cap.dst())) {
|
|
||||||
PERR("failed to receive signal");
|
|
||||||
return Signal(Signal::Data());
|
|
||||||
}
|
}
|
||||||
|
/* end kernel-aided life-time management */
|
||||||
/* get signal data */
|
Kernel::ack_signal(data->context->_cap.dst());
|
||||||
Signal s(*(Signal::Data *)Thread_base::myself()->utcb()->base());
|
|
||||||
return s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Signal_receiver::local_submit(Signal::Data signal)
|
void Signal_receiver::local_submit(Signal::Data) { PERR("not implemented"); }
|
||||||
{
|
|
||||||
PERR("not implemented");
|
|
||||||
}
|
|
||||||
|
|
|
@ -339,11 +339,6 @@ class Kernel::Signal_receiver : public Kernel::Object
|
||||||
*/
|
*/
|
||||||
int add_handler(Signal_handler * const h);
|
int add_handler(Signal_handler * const h);
|
||||||
|
|
||||||
/**
|
|
||||||
* Return wether any of the contexts of this receiver is deliverable
|
|
||||||
*/
|
|
||||||
bool deliverable();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Syscall to create a signal receiver
|
* Syscall to create a signal receiver
|
||||||
*
|
*
|
||||||
|
|
|
@ -232,7 +232,6 @@ class Kernel::Thread
|
||||||
void _call_update_instr_region();
|
void _call_update_instr_region();
|
||||||
void _call_print_char();
|
void _call_print_char();
|
||||||
void _call_await_signal();
|
void _call_await_signal();
|
||||||
void _call_signal_pending();
|
|
||||||
void _call_submit_signal();
|
void _call_submit_signal();
|
||||||
void _call_ack_signal();
|
void _call_ack_signal();
|
||||||
void _call_kill_signal_context();
|
void _call_kill_signal_context();
|
||||||
|
|
|
@ -223,9 +223,6 @@ int Signal_receiver::add_handler(Signal_handler * const h)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Signal_receiver::deliverable() { return !_deliver.empty(); }
|
|
||||||
|
|
||||||
|
|
||||||
Signal_receiver::~Signal_receiver()
|
Signal_receiver::~Signal_receiver()
|
||||||
{
|
{
|
||||||
/* destruct all attached contexts */
|
/* destruct all attached contexts */
|
||||||
|
|
|
@ -483,21 +483,6 @@ void Thread::_call_await_signal()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Thread::_call_signal_pending()
|
|
||||||
{
|
|
||||||
/* lookup signal receiver */
|
|
||||||
Signal_receiver * const r = pd()->cap_tree().find<Signal_receiver>(user_arg_1());
|
|
||||||
if (!r) {
|
|
||||||
PWRN("%s -> %s: no pending, unknown signal receiver",
|
|
||||||
pd_label(), label());
|
|
||||||
user_arg_0(0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/* get pending state */
|
|
||||||
user_arg_0(r->deliverable());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Thread::_call_submit_signal()
|
void Thread::_call_submit_signal()
|
||||||
{
|
{
|
||||||
/* lookup signal context */
|
/* lookup signal context */
|
||||||
|
@ -625,7 +610,6 @@ void Thread::_call()
|
||||||
case call_id_kill_signal_context(): _call_kill_signal_context(); return;
|
case call_id_kill_signal_context(): _call_kill_signal_context(); return;
|
||||||
case call_id_submit_signal(): _call_submit_signal(); return;
|
case call_id_submit_signal(): _call_submit_signal(); return;
|
||||||
case call_id_await_signal(): _call_await_signal(); return;
|
case call_id_await_signal(): _call_await_signal(); return;
|
||||||
case call_id_signal_pending(): _call_signal_pending(); return;
|
|
||||||
case call_id_ack_signal(): _call_ack_signal(); return;
|
case call_id_ack_signal(): _call_ack_signal(); return;
|
||||||
case call_id_print_char(): _call_print_char(); return;
|
case call_id_print_char(): _call_print_char(); return;
|
||||||
case call_id_delete_cap(): _call_delete_cap(); return;
|
case call_id_delete_cap(): _call_delete_cap(); return;
|
||||||
|
|
|
@ -36,6 +36,7 @@ namespace Genode {
|
||||||
class Signal_dispatcher_base;
|
class Signal_dispatcher_base;
|
||||||
class Signal_connection;
|
class Signal_connection;
|
||||||
template <typename> class Signal_dispatcher;
|
template <typename> class Signal_dispatcher;
|
||||||
|
Signal_connection * signal_connection();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -200,6 +201,12 @@ class Genode::Signal_receiver : Noncopyable
|
||||||
*/
|
*/
|
||||||
void _platform_destructor();
|
void _platform_destructor();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hooks to platform specific dissolve parts
|
||||||
|
*/
|
||||||
|
void _platform_begin_dissolve(Signal_context * const c);
|
||||||
|
void _platform_finish_dissolve(Signal_context * const c);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -15,9 +15,19 @@
|
||||||
|
|
||||||
/* Genode includes */
|
/* Genode includes */
|
||||||
#include <base/signal.h>
|
#include <base/signal.h>
|
||||||
|
#include <signal_session/connection.h>
|
||||||
|
|
||||||
using namespace Genode;
|
using namespace Genode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return process-wide signal session
|
||||||
|
*/
|
||||||
|
Signal_connection * Genode::signal_connection()
|
||||||
|
{
|
||||||
|
static Signal_connection sc;
|
||||||
|
return ≻
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/************
|
/************
|
||||||
** Signal **
|
** Signal **
|
||||||
|
@ -52,6 +62,35 @@ Signal & Signal::operator=(Signal const &other)
|
||||||
Signal::~Signal() { _dec_ref_and_unlock(); }
|
Signal::~Signal() { _dec_ref_and_unlock(); }
|
||||||
|
|
||||||
|
|
||||||
|
void Signal::_dec_ref_and_unlock()
|
||||||
|
{
|
||||||
|
if (_data.context) {
|
||||||
|
Lock::Guard lock_guard(_data.context->_lock);
|
||||||
|
_data.context->_ref_cnt--;
|
||||||
|
if (_data.context->_ref_cnt == 0)
|
||||||
|
_data.context->_destroy_lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
if (_data.context) {
|
||||||
|
_data.context->_ref_cnt = 1;
|
||||||
|
_data.context->_destroy_lock.lock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/********************
|
/********************
|
||||||
** Signal_context **
|
** Signal_context **
|
||||||
********************/
|
********************/
|
||||||
|
@ -71,6 +110,9 @@ Signal_context::~Signal_context()
|
||||||
** Signal_transmitter **
|
** Signal_transmitter **
|
||||||
************************/
|
************************/
|
||||||
|
|
||||||
|
Signal_connection * Signal_transmitter::connection() { return signal_connection(); }
|
||||||
|
|
||||||
|
|
||||||
Signal_transmitter::Signal_transmitter(Signal_context_capability context)
|
Signal_transmitter::Signal_transmitter(Signal_context_capability context)
|
||||||
: _context(context) { }
|
: _context(context) { }
|
||||||
|
|
||||||
|
@ -85,6 +127,63 @@ Signal_context_capability Signal_transmitter::context() { return _context; }
|
||||||
** Signal_receiver **
|
** Signal_receiver **
|
||||||
*********************/
|
*********************/
|
||||||
|
|
||||||
|
Signal Signal_receiver::wait_for_signal()
|
||||||
|
{
|
||||||
|
for (;;) {
|
||||||
|
|
||||||
|
/* block until the receiver has received a signal */
|
||||||
|
block_for_signal();
|
||||||
|
|
||||||
|
try {
|
||||||
|
return pending_signal();
|
||||||
|
} catch (Signal_not_pending) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Signal Signal_receiver::pending_signal()
|
||||||
|
{
|
||||||
|
Lock::Guard list_lock_guard(_contexts_lock);
|
||||||
|
|
||||||
|
/* look up the contexts for the pending signal */
|
||||||
|
for (List_element<Signal_context> *le = _contexts.first(); le; le = le->next()) {
|
||||||
|
|
||||||
|
Signal_context *context = le->object();
|
||||||
|
|
||||||
|
Lock::Guard lock_guard(context->_lock);
|
||||||
|
|
||||||
|
/* check if context has a pending signal */
|
||||||
|
if (!context->_pending)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
context->_pending = false;
|
||||||
|
Signal::Data result = context->_curr_signal;
|
||||||
|
|
||||||
|
/* invalidate current signal in context */
|
||||||
|
context->_curr_signal = Signal::Data(0, 0);
|
||||||
|
|
||||||
|
if (result.num == 0)
|
||||||
|
PWRN("returning signal with num == 0");
|
||||||
|
|
||||||
|
Trace::Signal_received trace_event(*context, result.num);
|
||||||
|
|
||||||
|
/* return last received signal */
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Normally, we should never arrive at this point because that would
|
||||||
|
* mean, the '_signal_available' semaphore was increased without
|
||||||
|
* registering the signal in any context associated to the receiver.
|
||||||
|
*
|
||||||
|
* However, if a context gets dissolved right after submitting a
|
||||||
|
* signal, we may have increased the semaphore already. In this case
|
||||||
|
* the signal-causing context is absent from the list.
|
||||||
|
*/
|
||||||
|
throw Signal_not_pending();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Signal_receiver::~Signal_receiver()
|
Signal_receiver::~Signal_receiver()
|
||||||
{
|
{
|
||||||
Lock::Guard list_lock_guard(_contexts_lock);
|
Lock::Guard list_lock_guard(_contexts_lock);
|
||||||
|
@ -95,3 +194,53 @@ Signal_receiver::~Signal_receiver()
|
||||||
|
|
||||||
_platform_destructor();
|
_platform_destructor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Signal_receiver::_unsynchronized_dissolve(Signal_context * const context)
|
||||||
|
{
|
||||||
|
_platform_begin_dissolve(context);
|
||||||
|
|
||||||
|
/* tell core to stop sending signals referring to the context */
|
||||||
|
signal_connection()->free_context(context->_cap);
|
||||||
|
|
||||||
|
/* restore default initialization of signal context */
|
||||||
|
context->_receiver = 0;
|
||||||
|
context->_cap = Signal_context_capability();
|
||||||
|
|
||||||
|
/* remove context from context list */
|
||||||
|
_contexts.remove(&context->_receiver_le);
|
||||||
|
|
||||||
|
_platform_finish_dissolve(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
Lock::Guard context_destroy_lock_guard(context->_destroy_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool Signal_receiver::pending()
|
||||||
|
{
|
||||||
|
Lock::Guard list_lock_guard(_contexts_lock);
|
||||||
|
|
||||||
|
/* look up the contexts for the pending signal */
|
||||||
|
for (List_element<Signal_context> *le = _contexts.first(); le; le = le->next()) {
|
||||||
|
|
||||||
|
Signal_context *context = le->object();
|
||||||
|
|
||||||
|
Lock::Guard lock_guard(context->_lock);
|
||||||
|
|
||||||
|
if (context->_pending)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
|
@ -18,21 +18,6 @@
|
||||||
|
|
||||||
using namespace Genode;
|
using namespace Genode;
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return process-wide signal session used for signal allocation and submission
|
|
||||||
*/
|
|
||||||
static Signal_connection *signal_connection()
|
|
||||||
{
|
|
||||||
static Signal_connection sc;
|
|
||||||
return ≻
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/******************************************************
|
|
||||||
** Process-wide connection to core's signal service **
|
|
||||||
******************************************************/
|
|
||||||
|
|
||||||
enum { STACK_SIZE = 4*1024*sizeof(addr_t) };
|
enum { STACK_SIZE = 4*1024*sizeof(addr_t) };
|
||||||
|
|
||||||
class Signal_handler_thread : Thread<STACK_SIZE>, Lock
|
class Signal_handler_thread : Thread<STACK_SIZE>, Lock
|
||||||
|
@ -166,39 +151,6 @@ Genode::Signal_context_registry *signal_context_registry()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/************
|
|
||||||
** Signal **
|
|
||||||
************/
|
|
||||||
|
|
||||||
void Signal::_dec_ref_and_unlock()
|
|
||||||
{
|
|
||||||
if (_data.context) {
|
|
||||||
Lock::Guard lock_guard(_data.context->_lock);
|
|
||||||
_data.context->_ref_cnt--;
|
|
||||||
if (_data.context->_ref_cnt == 0)
|
|
||||||
_data.context->_destroy_lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
if (_data.context) {
|
|
||||||
_data.context->_ref_cnt = 1;
|
|
||||||
_data.context->_destroy_lock.lock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/********************
|
/********************
|
||||||
** Signal context **
|
** Signal context **
|
||||||
********************/
|
********************/
|
||||||
|
@ -224,33 +176,10 @@ void Signal_context::submit(unsigned num)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/************************
|
|
||||||
** Signal transmitter **
|
|
||||||
************************/
|
|
||||||
|
|
||||||
Signal_connection * Signal_transmitter::connection() { return signal_connection(); }
|
|
||||||
|
|
||||||
|
|
||||||
/*********************
|
/*********************
|
||||||
** Signal receiver **
|
** Signal receiver **
|
||||||
*********************/
|
*********************/
|
||||||
|
|
||||||
void Signal_receiver::_unsynchronized_dissolve(Signal_context *context)
|
|
||||||
{
|
|
||||||
/* tell core to stop sending signals referring to the context */
|
|
||||||
signal_connection()->free_context(context->_cap);
|
|
||||||
|
|
||||||
/* restore default initialization of signal context */
|
|
||||||
context->_receiver = 0;
|
|
||||||
context->_cap = Signal_context_capability();
|
|
||||||
|
|
||||||
/* remove context from context list */
|
|
||||||
_contexts.remove(&context->_receiver_le);
|
|
||||||
|
|
||||||
/* unregister context from process-wide registry */
|
|
||||||
signal_context_registry()->remove(&context->_registry_le);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Signal_receiver::Signal_receiver()
|
Signal_receiver::Signal_receiver()
|
||||||
{
|
{
|
||||||
|
@ -301,100 +230,12 @@ Signal_context_capability Signal_receiver::manage(Signal_context *context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
Lock::Guard context_destroy_lock_guard(context->_destroy_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool Signal_receiver::pending()
|
|
||||||
{
|
|
||||||
Lock::Guard list_lock_guard(_contexts_lock);
|
|
||||||
|
|
||||||
/* look up the contexts for the pending signal */
|
|
||||||
for (List_element<Signal_context> *le = _contexts.first(); le; le = le->next()) {
|
|
||||||
|
|
||||||
Signal_context *context = le->object();
|
|
||||||
|
|
||||||
Lock::Guard lock_guard(context->_lock);
|
|
||||||
|
|
||||||
if (context->_pending)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Signal Signal_receiver::pending_signal()
|
|
||||||
{
|
|
||||||
Lock::Guard list_lock_guard(_contexts_lock);
|
|
||||||
|
|
||||||
/* look up the contexts for the pending signal */
|
|
||||||
for (List_element<Signal_context> *le = _contexts.first(); le; le = le->next()) {
|
|
||||||
|
|
||||||
Signal_context *context = le->object();
|
|
||||||
|
|
||||||
Lock::Guard lock_guard(context->_lock);
|
|
||||||
|
|
||||||
/* check if context has a pending signal */
|
|
||||||
if (!context->_pending)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
context->_pending = false;
|
|
||||||
Signal::Data result = context->_curr_signal;
|
|
||||||
|
|
||||||
/* invalidate current signal in context */
|
|
||||||
context->_curr_signal = Signal::Data(0, 0);
|
|
||||||
|
|
||||||
if (result.num == 0)
|
|
||||||
PWRN("returning signal with num == 0");
|
|
||||||
|
|
||||||
Trace::Signal_received trace_event(*context, result.num);
|
|
||||||
|
|
||||||
/* return last received signal */
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Normally, we should never arrive at this point because that would
|
|
||||||
* mean, the '_signal_available' semaphore was increased without
|
|
||||||
* registering the signal in any context associated to the receiver.
|
|
||||||
*
|
|
||||||
* However, if a context gets dissolved right after submitting a
|
|
||||||
* signal, we may have increased the semaphore already. In this case
|
|
||||||
* the signal-causing context is absent from the list.
|
|
||||||
*/
|
|
||||||
throw Signal_not_pending();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Signal_receiver::block_for_signal()
|
void Signal_receiver::block_for_signal()
|
||||||
{
|
{
|
||||||
_signal_available.down();
|
_signal_available.down();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Signal Signal_receiver::wait_for_signal()
|
|
||||||
{
|
|
||||||
for (;;) {
|
|
||||||
|
|
||||||
/* block until the receiver has received a signal */
|
|
||||||
block_for_signal();
|
|
||||||
|
|
||||||
try {
|
|
||||||
return pending_signal();
|
|
||||||
} catch (Signal_not_pending) { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Signal_receiver::local_submit(Signal::Data ns)
|
void Signal_receiver::local_submit(Signal::Data ns)
|
||||||
{
|
{
|
||||||
Signal_context *context = ns.context;
|
Signal_context *context = ns.context;
|
||||||
|
@ -437,5 +278,9 @@ void Signal_receiver::dispatch_signals(Signal_source *signal_source)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Signal_receiver::_platform_begin_dissolve(Signal_context *) { }
|
||||||
|
|
||||||
|
void Signal_receiver::_platform_finish_dissolve(Signal_context * const c) {
|
||||||
|
signal_context_registry()->remove(&c->_registry_le); }
|
||||||
|
|
||||||
void Signal_receiver::_platform_destructor() { }
|
void Signal_receiver::_platform_destructor() { }
|
||||||
|
|
Loading…
Reference in New Issue
Block a user