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:
Sebastian Sumpf 2015-11-13 15:49:11 +01:00 committed by Christian Helmuth
parent 18d24eec7b
commit 0c3dfbad65
9 changed files with 183 additions and 331 deletions

View File

@ -37,12 +37,11 @@ namespace Kernel
constexpr Call_arg call_id_kill_signal_context() { return 6; }
constexpr Call_arg call_id_submit_signal() { return 7; }
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 10; }
constexpr Call_arg call_id_print_char() { return 11; }
constexpr Call_arg call_id_update_data_region() { return 12; }
constexpr Call_arg call_id_update_instr_region() { return 13; }
constexpr Call_arg call_id_delete_cap() { return 14; }
constexpr Call_arg call_id_ack_signal() { return 9; }
constexpr Call_arg call_id_print_char() { return 10; }
constexpr Call_arg call_id_update_data_region() { return 11; }
constexpr Call_arg call_id_update_instr_region() { return 12; }
constexpr Call_arg call_id_delete_cap() { return 13; }
/*****************************************************************
@ -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
*

View File

@ -21,67 +21,16 @@
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 **
********************/
void Signal_context::submit(unsigned num)
{
Kernel::submit_signal(_cap.dst(), num);
}
void Signal_context::submit(unsigned) { PERR("not implemented"); }
/************************
** Signal transmitter **
************************/
Signal_connection * Signal_transmitter::connection() { return signal_connection(); }
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());
/* 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)
{
@ -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()
{
/* await a signal */
/* wait for a signal */
if (Kernel::await_signal(_cap.dst())) {
PERR("failed to receive signal");
return;
}
/* get signal */
Signal::Data *data = (Signal::Data *)Thread_base::myself()->utcb()->base();
Signal s(*data);
/* save signal data in context list */
s.context()->_curr_signal = *data;
_contexts.insert(&s.context()->_receiver_le);
}
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());
/* read signal data */
const void * const utcb = Thread_base::myself()->utcb()->base();
Signal::Data * const data = (Signal::Data *)utcb;
Signal_context * const context = data->context;
{
/* update signal context */
Lock::Guard lock_guard(context->_lock);
unsigned const num = context->_curr_signal.num + data->num;
context->_pending = true;
context->_curr_signal = Signal::Data(context, num);
}
/* get signal data */
Signal s(*(Signal::Data *)Thread_base::myself()->utcb()->base());
return s;
/* end kernel-aided life-time management */
Kernel::ack_signal(data->context->_cap.dst());
}
void Signal_receiver::local_submit(Signal::Data signal)
{
PERR("not implemented");
}
void Signal_receiver::local_submit(Signal::Data) { PERR("not implemented"); }

View File

@ -339,11 +339,6 @@ class Kernel::Signal_receiver : public Kernel::Object
*/
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
*

View File

@ -232,7 +232,6 @@ class Kernel::Thread
void _call_update_instr_region();
void _call_print_char();
void _call_await_signal();
void _call_signal_pending();
void _call_submit_signal();
void _call_ack_signal();
void _call_kill_signal_context();

View File

@ -223,9 +223,6 @@ int Signal_receiver::add_handler(Signal_handler * const h)
}
bool Signal_receiver::deliverable() { return !_deliver.empty(); }
Signal_receiver::~Signal_receiver()
{
/* destruct all attached contexts */

View File

@ -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()
{
/* lookup signal context */
@ -625,7 +610,6 @@ void Thread::_call()
case call_id_kill_signal_context(): _call_kill_signal_context(); return;
case call_id_submit_signal(): _call_submit_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_print_char(): _call_print_char(); return;
case call_id_delete_cap(): _call_delete_cap(); return;

View File

@ -36,6 +36,7 @@ namespace Genode {
class Signal_dispatcher_base;
class Signal_connection;
template <typename> class Signal_dispatcher;
Signal_connection * signal_connection();
}
@ -200,6 +201,12 @@ class Genode::Signal_receiver : Noncopyable
*/
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:
/**

View File

@ -15,9 +15,19 @@
/* Genode includes */
#include <base/signal.h>
#include <signal_session/connection.h>
using namespace Genode;
/**
* Return process-wide signal session
*/
Signal_connection * Genode::signal_connection()
{
static Signal_connection sc;
return &sc;
}
/************
** Signal **
@ -52,6 +62,35 @@ Signal & Signal::operator=(Signal const &other)
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 **
********************/
@ -71,6 +110,9 @@ Signal_context::~Signal_context()
** Signal_transmitter **
************************/
Signal_connection * Signal_transmitter::connection() { return signal_connection(); }
Signal_transmitter::Signal_transmitter(Signal_context_capability context)
: _context(context) { }
@ -85,6 +127,63 @@ Signal_context_capability Signal_transmitter::context() { return _context; }
** 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()
{
Lock::Guard list_lock_guard(_contexts_lock);
@ -95,3 +194,53 @@ Signal_receiver::~Signal_receiver()
_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;
}

View File

@ -18,21 +18,6 @@
using namespace Genode;
/**
* Return process-wide signal session used for signal allocation and submission
*/
static Signal_connection *signal_connection()
{
static Signal_connection sc;
return &sc;
}
/******************************************************
** Process-wide connection to core's signal service **
******************************************************/
enum { STACK_SIZE = 4*1024*sizeof(addr_t) };
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 **
********************/
@ -224,33 +176,10 @@ void Signal_context::submit(unsigned num)
}
/************************
** Signal transmitter **
************************/
Signal_connection * Signal_transmitter::connection() { return signal_connection(); }
/*********************
** 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()
{
@ -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()
{
_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)
{
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() { }