genode/repos/base/src/base/signal/common.cc
Norman Feske b1910cdd54 Integrate SIGNAL session into PD session
This patch removes the SIGNAL service from core and moves its
functionality to the PD session. Furthermore, it unifies the PD service
implementation and terminology across the various base platforms.

Issue #1841
2016-03-07 12:34:44 +01:00

236 lines
4.9 KiB
C++

/*
* \brief Platform-independent part of signal framework
* \author Norman Feske
* \author Christian Prochaska
* \author Martin Stein
* \date 2013-02-21
*/
/*
* Copyright (C) 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.
*/
/* Genode includes */
#include <base/env.h>
#include <base/signal.h>
#include <base/trace/events.h>
using namespace Genode;
/************
** Signal **
************/
Signal::Signal(Signal const &other)
{
_data.context = other._data.context;
_data.num = other._data.num;
_inc_ref();
}
Signal & Signal::operator=(Signal const &other)
{
if ((_data.context == other._data.context) &&
(_data.num == other._data.num))
return *this;
_dec_ref_and_unlock();
_data.context = other._data.context;
_data.num = other._data.num;
_inc_ref();
return *this;
}
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::~Signal_context()
{
/*
* Detect bug in an application where a signal context is destroyed prior
* dissolving it from the signal receiver.
*/
if (_receiver)
PERR("Destructing undissolved signal context");
}
/************************
** Signal_transmitter **
************************/
Signal_transmitter::Signal_transmitter(Signal_context_capability context)
: _context(context) { }
void Signal_transmitter::context(Signal_context_capability context) {
_context = context; }
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);
/* disassociate contexts from the receiver */
for (List_element<Signal_context> *le; (le = _contexts.first()); )
_unsynchronized_dissolve(le->object());
_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 */
env()->pd_session()->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;
}