2011-12-22 16:19:25 +01:00
|
|
|
/*
|
|
|
|
* \brief Generic implementation parts of the signaling framework
|
|
|
|
* \author Norman Feske
|
|
|
|
* \date 2008-09-16
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2013-01-10 21:44:47 +01:00
|
|
|
* Copyright (C) 2008-2013 Genode Labs GmbH
|
2011-12-22 16:19:25 +01:00
|
|
|
*
|
|
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
|
|
* under the terms of the GNU General Public License version 2.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <base/signal.h>
|
|
|
|
#include <base/thread.h>
|
2013-08-13 16:15:52 +02:00
|
|
|
#include <base/trace/events.h>
|
2011-12-22 16:19:25 +01:00
|
|
|
#include <signal_session/connection.h>
|
|
|
|
|
|
|
|
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 **
|
|
|
|
******************************************************/
|
|
|
|
|
2013-02-22 21:37:25 +01:00
|
|
|
enum { STACK_SIZE = 4*1024*sizeof(addr_t) };
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
class Signal_handler_thread : Thread<STACK_SIZE>, Lock
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return process-wide signal source used for signal reception
|
|
|
|
*
|
|
|
|
* This function must be called from the context of the signal handler
|
|
|
|
* thread because on some platforms (e.g., Fiasco.OC), the calling
|
|
|
|
* thread context is used for implementing the signal-source protocol.
|
|
|
|
*/
|
|
|
|
static Signal_source *signal_source();
|
|
|
|
|
|
|
|
void entry()
|
|
|
|
{
|
|
|
|
Signal_source *source = signal_source();
|
|
|
|
unlock();
|
|
|
|
Signal_receiver::dispatch_signals(source);
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor
|
|
|
|
*/
|
|
|
|
Signal_handler_thread()
|
|
|
|
: Thread<STACK_SIZE>("signal handler"), Lock(Lock::LOCKED)
|
|
|
|
{
|
|
|
|
start();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make sure to have initialized the 'signal_source()' channel
|
|
|
|
* before proceeding with the use of signals. Otherwise, signals
|
|
|
|
* that occurred until the construction of 'signal_source' is
|
|
|
|
* completed may get lost.
|
|
|
|
*/
|
|
|
|
lock();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
Signal_source *Signal_handler_thread::signal_source()
|
|
|
|
{
|
|
|
|
static Signal_source_client sigsrc(signal_connection()->signal_source());
|
|
|
|
return &sigsrc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return process-wide signal source used for signal reception
|
|
|
|
*/
|
|
|
|
static Signal_handler_thread *signal_handler_thread()
|
|
|
|
{
|
|
|
|
static Signal_handler_thread signal_handler_thread;
|
|
|
|
return &signal_handler_thread;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-03-21 20:26:02 +01:00
|
|
|
/*****************************
|
|
|
|
** Signal context registry **
|
|
|
|
*****************************/
|
|
|
|
|
|
|
|
namespace Genode {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Facility to validate the liveliness of signal contexts
|
|
|
|
*
|
|
|
|
* After dissolving a 'Signal_context' from a 'Signal_receiver', a signal
|
|
|
|
* belonging to the context may still in flight, i.e., currently processed
|
|
|
|
* within core or the kernel. Hence, after having received a signal, we
|
|
|
|
* need to manually check for the liveliness of the associated context.
|
|
|
|
* Because we cannot trust the signal imprint to represent a valid pointer,
|
|
|
|
* we need an associative data structure to validate the value. That is the
|
|
|
|
* role of the 'Signal_context_registry'.
|
|
|
|
*/
|
|
|
|
class Signal_context_registry
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Currently, the registry is just a linked list. If this becomes a
|
|
|
|
* scalability problem, we might introduce a more sophisticated
|
|
|
|
* associative data structure.
|
|
|
|
*/
|
|
|
|
Lock mutable _lock;
|
|
|
|
List<List_element<Signal_context> > _list;
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
void insert(List_element<Signal_context> *le)
|
|
|
|
{
|
|
|
|
Lock::Guard guard(_lock);
|
|
|
|
_list.insert(le);
|
|
|
|
}
|
|
|
|
|
|
|
|
void remove(List_element<Signal_context> *le)
|
|
|
|
{
|
|
|
|
Lock::Guard guard(_lock);
|
|
|
|
_list.remove(le);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool test_and_lock(Signal_context *context) const
|
|
|
|
{
|
|
|
|
Lock::Guard guard(_lock);
|
|
|
|
|
|
|
|
/* search list for context */
|
2013-09-07 12:54:35 +02:00
|
|
|
List_element<Signal_context> const *le = _list.first();
|
2012-03-21 20:26:02 +01:00
|
|
|
for ( ; le; le = le->next()) {
|
|
|
|
|
|
|
|
if (context == le->object()) {
|
|
|
|
/* lock object */
|
|
|
|
context->_lock.lock();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return process-wide registry of registered signal contexts
|
|
|
|
*/
|
|
|
|
Genode::Signal_context_registry *signal_context_registry()
|
|
|
|
{
|
|
|
|
static Signal_context_registry inst;
|
|
|
|
return &inst;
|
|
|
|
}
|
|
|
|
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2013-01-14 18:24:32 +01:00
|
|
|
/************
|
|
|
|
** 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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-10-18 12:08:44 +02:00
|
|
|
/********************
|
|
|
|
** Signal context **
|
|
|
|
********************/
|
|
|
|
|
|
|
|
void Signal_context::submit(unsigned num)
|
|
|
|
{
|
|
|
|
if (!_receiver) {
|
|
|
|
PWRN("signal context with no receiver");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!signal_context_registry()->test_and_lock(this)) {
|
|
|
|
PWRN("encountered dead signal context");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* construct and locally submit signal object */
|
|
|
|
Signal::Data signal(this, num);
|
|
|
|
_receiver->local_submit(signal);
|
|
|
|
|
|
|
|
/* free context lock that was taken by 'test_and_lock' */
|
|
|
|
_lock.unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-12-22 16:19:25 +01:00
|
|
|
/************************
|
|
|
|
** Signal transmitter **
|
|
|
|
************************/
|
|
|
|
|
2013-01-10 20:56:48 +01:00
|
|
|
void Signal_transmitter::submit(unsigned cnt)
|
2011-12-22 16:19:25 +01:00
|
|
|
{
|
2013-08-13 16:15:52 +02:00
|
|
|
{
|
|
|
|
Trace::Signal_submit trace_event(cnt);
|
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
signal_connection()->submit(_context, cnt);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*********************
|
|
|
|
** 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 */
|
2012-03-21 20:26:02 +01:00
|
|
|
context->_receiver = 0;
|
|
|
|
context->_cap = Signal_context_capability();
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
/* remove context from context list */
|
2012-03-21 20:26:02 +01:00
|
|
|
_contexts.remove(&context->_receiver_le);
|
|
|
|
|
|
|
|
/* unregister context from process-wide registry */
|
|
|
|
signal_context_registry()->remove(&context->_registry_le);
|
2011-12-22 16:19:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Signal_receiver::Signal_receiver()
|
|
|
|
{
|
|
|
|
/* make sure that the process-local signal handler thread is running */
|
|
|
|
signal_handler_thread();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Signal_context_capability Signal_receiver::manage(Signal_context *context)
|
|
|
|
{
|
|
|
|
if (context->_receiver)
|
|
|
|
throw Context_already_in_use();
|
|
|
|
|
|
|
|
context->_receiver = this;
|
|
|
|
|
|
|
|
Lock::Guard list_lock_guard(_contexts_lock);
|
|
|
|
|
|
|
|
/* insert context into context list */
|
2012-03-21 20:26:02 +01:00
|
|
|
_contexts.insert(&context->_receiver_le);
|
|
|
|
|
|
|
|
/* register context at process-wide registry */
|
|
|
|
signal_context_registry()->insert(&context->_registry_le);
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
bool try_again;
|
|
|
|
do {
|
|
|
|
try_again = false;
|
|
|
|
try {
|
|
|
|
|
|
|
|
/* use signal context as imprint */
|
|
|
|
context->_cap = signal_connection()->alloc_context((long)context);
|
|
|
|
return context->_cap;
|
|
|
|
|
|
|
|
} catch (Signal_session::Out_of_metadata) {
|
|
|
|
|
|
|
|
/* give up if the error occurred a second time */
|
|
|
|
if (try_again)
|
|
|
|
break;
|
|
|
|
|
2014-10-02 19:47:36 +02:00
|
|
|
size_t const quota = 1024*sizeof(long);
|
|
|
|
char buf[64];
|
|
|
|
snprintf(buf, sizeof(buf), "ram_quota=%zu", quota);
|
|
|
|
|
|
|
|
PINF("upgrading quota donation for SIGNAL session (%zu bytes)", quota);
|
|
|
|
|
|
|
|
env()->parent()->upgrade(signal_connection()->cap(), buf);
|
2011-12-22 16:19:25 +01:00
|
|
|
try_again = true;
|
|
|
|
}
|
|
|
|
} while (try_again);
|
|
|
|
return Signal_context_capability();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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);
|
2013-01-14 18:24:32 +01:00
|
|
|
|
|
|
|
Lock::Guard context_destroy_lock_guard(context->_destroy_lock);
|
2011-12-22 16:19:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Signal_receiver::pending()
|
|
|
|
{
|
|
|
|
Lock::Guard list_lock_guard(_contexts_lock);
|
|
|
|
|
|
|
|
/* look up the contexts for the pending signal */
|
2012-03-21 20:26:02 +01:00
|
|
|
for (List_element<Signal_context> *le = _contexts.first(); le; le = le->next()) {
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2012-03-21 20:26:02 +01:00
|
|
|
Signal_context *context = le->object();
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
Lock::Guard lock_guard(context->_lock);
|
|
|
|
|
|
|
|
if (context->_pending)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Signal Signal_receiver::wait_for_signal()
|
|
|
|
{
|
|
|
|
for (;;) {
|
|
|
|
|
|
|
|
/* block until the receiver has received a signal */
|
|
|
|
_signal_available.down();
|
|
|
|
|
|
|
|
Lock::Guard list_lock_guard(_contexts_lock);
|
|
|
|
|
|
|
|
/* look up the contexts for the pending signal */
|
2012-03-21 20:26:02 +01:00
|
|
|
for (List_element<Signal_context> *le = _contexts.first(); le; le = le->next()) {
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2012-03-21 20:26:02 +01:00
|
|
|
Signal_context *context = le->object();
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
Lock::Guard lock_guard(context->_lock);
|
|
|
|
|
|
|
|
/* check if context has a pending signal */
|
|
|
|
if (!context->_pending)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
context->_pending = false;
|
2013-01-14 18:24:32 +01:00
|
|
|
Signal::Data result = context->_curr_signal;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
/* invalidate current signal in context */
|
2013-01-14 18:24:32 +01:00
|
|
|
context->_curr_signal = Signal::Data(0, 0);
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2013-01-14 18:24:32 +01:00
|
|
|
if (result.num == 0)
|
2011-12-22 17:20:45 +01:00
|
|
|
PWRN("returning signal with num == 0");
|
|
|
|
|
2013-08-13 16:15:52 +02:00
|
|
|
Trace::Signal_received trace_event(*context, result.num);
|
|
|
|
|
2011-12-22 16:19:25 +01:00
|
|
|
/* 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.
|
2012-03-21 20:26:02 +01:00
|
|
|
*
|
|
|
|
* 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.
|
2011-12-22 16:19:25 +01:00
|
|
|
*/
|
|
|
|
}
|
2013-01-14 18:24:32 +01:00
|
|
|
return Signal::Data(0, 0); /* unreachable */
|
2011-12-22 16:19:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-01-14 18:24:32 +01:00
|
|
|
void Signal_receiver::local_submit(Signal::Data ns)
|
2011-12-22 16:19:25 +01:00
|
|
|
{
|
2013-01-14 18:24:32 +01:00
|
|
|
Signal_context *context = ns.context;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Replace current signal of the context by signal with accumulated
|
|
|
|
* counters. In the common case, the current signal is an invalid
|
|
|
|
* signal with a counter value of zero.
|
|
|
|
*/
|
2013-01-14 18:24:32 +01:00
|
|
|
unsigned num = context->_curr_signal.num + ns.num;
|
|
|
|
context->_curr_signal = Signal::Data(context, num);
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
/* wake up the receiver if the context becomes pending */
|
|
|
|
if (!context->_pending) {
|
|
|
|
context->_pending = true;
|
|
|
|
_signal_available.up();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Signal_receiver::dispatch_signals(Signal_source *signal_source)
|
|
|
|
{
|
|
|
|
for (;;) {
|
|
|
|
Signal_source::Signal source_signal = signal_source->wait_for_signal();
|
|
|
|
|
|
|
|
/* look up context as pointed to by the signal imprint */
|
|
|
|
Signal_context *context = (Signal_context *)(source_signal.imprint());
|
|
|
|
|
2012-03-21 20:26:02 +01:00
|
|
|
if (!signal_context_registry()->test_and_lock(context)) {
|
|
|
|
PWRN("encountered dead signal context");
|
|
|
|
continue;
|
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
/* construct and locally submit signal object */
|
2013-01-14 18:24:32 +01:00
|
|
|
Signal::Data signal(context, source_signal.num());
|
2011-12-22 16:19:25 +01:00
|
|
|
context->_receiver->local_submit(signal);
|
2012-03-21 20:26:02 +01:00
|
|
|
|
|
|
|
/* free context lock that was taken by 'test_and_lock' */
|
|
|
|
context->_lock.unlock();
|
2011-12-22 16:19:25 +01:00
|
|
|
}
|
|
|
|
}
|
2013-09-12 01:25:53 +02:00
|
|
|
|
|
|
|
|
|
|
|
void Signal_receiver::_platform_destructor() { }
|