genode/repos/base/src/lib/base/signal.cc

348 lines
8.7 KiB
C++
Raw Normal View History

2011-12-22 16:19:25 +01:00
/*
* \brief Generic implementation parts of the signaling framework
* \author Norman Feske
* \date 2008-09-16
*/
/*
* Copyright (C) 2008-2017 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 Affero General Public License version 3.
2011-12-22 16:19:25 +01:00
*/
/* Genode includes */
#include <util/retry.h>
#include <base/env.h>
2011-12-22 16:19:25 +01:00
#include <base/signal.h>
#include <base/thread.h>
#include <base/sleep.h>
2013-08-13 16:15:52 +02:00
#include <base/trace/events.h>
#include <util/reconstructible.h>
#include <deprecated/env.h>
2011-12-22 16:19:25 +01:00
/* base-internal includes */
#include <base/internal/globals.h>
#include <base/internal/unmanaged_singleton.h>
#include <signal_source/client.h>
2011-12-22 16:19:25 +01:00
using namespace Genode;
2011-12-22 16:19:25 +01:00
2020-02-19 16:26:40 +01:00
class Signal_handler_thread : Thread, Blockade
2011-12-22 16:19:25 +01:00
{
private:
/**
* Actual signal source
2011-12-22 16:19:25 +01:00
*
* Member must be constructed in the context of the signal handler
2011-12-22 16:19:25 +01:00
* thread because on some platforms (e.g., Fiasco.OC), the calling
* thread context is used for implementing the signal-source protocol.
*/
Follow practices suggested by "Effective C++" The patch adjust the code of the base, base-<kernel>, and os repository. To adapt existing components to fix violations of the best practices suggested by "Effective C++" as reported by the -Weffc++ compiler argument. The changes follow the patterns outlined below: * A class with virtual functions can no longer publicly inherit base classed without a vtable. The inherited object may either be moved to a member variable, or inherited privately. The latter would be used for classes that inherit 'List::Element' or 'Avl_node'. In order to enable the 'List' and 'Avl_tree' to access the meta data, the 'List' must become a friend. * Instead of adding a virtual destructor to abstract base classes, we inherit the new 'Interface' class, which contains a virtual destructor. This way, single-line abstract base classes can stay as compact as they are now. The 'Interface' utility resides in base/include/util/interface.h. * With the new warnings enabled, all member variables must be explicitly initialized. Basic types may be initialized with '='. All other types are initialized with braces '{ ... }' or as class initializers. If basic types and non-basic types appear in a row, it is nice to only use the brace syntax (also for basic types) and align the braces. * If a class contains pointers as members, it must now also provide a copy constructor and assignment operator. In the most cases, one would make them private, effectively disallowing the objects to be copied. Unfortunately, this warning cannot be fixed be inheriting our existing 'Noncopyable' class (the compiler fails to detect that the inheriting class cannot be copied and still gives the error). For now, we have to manually add declarations for both the copy constructor and assignment operator as private class members. Those declarations should be prepended with a comment like this: /* * Noncopyable */ Thread(Thread const &); Thread &operator = (Thread const &); In the future, we should revisit these places and try to replace the pointers with references. In the presence of at least one reference member, the compiler would no longer implicitly generate a copy constructor. So we could remove the manual declaration. Issue #465
2017-12-21 15:42:15 +01:00
Constructible<Signal_source_client> _signal_source { };
2011-12-22 16:19:25 +01:00
void entry() override
2011-12-22 16:19:25 +01:00
{
_signal_source.construct(env_deprecated()->pd_session()->alloc_signal_source());
2020-02-19 16:26:40 +01:00
wakeup();
Signal_receiver::dispatch_signals(&(*_signal_source));
2011-12-22 16:19:25 +01:00
}
enum { STACK_SIZE = 4*1024*sizeof(addr_t) };
2011-12-22 16:19:25 +01:00
public:
/**
* Constructor
*/
Signal_handler_thread(Env &env)
2020-02-19 16:26:40 +01:00
: Thread(env, "signal handler", STACK_SIZE)
2011-12-22 16:19:25 +01:00
{
start();
/*
* Make sure the signal source was constructed before proceeding
* with the use of signals. Otherwise, signals may get lost until
* the construction finished.
2011-12-22 16:19:25 +01:00
*/
2020-02-19 16:26:40 +01:00
block();
2011-12-22 16:19:25 +01:00
}
~Signal_handler_thread()
{
Follow practices suggested by "Effective C++" The patch adjust the code of the base, base-<kernel>, and os repository. To adapt existing components to fix violations of the best practices suggested by "Effective C++" as reported by the -Weffc++ compiler argument. The changes follow the patterns outlined below: * A class with virtual functions can no longer publicly inherit base classed without a vtable. The inherited object may either be moved to a member variable, or inherited privately. The latter would be used for classes that inherit 'List::Element' or 'Avl_node'. In order to enable the 'List' and 'Avl_tree' to access the meta data, the 'List' must become a friend. * Instead of adding a virtual destructor to abstract base classes, we inherit the new 'Interface' class, which contains a virtual destructor. This way, single-line abstract base classes can stay as compact as they are now. The 'Interface' utility resides in base/include/util/interface.h. * With the new warnings enabled, all member variables must be explicitly initialized. Basic types may be initialized with '='. All other types are initialized with braces '{ ... }' or as class initializers. If basic types and non-basic types appear in a row, it is nice to only use the brace syntax (also for basic types) and align the braces. * If a class contains pointers as members, it must now also provide a copy constructor and assignment operator. In the most cases, one would make them private, effectively disallowing the objects to be copied. Unfortunately, this warning cannot be fixed be inheriting our existing 'Noncopyable' class (the compiler fails to detect that the inheriting class cannot be copied and still gives the error). For now, we have to manually add declarations for both the copy constructor and assignment operator as private class members. Those declarations should be prepended with a comment like this: /* * Noncopyable */ Thread(Thread const &); Thread &operator = (Thread const &); In the future, we should revisit these places and try to replace the pointers with references. In the presence of at least one reference member, the compiler would no longer implicitly generate a copy constructor. So we could remove the manual declaration. Issue #465
2017-12-21 15:42:15 +01:00
env_deprecated()->pd_session()->free_signal_source(_signal_source->rpc_cap());
}
2011-12-22 16:19:25 +01:00
};
/*
* The signal-handler thread will be constructed before global constructors are
* called and, consequently, must not be a global static object. Otherwise, the
* 'Constructible' constructor will be executed twice.
*/
static Constructible<Signal_handler_thread> & signal_handler_thread()
2011-12-22 16:19:25 +01:00
{
return *unmanaged_singleton<Constructible<Signal_handler_thread> >();
2011-12-22 16:19:25 +01:00
}
namespace Genode {
/*
* Initialize the component-local signal-handling thread
*
* This function is called once at the startup of the component. It must
* be called before creating the first signal receiver.
*
* We allow this function to be overridden in to enable core to omit the
* creation of the signal thread.
*/
void init_signal_thread(Env &env) __attribute__((weak));
void init_signal_thread(Env &env)
{
signal_handler_thread().construct(env);
}
void destroy_signal_thread()
{
signal_handler_thread().destruct();
}
2011-12-22 16:19:25 +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.
*/
2020-02-19 16:26:40 +01:00
Mutex mutable _mutex { };
Follow practices suggested by "Effective C++" The patch adjust the code of the base, base-<kernel>, and os repository. To adapt existing components to fix violations of the best practices suggested by "Effective C++" as reported by the -Weffc++ compiler argument. The changes follow the patterns outlined below: * A class with virtual functions can no longer publicly inherit base classed without a vtable. The inherited object may either be moved to a member variable, or inherited privately. The latter would be used for classes that inherit 'List::Element' or 'Avl_node'. In order to enable the 'List' and 'Avl_tree' to access the meta data, the 'List' must become a friend. * Instead of adding a virtual destructor to abstract base classes, we inherit the new 'Interface' class, which contains a virtual destructor. This way, single-line abstract base classes can stay as compact as they are now. The 'Interface' utility resides in base/include/util/interface.h. * With the new warnings enabled, all member variables must be explicitly initialized. Basic types may be initialized with '='. All other types are initialized with braces '{ ... }' or as class initializers. If basic types and non-basic types appear in a row, it is nice to only use the brace syntax (also for basic types) and align the braces. * If a class contains pointers as members, it must now also provide a copy constructor and assignment operator. In the most cases, one would make them private, effectively disallowing the objects to be copied. Unfortunately, this warning cannot be fixed be inheriting our existing 'Noncopyable' class (the compiler fails to detect that the inheriting class cannot be copied and still gives the error). For now, we have to manually add declarations for both the copy constructor and assignment operator as private class members. Those declarations should be prepended with a comment like this: /* * Noncopyable */ Thread(Thread const &); Thread &operator = (Thread const &); In the future, we should revisit these places and try to replace the pointers with references. In the presence of at least one reference member, the compiler would no longer implicitly generate a copy constructor. So we could remove the manual declaration. Issue #465
2017-12-21 15:42:15 +01:00
List<List_element<Signal_context> > _list { };
public:
void insert(List_element<Signal_context> *le)
{
2020-02-19 16:26:40 +01:00
Mutex::Guard guard(_mutex);
_list.insert(le);
}
void remove(List_element<Signal_context> *le)
{
2020-02-19 16:26:40 +01:00
Mutex::Guard guard(_mutex);
_list.remove(le);
}
bool test_and_lock(Signal_context *context) const
{
2020-02-19 16:26:40 +01:00
Mutex::Guard guard(_mutex);
/* search list for context */
List_element<Signal_context> const *le = _list.first();
for ( ; le; le = le->next()) {
if (context == le->object()) {
2020-02-19 16:26:40 +01:00
/* acquire the object */
context->_mutex.acquire();
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
/*********************
** Signal receiver **
*********************/
Signal_receiver::Signal_receiver() { }
2011-12-22 16:19:25 +01:00
Signal_context_capability Signal_receiver::manage(Signal_context *context)
{
if (context->_receiver)
throw Context_already_in_use();
context->_receiver = this;
2020-02-19 16:26:40 +01:00
Mutex::Guard contexts_guard(_contexts_mutex);
2011-12-22 16:19:25 +01:00
/* insert context into context list */
_contexts.insert_as_tail(context);
/* register context at process-wide registry */
signal_context_registry()->insert(&context->_registry_le);
2011-12-22 16:19:25 +01:00
Capability quota accounting and trading This patch mirrors the accounting and trading scheme that Genode employs for physical memory to the accounting of capability allocations. Capability quotas must now be explicitly assigned to subsystems by specifying a 'caps=<amount>' attribute to init's start nodes. Analogously to RAM quotas, cap quotas can be traded between clients and servers as part of the session protocol. The capability budget of each component is maintained by the component's corresponding PD session at core. At the current stage, the accounting is applied to RPC capabilities, signal-context capabilities, and dataspace capabilities. Capabilities that are dynamically allocated via core's CPU and TRACE service are not yet covered. Also, the capabilities allocated by resource multiplexers outside of core (like nitpicker) must be accounted by the respective servers, which is not covered yet. If a component runs out of capabilities, core's PD service prints a warning to the log. To observe the consumption of capabilities per component in detail, the PD service is equipped with a diagnostic mode, which can be enabled via the 'diag' attribute in the target node of init's routing rules. E.g., the following route enables the diagnostic mode for the PD session of the "timer" component: <default-route> <service name="PD" unscoped_label="timer"> <parent diag="yes"/> </service> ... </default-route> For subsystems based on a sub-init instance, init can be configured to report the capability-quota information of its subsystems by adding the attribute 'child_caps="yes"' to init's '<report>' config node. Init's own capability quota can be reported by adding the attribute 'init_caps="yes"'. Fixes #2398
2017-05-08 21:35:43 +02:00
for (;;) {
Ram_quota ram_upgrade { 0 };
Cap_quota cap_upgrade { 0 };
try {
2011-12-22 16:19:25 +01:00
/* use signal context as imprint */
context->_cap = env_deprecated()->pd_session()->alloc_context(_cap, (long)context);
Capability quota accounting and trading This patch mirrors the accounting and trading scheme that Genode employs for physical memory to the accounting of capability allocations. Capability quotas must now be explicitly assigned to subsystems by specifying a 'caps=<amount>' attribute to init's start nodes. Analogously to RAM quotas, cap quotas can be traded between clients and servers as part of the session protocol. The capability budget of each component is maintained by the component's corresponding PD session at core. At the current stage, the accounting is applied to RPC capabilities, signal-context capabilities, and dataspace capabilities. Capabilities that are dynamically allocated via core's CPU and TRACE service are not yet covered. Also, the capabilities allocated by resource multiplexers outside of core (like nitpicker) must be accounted by the respective servers, which is not covered yet. If a component runs out of capabilities, core's PD service prints a warning to the log. To observe the consumption of capabilities per component in detail, the PD service is equipped with a diagnostic mode, which can be enabled via the 'diag' attribute in the target node of init's routing rules. E.g., the following route enables the diagnostic mode for the PD session of the "timer" component: <default-route> <service name="PD" unscoped_label="timer"> <parent diag="yes"/> </service> ... </default-route> For subsystems based on a sub-init instance, init can be configured to report the capability-quota information of its subsystems by adding the attribute 'child_caps="yes"' to init's '<report>' config node. Init's own capability quota can be reported by adding the attribute 'init_caps="yes"'. Fixes #2398
2017-05-08 21:35:43 +02:00
break;
}
catch (Out_of_ram) { ram_upgrade = Ram_quota { 1024*sizeof(long) }; }
catch (Out_of_caps) { cap_upgrade = Cap_quota { 4 }; }
Capability quota accounting and trading This patch mirrors the accounting and trading scheme that Genode employs for physical memory to the accounting of capability allocations. Capability quotas must now be explicitly assigned to subsystems by specifying a 'caps=<amount>' attribute to init's start nodes. Analogously to RAM quotas, cap quotas can be traded between clients and servers as part of the session protocol. The capability budget of each component is maintained by the component's corresponding PD session at core. At the current stage, the accounting is applied to RPC capabilities, signal-context capabilities, and dataspace capabilities. Capabilities that are dynamically allocated via core's CPU and TRACE service are not yet covered. Also, the capabilities allocated by resource multiplexers outside of core (like nitpicker) must be accounted by the respective servers, which is not covered yet. If a component runs out of capabilities, core's PD service prints a warning to the log. To observe the consumption of capabilities per component in detail, the PD service is equipped with a diagnostic mode, which can be enabled via the 'diag' attribute in the target node of init's routing rules. E.g., the following route enables the diagnostic mode for the PD session of the "timer" component: <default-route> <service name="PD" unscoped_label="timer"> <parent diag="yes"/> </service> ... </default-route> For subsystems based on a sub-init instance, init can be configured to report the capability-quota information of its subsystems by adding the attribute 'child_caps="yes"' to init's '<report>' config node. Init's own capability quota can be reported by adding the attribute 'init_caps="yes"'. Fixes #2398
2017-05-08 21:35:43 +02:00
log("upgrading quota donation for PD session "
"(", ram_upgrade, " bytes, ", cap_upgrade, " caps)");
Capability quota accounting and trading This patch mirrors the accounting and trading scheme that Genode employs for physical memory to the accounting of capability allocations. Capability quotas must now be explicitly assigned to subsystems by specifying a 'caps=<amount>' attribute to init's start nodes. Analogously to RAM quotas, cap quotas can be traded between clients and servers as part of the session protocol. The capability budget of each component is maintained by the component's corresponding PD session at core. At the current stage, the accounting is applied to RPC capabilities, signal-context capabilities, and dataspace capabilities. Capabilities that are dynamically allocated via core's CPU and TRACE service are not yet covered. Also, the capabilities allocated by resource multiplexers outside of core (like nitpicker) must be accounted by the respective servers, which is not covered yet. If a component runs out of capabilities, core's PD service prints a warning to the log. To observe the consumption of capabilities per component in detail, the PD service is equipped with a diagnostic mode, which can be enabled via the 'diag' attribute in the target node of init's routing rules. E.g., the following route enables the diagnostic mode for the PD session of the "timer" component: <default-route> <service name="PD" unscoped_label="timer"> <parent diag="yes"/> </service> ... </default-route> For subsystems based on a sub-init instance, init can be configured to report the capability-quota information of its subsystems by adding the attribute 'child_caps="yes"' to init's '<report>' config node. Init's own capability quota can be reported by adding the attribute 'init_caps="yes"'. Fixes #2398
2017-05-08 21:35:43 +02:00
env_deprecated()->parent()->upgrade(Parent::Env::pd(),
String<100>("ram_quota=", ram_upgrade, ", "
"cap_quota=", cap_upgrade).string());
}
return context->_cap;
2011-12-22 16:19:25 +01:00
}
void Signal_receiver::block_for_signal()
{
_signal_available.down();
}
Signal Signal_receiver::pending_signal()
{
2020-02-19 16:26:40 +01:00
Mutex::Guard contexts_guard(_contexts_mutex);
Signal::Data result;
_contexts.for_each_locked([&] (Signal_context &context) {
if (!context._pending) return;
_contexts.head(context._next);
context._pending = false;
result = context._curr_signal;
context._curr_signal = Signal::Data(0, 0);
Trace::Signal_received trace_event(context, result.num);
throw Context_ring::Break_for_each();
});
if (result.context) {
2020-02-19 16:26:40 +01:00
Mutex::Guard context_guard(result.context->_mutex);
if (result.num == 0)
warning("returning signal with num == 0");
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::unblock_signal_waiter(Rpc_entrypoint &)
{
_signal_available.up();
}
void Signal_receiver::local_submit(Signal::Data ns)
2011-12-22 16:19:25 +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.
*/
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());
if (!context) {
error("received null signal imprint, stop signal dispatcher");
sleep_forever();
}
if (!signal_context_registry()->test_and_lock(context)) {
warning("encountered dead signal context ", context, " in signal dispatcher");
continue;
}
2011-12-22 16:19:25 +01:00
if (context->_receiver) {
/* construct and locally submit signal object */
Signal::Data signal(context, source_signal.num());
context->_receiver->local_submit(signal);
} else {
warning("signal context ", context, " with no receiver in signal dispatcher");
}
2020-02-19 16:26:40 +01:00
/* free context mutex that was taken by 'test_and_lock' */
context->_mutex.release();
2011-12-22 16:19:25 +01:00
}
}
void Signal_receiver::_platform_begin_dissolve(Signal_context *context)
{
/*
2020-02-19 16:26:40 +01:00
* Because the 'remove' operation takes the registry mutex, the context
* must not be acquired when calling this method. See the comment in
* 'Signal_receiver::dissolve'.
*/
signal_context_registry()->remove(&context->_registry_le);
}
void Signal_receiver::_platform_finish_dissolve(Signal_context *) { }
void Signal_receiver::_platform_destructor() { }