genode/repos/base/src/lib/base-common/child.cc

953 lines
28 KiB
C++
Raw Normal View History

/*
* \brief Child creation framework
* \author Norman Feske
* \date 2006-07-22
*/
/*
* Copyright (C) 2006-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* Genode includes */
#include <base/child.h>
#include <base/quota_transfer.h>
/* base-internal includes */
#include <base/internal/child_policy.h>
using namespace Genode;
/***********
** Child **
***********/
template <typename SESSION>
static Service &parent_service()
{
static Parent_service service(SESSION::service_name());
return service;
}
void Child::yield(Resource_args const &args)
{
Lock::Guard guard(_yield_request_lock);
/* buffer yield request arguments to be picked up by the child */
_yield_request_args = args;
/* notify the child about the yield request */
if (_yield_sigh.valid())
Signal_transmitter(_yield_sigh).submit();
}
void Child::notify_resource_avail() const
{
if (_resource_avail_sigh.valid())
Signal_transmitter(_resource_avail_sigh).submit();
}
void Child::announce(Parent::Service_name const &name)
{
if (!name.valid_string()) return;
_policy.announce_service(name.string());
}
void Child::session_sigh(Signal_context_capability sigh)
{
_session_sigh = sigh;
if (!_session_sigh.valid())
return;
/*
* Deliver pending session response if a session became available before
* the signal handler got installed. This can happen for the very first
* asynchronously created session of a component. In 'component.cc', the
* signal handler is registered as response of the session request that
* needs asynchronous handling.
*/
_id_space.for_each<Session_state const>([&] (Session_state const &session) {
base: remove Child::heap This patch improves the accounting for the backing store of session-state meta data. Originally, the session state used to be allocated by a child-local heap partition fed from the child's RAM session. However, whereas this approach was somehow practical from a runtime's (parent's) point of view, the child component could not count on the quota in its own RAM session. I.e., if the Child::heap grew at the parent side, the child's RAM session would magically diminish. This caused two problems. First, it violates assumptions of components like init that carefully manage their RAM resources (and giving most of them away their children). Second, if a child transfers most of its RAM session quota to another RAM session (like init does), the child's RAM session may actually not allow the parent's heap to grow, which is a very difficult error condition to deal with. In the new version, there is no Child::heap anymore. Instead, session states are allocated from the runtime's RAM session. In order to let children pay for these costs, the parent withdraws the local session costs from the session quota donated from the child when the child initiates a new session. Hence, in principle, all components on the route of the session request take a small bite from the session quota to pay for their local book keeping Consequently, the session quota that ends up at the server may become depleted more or less, depending on the route. In the case where the remaining quota is insufficient for the server, the server responds with 'QUOTA_EXCEEDED'. Since this behavior must generally be expected, this patch equips the client-side 'Env::session' implementation with the ability to re-issue session requests with successively growing quota donations. For several of core's services (ROM, IO_MEM, IRQ), the default session quota has now increased by 2 KiB, which should suffice for session requests to up to 3 hops as is the common case for most run scripts. For longer routes, the retry mechanism as described above comes into effect. For the time being, we give a warning whenever the server-side quota check triggers the retry mechanism. The warning may eventually be removed at a later stage.
2017-02-19 10:31:50 +01:00
if (session.phase == Session_state::AVAILABLE ||
session.phase == Session_state::INSUFFICIENT_RAM_QUOTA ||
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
session.phase == Session_state::INSUFFICIENT_CAP_QUOTA ||
session.phase == Session_state::SERVICE_DENIED) {
base: remove Child::heap This patch improves the accounting for the backing store of session-state meta data. Originally, the session state used to be allocated by a child-local heap partition fed from the child's RAM session. However, whereas this approach was somehow practical from a runtime's (parent's) point of view, the child component could not count on the quota in its own RAM session. I.e., if the Child::heap grew at the parent side, the child's RAM session would magically diminish. This caused two problems. First, it violates assumptions of components like init that carefully manage their RAM resources (and giving most of them away their children). Second, if a child transfers most of its RAM session quota to another RAM session (like init does), the child's RAM session may actually not allow the parent's heap to grow, which is a very difficult error condition to deal with. In the new version, there is no Child::heap anymore. Instead, session states are allocated from the runtime's RAM session. In order to let children pay for these costs, the parent withdraws the local session costs from the session quota donated from the child when the child initiates a new session. Hence, in principle, all components on the route of the session request take a small bite from the session quota to pay for their local book keeping Consequently, the session quota that ends up at the server may become depleted more or less, depending on the route. In the case where the remaining quota is insufficient for the server, the server responds with 'QUOTA_EXCEEDED'. Since this behavior must generally be expected, this patch equips the client-side 'Env::session' implementation with the ability to re-issue session requests with successively growing quota donations. For several of core's services (ROM, IO_MEM, IRQ), the default session quota has now increased by 2 KiB, which should suffice for session requests to up to 3 hops as is the common case for most run scripts. For longer routes, the retry mechanism as described above comes into effect. For the time being, we give a warning whenever the server-side quota check triggers the retry mechanism. The warning may eventually be removed at a later stage.
2017-02-19 10:31:50 +01:00
if (sigh.valid() && session.async_client_notify)
Signal_transmitter(sigh).submit();
}
});
}
/**
* Create session-state object for a dynamically created session
*
* \throw Out_of_ram
* \throw Out_of_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
* \throw Insufficient_cap_quota
* \throw Insufficient_ram_quota
* \throw Service_denied
*/
Session_state &
create_session(Child_policy::Name const &child_name, Service &service,
Session_label const &label,
Session_state::Factory &factory, Id_space<Parent::Client> &id_space,
Parent::Client::Id id, Session_state::Args const &args,
Affinity const &affinity)
{
try {
return service.create_session(factory, id_space, id, label, args, affinity); }
catch (Insufficient_ram_quota) {
error(child_name, " requested session with insufficient RAM quota");
throw; }
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
catch (Insufficient_cap_quota) {
error(child_name, " requested session with insufficient cap quota");
throw; }
catch (Allocator::Out_of_memory) {
error(child_name, " session meta data could not be allocated");
throw Out_of_ram(); }
catch (Id_space<Parent::Client>::Conflicting_id) {
error(child_name, " requested conflicting session ID ", id, " "
"(service=", service.name(), " args=", args, ")");
try {
id_space.apply<Session_state>(id, [&] (Session_state &session) {
error("existing session: ", session); });
}
catch (Id_space<Parent::Client>::Unknown_id) { }
}
throw Service_denied();
}
Session_capability Child::session(Parent::Client::Id id,
Parent::Service_name const &name,
Parent::Session_args const &args,
Affinity const &affinity)
{
if (!name.valid_string() || !args.valid_string() || _pd.closed())
throw Service_denied();
char argbuf[Parent::Session_args::MAX_SIZE];
strncpy(argbuf, args.string(), sizeof(argbuf));
/* prefix session label */
base/os: remove deprecated APIs This commit removes APIs that were previously marked as deprecated. This change has the following implications: - The use of the global 'env()' accessor is not possible anymore. - Boolean accessor methods are no longer prefixed with 'is_'. E.g., instead of 'is_valid()', use 'valid()'. - The last traces of 'Ram_session' are gone now. The 'Env::ram()' accessor returns the 'Ram_allocator' interface, which is a subset of the 'Pd_session' interface. - All connection constructors need the 'Env' as argument. - The 'Reporter' constructor needs an 'Env' argument now because the reporter creates a report connection. - The old overload 'Child_policy::resolve_session_request' that returned a 'Service' does not exist anymore. - The base/printf.h header has been removed, use base/log.h instead. - The old notion of 'Signal_dispatcher' is gone. Use 'Signal_handler'. - Transitional headers like os/server.h, cap_session/, volatile_object.h, os/attached*_dataspace.h, signal_rpc_dispatcher.h have been removed. - The distinction between 'Thread_state' and 'Thread_state_base' does not exist anymore. - The header cpu_thread/capability.h along with the type definition of 'Cpu_thread_capability' has been removed. Use the type 'Thread_capability' define in cpu_session/cpu_session.h instead. - Several XML utilities (i.e., at os/include/decorator) could be removed because their functionality is nowadays covered by util/xml_node.h. - The 'os/ram_session_guard.h' has been removed. Use 'Constrained_ram_allocator' provided by base/ram_allocator.h instead. Issue #1987
2019-01-30 17:27:46 +01:00
Session_label const label = prefixed_label(_policy.name(), label_from_args(argbuf));
Arg_string::set_arg_string(argbuf, sizeof(argbuf), "label", label.string());
/* filter session arguments according to the child policy */
_policy.filter_session_args(name.string(), argbuf, sizeof(argbuf));
/* filter session affinity */
Affinity const filtered_affinity = _policy.filter_session_affinity(affinity);
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
Cap_quota const cap_quota = cap_quota_from_args(argbuf);
Ram_quota const ram_quota = ram_quota_from_args(argbuf);
base: remove Child::heap This patch improves the accounting for the backing store of session-state meta data. Originally, the session state used to be allocated by a child-local heap partition fed from the child's RAM session. However, whereas this approach was somehow practical from a runtime's (parent's) point of view, the child component could not count on the quota in its own RAM session. I.e., if the Child::heap grew at the parent side, the child's RAM session would magically diminish. This caused two problems. First, it violates assumptions of components like init that carefully manage their RAM resources (and giving most of them away their children). Second, if a child transfers most of its RAM session quota to another RAM session (like init does), the child's RAM session may actually not allow the parent's heap to grow, which is a very difficult error condition to deal with. In the new version, there is no Child::heap anymore. Instead, session states are allocated from the runtime's RAM session. In order to let children pay for these costs, the parent withdraws the local session costs from the session quota donated from the child when the child initiates a new session. Hence, in principle, all components on the route of the session request take a small bite from the session quota to pay for their local book keeping Consequently, the session quota that ends up at the server may become depleted more or less, depending on the route. In the case where the remaining quota is insufficient for the server, the server responds with 'QUOTA_EXCEEDED'. Since this behavior must generally be expected, this patch equips the client-side 'Env::session' implementation with the ability to re-issue session requests with successively growing quota donations. For several of core's services (ROM, IO_MEM, IRQ), the default session quota has now increased by 2 KiB, which should suffice for session requests to up to 3 hops as is the common case for most run scripts. For longer routes, the retry mechanism as described above comes into effect. For the time being, we give a warning whenever the server-side quota check triggers the retry mechanism. The warning may eventually be removed at a later stage.
2017-02-19 10:31:50 +01:00
/* portion of quota to keep for ourself to maintain the session meta data */
size_t const keep_ram_quota = _session_factory.session_costs();
if (ram_quota.value < keep_ram_quota)
throw Insufficient_ram_quota();
base: remove Child::heap This patch improves the accounting for the backing store of session-state meta data. Originally, the session state used to be allocated by a child-local heap partition fed from the child's RAM session. However, whereas this approach was somehow practical from a runtime's (parent's) point of view, the child component could not count on the quota in its own RAM session. I.e., if the Child::heap grew at the parent side, the child's RAM session would magically diminish. This caused two problems. First, it violates assumptions of components like init that carefully manage their RAM resources (and giving most of them away their children). Second, if a child transfers most of its RAM session quota to another RAM session (like init does), the child's RAM session may actually not allow the parent's heap to grow, which is a very difficult error condition to deal with. In the new version, there is no Child::heap anymore. Instead, session states are allocated from the runtime's RAM session. In order to let children pay for these costs, the parent withdraws the local session costs from the session quota donated from the child when the child initiates a new session. Hence, in principle, all components on the route of the session request take a small bite from the session quota to pay for their local book keeping Consequently, the session quota that ends up at the server may become depleted more or less, depending on the route. In the case where the remaining quota is insufficient for the server, the server responds with 'QUOTA_EXCEEDED'. Since this behavior must generally be expected, this patch equips the client-side 'Env::session' implementation with the ability to re-issue session requests with successively growing quota donations. For several of core's services (ROM, IO_MEM, IRQ), the default session quota has now increased by 2 KiB, which should suffice for session requests to up to 3 hops as is the common case for most run scripts. For longer routes, the retry mechanism as described above comes into effect. For the time being, we give a warning whenever the server-side quota check triggers the retry mechanism. The warning may eventually be removed at a later stage.
2017-02-19 10:31:50 +01:00
/* ram quota to be forwarded to the server */
Ram_quota const forward_ram_quota { ram_quota.value - keep_ram_quota };
base: remove Child::heap This patch improves the accounting for the backing store of session-state meta data. Originally, the session state used to be allocated by a child-local heap partition fed from the child's RAM session. However, whereas this approach was somehow practical from a runtime's (parent's) point of view, the child component could not count on the quota in its own RAM session. I.e., if the Child::heap grew at the parent side, the child's RAM session would magically diminish. This caused two problems. First, it violates assumptions of components like init that carefully manage their RAM resources (and giving most of them away their children). Second, if a child transfers most of its RAM session quota to another RAM session (like init does), the child's RAM session may actually not allow the parent's heap to grow, which is a very difficult error condition to deal with. In the new version, there is no Child::heap anymore. Instead, session states are allocated from the runtime's RAM session. In order to let children pay for these costs, the parent withdraws the local session costs from the session quota donated from the child when the child initiates a new session. Hence, in principle, all components on the route of the session request take a small bite from the session quota to pay for their local book keeping Consequently, the session quota that ends up at the server may become depleted more or less, depending on the route. In the case where the remaining quota is insufficient for the server, the server responds with 'QUOTA_EXCEEDED'. Since this behavior must generally be expected, this patch equips the client-side 'Env::session' implementation with the ability to re-issue session requests with successively growing quota donations. For several of core's services (ROM, IO_MEM, IRQ), the default session quota has now increased by 2 KiB, which should suffice for session requests to up to 3 hops as is the common case for most run scripts. For longer routes, the retry mechanism as described above comes into effect. For the time being, we give a warning whenever the server-side quota check triggers the retry mechanism. The warning may eventually be removed at a later stage.
2017-02-19 10:31:50 +01:00
/* adjust the session information as presented to the server */
Arg_string::set_arg(argbuf, sizeof(argbuf), "ram_quota", forward_ram_quota.value);
base: remove Child::heap This patch improves the accounting for the backing store of session-state meta data. Originally, the session state used to be allocated by a child-local heap partition fed from the child's RAM session. However, whereas this approach was somehow practical from a runtime's (parent's) point of view, the child component could not count on the quota in its own RAM session. I.e., if the Child::heap grew at the parent side, the child's RAM session would magically diminish. This caused two problems. First, it violates assumptions of components like init that carefully manage their RAM resources (and giving most of them away their children). Second, if a child transfers most of its RAM session quota to another RAM session (like init does), the child's RAM session may actually not allow the parent's heap to grow, which is a very difficult error condition to deal with. In the new version, there is no Child::heap anymore. Instead, session states are allocated from the runtime's RAM session. In order to let children pay for these costs, the parent withdraws the local session costs from the session quota donated from the child when the child initiates a new session. Hence, in principle, all components on the route of the session request take a small bite from the session quota to pay for their local book keeping Consequently, the session quota that ends up at the server may become depleted more or less, depending on the route. In the case where the remaining quota is insufficient for the server, the server responds with 'QUOTA_EXCEEDED'. Since this behavior must generally be expected, this patch equips the client-side 'Env::session' implementation with the ability to re-issue session requests with successively growing quota donations. For several of core's services (ROM, IO_MEM, IRQ), the default session quota has now increased by 2 KiB, which should suffice for session requests to up to 3 hops as is the common case for most run scripts. For longer routes, the retry mechanism as described above comes into effect. For the time being, we give a warning whenever the server-side quota check triggers the retry mechanism. The warning may eventually be removed at a later stage.
2017-02-19 10:31:50 +01:00
/* may throw a 'Service_denied' exception */
base/os: remove deprecated APIs This commit removes APIs that were previously marked as deprecated. This change has the following implications: - The use of the global 'env()' accessor is not possible anymore. - Boolean accessor methods are no longer prefixed with 'is_'. E.g., instead of 'is_valid()', use 'valid()'. - The last traces of 'Ram_session' are gone now. The 'Env::ram()' accessor returns the 'Ram_allocator' interface, which is a subset of the 'Pd_session' interface. - All connection constructors need the 'Env' as argument. - The 'Reporter' constructor needs an 'Env' argument now because the reporter creates a report connection. - The old overload 'Child_policy::resolve_session_request' that returned a 'Service' does not exist anymore. - The base/printf.h header has been removed, use base/log.h instead. - The old notion of 'Signal_dispatcher' is gone. Use 'Signal_handler'. - Transitional headers like os/server.h, cap_session/, volatile_object.h, os/attached*_dataspace.h, signal_rpc_dispatcher.h have been removed. - The distinction between 'Thread_state' and 'Thread_state_base' does not exist anymore. - The header cpu_thread/capability.h along with the type definition of 'Cpu_thread_capability' has been removed. Use the type 'Thread_capability' define in cpu_session/cpu_session.h instead. - Several XML utilities (i.e., at os/include/decorator) could be removed because their functionality is nowadays covered by util/xml_node.h. - The 'os/ram_session_guard.h' has been removed. Use 'Constrained_ram_allocator' provided by base/ram_allocator.h instead. Issue #1987
2019-01-30 17:27:46 +01:00
Child_policy::Route route = _policy.resolve_session_request(name.string(), label);
Service &service = route.service;
/* propagate diag flag */
Arg_string::set_arg(argbuf, sizeof(argbuf), "diag", route.diag.enabled);
Session_state &session =
create_session(_policy.name(), service, route.label,
_session_factory, _id_space, id, argbuf, filtered_affinity);
_policy.session_state_changed();
session.ready_callback = this;
session.closed_callback = this;
try {
Ram_transfer::Remote_account ref_ram_account { _policy.ref_pd(), _policy.ref_pd_cap() };
Cap_transfer::Remote_account ref_cap_account { _policy.ref_pd(), _policy.ref_pd_cap() };
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
Ram_transfer::Remote_account ram_account { pd(), pd_session_cap() };
Cap_transfer::Remote_account cap_account { pd(), pd_session_cap() };
base: remove Child::heap This patch improves the accounting for the backing store of session-state meta data. Originally, the session state used to be allocated by a child-local heap partition fed from the child's RAM session. However, whereas this approach was somehow practical from a runtime's (parent's) point of view, the child component could not count on the quota in its own RAM session. I.e., if the Child::heap grew at the parent side, the child's RAM session would magically diminish. This caused two problems. First, it violates assumptions of components like init that carefully manage their RAM resources (and giving most of them away their children). Second, if a child transfers most of its RAM session quota to another RAM session (like init does), the child's RAM session may actually not allow the parent's heap to grow, which is a very difficult error condition to deal with. In the new version, there is no Child::heap anymore. Instead, session states are allocated from the runtime's RAM session. In order to let children pay for these costs, the parent withdraws the local session costs from the session quota donated from the child when the child initiates a new session. Hence, in principle, all components on the route of the session request take a small bite from the session quota to pay for their local book keeping Consequently, the session quota that ends up at the server may become depleted more or less, depending on the route. In the case where the remaining quota is insufficient for the server, the server responds with 'QUOTA_EXCEEDED'. Since this behavior must generally be expected, this patch equips the client-side 'Env::session' implementation with the ability to re-issue session requests with successively growing quota donations. For several of core's services (ROM, IO_MEM, IRQ), the default session quota has now increased by 2 KiB, which should suffice for session requests to up to 3 hops as is the common case for most run scripts. For longer routes, the retry mechanism as described above comes into effect. For the time being, we give a warning whenever the server-side quota check triggers the retry mechanism. The warning may eventually be removed at a later stage.
2017-02-19 10:31:50 +01:00
/* transfer the quota donation from the child's account to ourself */
Ram_transfer ram_donation_from_child(ram_quota, ram_account, ref_ram_account);
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
Cap_transfer cap_donation_from_child(cap_quota, cap_account, ref_cap_account);
/* transfer session quota from ourself to the service provider */
Ram_transfer ram_donation_to_service(forward_ram_quota, ref_ram_account, service);
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
Cap_transfer cap_donation_to_service(cap_quota, ref_cap_account, service);
/* finish transaction */
ram_donation_from_child.acknowledge();
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
cap_donation_from_child.acknowledge();
ram_donation_to_service.acknowledge();
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
cap_donation_to_service.acknowledge();
}
/*
* Release session meta data if one of the quota transfers went wrong.
*/
catch (Ram_transfer::Quota_exceeded) {
session.destroy();
throw Out_of_ram();
}
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
catch (Cap_transfer::Quota_exceeded) {
session.destroy();
throw Out_of_caps();
}
/* try to dispatch session request synchronously */
service.initiate_request(session);
if (session.phase == Session_state::SERVICE_DENIED) {
_revert_quota_and_destroy(session);
throw Service_denied();
}
if (session.phase == Session_state::INSUFFICIENT_RAM_QUOTA) {
_revert_quota_and_destroy(session);
throw Insufficient_ram_quota();
}
if (session.phase == Session_state::INSUFFICIENT_CAP_QUOTA) {
_revert_quota_and_destroy(session);
throw Insufficient_cap_quota();
}
/*
* Copy out the session cap before we are potentially kicking off the
* asynchonous request handling at the server to avoid doule-read
* issues with the session.cap, which will be asynchronously assigned
* by the server side.
*/
Session_capability cap = session.cap;
/* if request was not handled synchronously, kick off async operation */
if (session.phase == Session_state::CREATE_REQUESTED)
service.wakeup();
if (cap.valid())
session.phase = Session_state::CAP_HANDED_OUT;
return cap;
}
Session_capability Child::session_cap(Client::Id id)
{
Session_capability cap;
auto lamda = [&] (Session_state &session) {
if (session.phase == Session_state::SERVICE_DENIED
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
|| session.phase == Session_state::INSUFFICIENT_RAM_QUOTA
|| session.phase == Session_state::INSUFFICIENT_CAP_QUOTA) {
base: remove Child::heap This patch improves the accounting for the backing store of session-state meta data. Originally, the session state used to be allocated by a child-local heap partition fed from the child's RAM session. However, whereas this approach was somehow practical from a runtime's (parent's) point of view, the child component could not count on the quota in its own RAM session. I.e., if the Child::heap grew at the parent side, the child's RAM session would magically diminish. This caused two problems. First, it violates assumptions of components like init that carefully manage their RAM resources (and giving most of them away their children). Second, if a child transfers most of its RAM session quota to another RAM session (like init does), the child's RAM session may actually not allow the parent's heap to grow, which is a very difficult error condition to deal with. In the new version, there is no Child::heap anymore. Instead, session states are allocated from the runtime's RAM session. In order to let children pay for these costs, the parent withdraws the local session costs from the session quota donated from the child when the child initiates a new session. Hence, in principle, all components on the route of the session request take a small bite from the session quota to pay for their local book keeping Consequently, the session quota that ends up at the server may become depleted more or less, depending on the route. In the case where the remaining quota is insufficient for the server, the server responds with 'QUOTA_EXCEEDED'. Since this behavior must generally be expected, this patch equips the client-side 'Env::session' implementation with the ability to re-issue session requests with successively growing quota donations. For several of core's services (ROM, IO_MEM, IRQ), the default session quota has now increased by 2 KiB, which should suffice for session requests to up to 3 hops as is the common case for most run scripts. For longer routes, the retry mechanism as described above comes into effect. For the time being, we give a warning whenever the server-side quota check triggers the retry mechanism. The warning may eventually be removed at a later stage.
2017-02-19 10:31:50 +01:00
Session_state::Phase const phase = session.phase;
/*
* Implicity discard the session request when delivering an
* exception because the exception will trigger the deallocation
* of the session ID at the child anyway.
*/
_revert_quota_and_destroy(session);
base: remove Child::heap This patch improves the accounting for the backing store of session-state meta data. Originally, the session state used to be allocated by a child-local heap partition fed from the child's RAM session. However, whereas this approach was somehow practical from a runtime's (parent's) point of view, the child component could not count on the quota in its own RAM session. I.e., if the Child::heap grew at the parent side, the child's RAM session would magically diminish. This caused two problems. First, it violates assumptions of components like init that carefully manage their RAM resources (and giving most of them away their children). Second, if a child transfers most of its RAM session quota to another RAM session (like init does), the child's RAM session may actually not allow the parent's heap to grow, which is a very difficult error condition to deal with. In the new version, there is no Child::heap anymore. Instead, session states are allocated from the runtime's RAM session. In order to let children pay for these costs, the parent withdraws the local session costs from the session quota donated from the child when the child initiates a new session. Hence, in principle, all components on the route of the session request take a small bite from the session quota to pay for their local book keeping Consequently, the session quota that ends up at the server may become depleted more or less, depending on the route. In the case where the remaining quota is insufficient for the server, the server responds with 'QUOTA_EXCEEDED'. Since this behavior must generally be expected, this patch equips the client-side 'Env::session' implementation with the ability to re-issue session requests with successively growing quota donations. For several of core's services (ROM, IO_MEM, IRQ), the default session quota has now increased by 2 KiB, which should suffice for session requests to up to 3 hops as is the common case for most run scripts. For longer routes, the retry mechanism as described above comes into effect. For the time being, we give a warning whenever the server-side quota check triggers the retry mechanism. The warning may eventually be removed at a later stage.
2017-02-19 10:31:50 +01:00
switch (phase) {
case Session_state::SERVICE_DENIED: throw Service_denied();
case Session_state::INSUFFICIENT_RAM_QUOTA: throw Insufficient_ram_quota();
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
case Session_state::INSUFFICIENT_CAP_QUOTA: throw Insufficient_cap_quota();
default: break;
}
}
if (!session.alive())
warning(_policy.name(), ": attempt to request cap for unavailable session: ", session);
if (session.cap.valid())
session.phase = Session_state::CAP_HANDED_OUT;
cap = session.cap;
};
try {
_id_space.apply<Session_state>(id, lamda); }
catch (Id_space<Parent::Client>::Unknown_id) {
warning(_policy.name(), " requested session cap for unknown ID"); }
_policy.session_state_changed();
return cap;
}
Parent::Upgrade_result Child::upgrade(Client::Id id, Parent::Upgrade_args const &args)
{
if (!args.valid_string()) {
warning("no valid session-upgrade arguments");
return UPGRADE_DONE;
}
/* ignore suprious request that may arrive after 'close_all_sessions' */
if (_pd.closed())
return UPGRADE_PENDING;
Upgrade_result result = UPGRADE_PENDING;
auto upgrade_session = [&] (Session_state &session) {
if (session.phase != Session_state::CAP_HANDED_OUT) {
warning("attempt to upgrade session in invalid state");
return;
}
Ram_quota const ram_quota {
Arg_string::find_arg(args.string(), "ram_quota").ulong_value(0) };
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
Cap_quota const cap_quota {
Arg_string::find_arg(args.string(), "cap_quota").ulong_value(0) };
try {
Ram_transfer::Remote_account ref_ram_account { _policy.ref_pd(), _policy.ref_pd_cap() };
Cap_transfer::Remote_account ref_cap_account { _policy.ref_pd(), _policy.ref_pd_cap() };
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
Ram_transfer::Remote_account ram_account { pd(), pd_session_cap() };
Cap_transfer::Remote_account cap_account { pd(), pd_session_cap() };
/* transfer quota from client to ourself */
Ram_transfer ram_donation_from_child(ram_quota, ram_account, ref_ram_account);
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
Cap_transfer cap_donation_from_child(cap_quota, cap_account, ref_cap_account);
/* transfer session quota from ourself to the service provider */
Ram_transfer ram_donation_to_service(ram_quota, ref_ram_account, session.service());
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
Cap_transfer cap_donation_to_service(cap_quota, ref_cap_account, session.service());
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
session.increase_donated_quota(ram_quota, cap_quota);
session.phase = Session_state::UPGRADE_REQUESTED;
session.service().initiate_request(session);
/* finish transaction */
ram_donation_from_child.acknowledge();
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
cap_donation_from_child.acknowledge();
ram_donation_to_service.acknowledge();
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
cap_donation_to_service.acknowledge();
}
catch (Ram_transfer::Quota_exceeded) {
warning(_policy.name(), ": RAM upgrade of ", session.service().name(), " failed");
throw Out_of_ram();
}
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
catch (Cap_transfer::Quota_exceeded) {
warning(_policy.name(), ": cap upgrade of ", session.service().name(), " failed");
throw Out_of_caps();
}
if (session.phase == Session_state::CAP_HANDED_OUT) {
result = UPGRADE_DONE;
_policy.session_state_changed();
return;
}
session.service().wakeup();
};
try { _id_space.apply<Session_state>(id, upgrade_session); }
catch (Id_space<Parent::Client>::Unknown_id) { }
_policy.session_state_changed();
return result;
}
void Child::_revert_quota_and_destroy(Session_state &session)
{
Ram_transfer::Remote_account ref_ram_account(_policy.ref_pd(), _policy.ref_pd_cap());
Ram_transfer::Account &service_ram_account = session.service();
Ram_transfer::Remote_account child_ram_account(pd(), pd_session_cap());
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
Cap_transfer::Remote_account ref_cap_account(_policy.ref_pd(), _policy.ref_pd_cap());
Cap_transfer::Account &service_cap_account = session.service();
Cap_transfer::Remote_account child_cap_account(pd(), pd_session_cap());
try {
/* transfer session quota from the service to ourself */
Ram_transfer ram_donation_from_service(session.donated_ram_quota(),
service_ram_account, ref_ram_account);
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
Cap_transfer cap_donation_from_service(session.donated_cap_quota(),
service_cap_account, ref_cap_account);
base: remove Child::heap This patch improves the accounting for the backing store of session-state meta data. Originally, the session state used to be allocated by a child-local heap partition fed from the child's RAM session. However, whereas this approach was somehow practical from a runtime's (parent's) point of view, the child component could not count on the quota in its own RAM session. I.e., if the Child::heap grew at the parent side, the child's RAM session would magically diminish. This caused two problems. First, it violates assumptions of components like init that carefully manage their RAM resources (and giving most of them away their children). Second, if a child transfers most of its RAM session quota to another RAM session (like init does), the child's RAM session may actually not allow the parent's heap to grow, which is a very difficult error condition to deal with. In the new version, there is no Child::heap anymore. Instead, session states are allocated from the runtime's RAM session. In order to let children pay for these costs, the parent withdraws the local session costs from the session quota donated from the child when the child initiates a new session. Hence, in principle, all components on the route of the session request take a small bite from the session quota to pay for their local book keeping Consequently, the session quota that ends up at the server may become depleted more or less, depending on the route. In the case where the remaining quota is insufficient for the server, the server responds with 'QUOTA_EXCEEDED'. Since this behavior must generally be expected, this patch equips the client-side 'Env::session' implementation with the ability to re-issue session requests with successively growing quota donations. For several of core's services (ROM, IO_MEM, IRQ), the default session quota has now increased by 2 KiB, which should suffice for session requests to up to 3 hops as is the common case for most run scripts. For longer routes, the retry mechanism as described above comes into effect. For the time being, we give a warning whenever the server-side quota check triggers the retry mechanism. The warning may eventually be removed at a later stage.
2017-02-19 10:31:50 +01:00
/*
* Transfer session quota from ourself to the client (our child). In
* addition to the quota returned from the server, we also return the
* quota that we preserved for locally storing the session meta data
* ('session_costs').
*/
Ram_quota const returned_ram { session.donated_ram_quota().value +
_session_factory.session_costs() };
Ram_transfer ram_donation_to_client(returned_ram,
ref_ram_account, child_ram_account);
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
Cap_transfer cap_donation_to_client(session.donated_cap_quota(),
ref_cap_account, child_cap_account);
/* finish transaction */
ram_donation_from_service.acknowledge();
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
cap_donation_from_service.acknowledge();
ram_donation_to_client.acknowledge();
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
cap_donation_to_client.acknowledge();
}
catch (Ram_transfer::Quota_exceeded) {
warning(_policy.name(), ": could not revert session RAM quota (", session, ")"); }
catch (Cap_transfer::Quota_exceeded) {
warning(_policy.name(), ": could not revert session cap quota (", session, ")"); }
session.destroy();
_policy.session_state_changed();
}
Child::Close_result Child::_close(Session_state &session)
{
/*
* If session could not be established, destruct session immediately
* without involving the server
*/
if (session.phase == Session_state::SERVICE_DENIED
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
|| session.phase == Session_state::INSUFFICIENT_RAM_QUOTA
|| session.phase == Session_state::INSUFFICIENT_CAP_QUOTA) {
_revert_quota_and_destroy(session);
return CLOSE_DONE;
}
/* close session if alive */
if (session.alive()) {
session.phase = Session_state::CLOSE_REQUESTED;
session.service().initiate_request(session);
}
/*
* The service may have completed the close request immediately (e.g.,
* a locally implemented service). In this case, we can skip the
* asynchonous handling.
*/
if (session.phase == Session_state::CLOSED) {
_revert_quota_and_destroy(session);
return CLOSE_DONE;
}
_policy.session_state_changed();
session.discard_id_at_client();
session.service().wakeup();
return CLOSE_PENDING;
}
Child::Close_result Child::close(Client::Id id)
{
/* refuse to close the child's initial sessions */
if (Parent::Env::session_id(id))
return CLOSE_DONE;
try {
Close_result result = CLOSE_PENDING;
auto lamda = [&] (Session_state &session) { result = _close(session); };
_id_space.apply<Session_state>(id, lamda);
return result;
}
catch (Id_space<Parent::Client>::Unknown_id) { return CLOSE_DONE; }
}
void Child::session_ready(Session_state &session)
{
if (_session_sigh.valid() && session.async_client_notify)
Signal_transmitter(_session_sigh).submit();
}
void Child::session_closed(Session_state &session)
{
/*
* If the session was provided by a child of us, 'service.ram()' returns
* the RAM session of the corresponding child. Since the session to the
* server is closed now, we expect the server to have released all donated
* resources so that we can decrease the servers' quota.
*
* If this goes wrong, the server is misbehaving.
*/
_revert_quota_and_destroy(session);
if (_session_sigh.valid())
Signal_transmitter(_session_sigh).submit();
}
void Child::session_response(Server::Id id, Session_response response)
{
try {
_policy.server_id_space().apply<Session_state>(id, [&] (Session_state &session) {
switch (response) {
case Parent::SESSION_CLOSED:
session.phase = Session_state::CLOSED;
/*
* If the client exists, reflect the response to the client
* via the 'closed_callback'. If the client has vanished,
* i.e., if the close request was issued by ourself while
* killing a child, we drop the session state immediately.
*/
if (session.closed_callback) {
session.closed_callback->session_closed(session);
} else {
/*
* The client no longer exists. So we cannot take the
* regular path of executing '_revert_quota_and_destroy' in
* the context of the client. Instead, we immediately
* withdraw the session quota from the server ('this') to
* the reference account, and destroy the session object.
*/
Ram_transfer::Remote_account ref_ram_account(_policy.ref_pd(), _policy.ref_pd_cap());
Ram_transfer::Account &service_ram_account = session.service();
Cap_transfer::Remote_account ref_cap_account(_policy.ref_pd(), _policy.ref_pd_cap());
Cap_transfer::Account &service_cap_account = session.service();
try {
/* transfer session quota from the service to ourself */
Ram_transfer ram_donation_from_service(session.donated_ram_quota(),
service_ram_account, ref_ram_account);
Cap_transfer cap_donation_from_service(session.donated_cap_quota(),
service_cap_account, ref_cap_account);
ram_donation_from_service.acknowledge();
cap_donation_from_service.acknowledge();
}
catch (Ram_transfer::Quota_exceeded) {
warning(_policy.name(), " failed to return session RAM quota "
"(", session.donated_ram_quota(), ")"); }
catch (Cap_transfer::Quota_exceeded) {
warning(_policy.name(), " failed to return session cap quota "
"(", session.donated_cap_quota(), ")"); }
session.destroy();
_policy.session_state_changed();
}
break;
case Parent::SERVICE_DENIED:
session.phase = Session_state::SERVICE_DENIED;
if (session.ready_callback)
session.ready_callback->session_ready(session);
break;
case Parent::INSUFFICIENT_RAM_QUOTA:
session.phase = Session_state::INSUFFICIENT_RAM_QUOTA;
base: remove Child::heap This patch improves the accounting for the backing store of session-state meta data. Originally, the session state used to be allocated by a child-local heap partition fed from the child's RAM session. However, whereas this approach was somehow practical from a runtime's (parent's) point of view, the child component could not count on the quota in its own RAM session. I.e., if the Child::heap grew at the parent side, the child's RAM session would magically diminish. This caused two problems. First, it violates assumptions of components like init that carefully manage their RAM resources (and giving most of them away their children). Second, if a child transfers most of its RAM session quota to another RAM session (like init does), the child's RAM session may actually not allow the parent's heap to grow, which is a very difficult error condition to deal with. In the new version, there is no Child::heap anymore. Instead, session states are allocated from the runtime's RAM session. In order to let children pay for these costs, the parent withdraws the local session costs from the session quota donated from the child when the child initiates a new session. Hence, in principle, all components on the route of the session request take a small bite from the session quota to pay for their local book keeping Consequently, the session quota that ends up at the server may become depleted more or less, depending on the route. In the case where the remaining quota is insufficient for the server, the server responds with 'QUOTA_EXCEEDED'. Since this behavior must generally be expected, this patch equips the client-side 'Env::session' implementation with the ability to re-issue session requests with successively growing quota donations. For several of core's services (ROM, IO_MEM, IRQ), the default session quota has now increased by 2 KiB, which should suffice for session requests to up to 3 hops as is the common case for most run scripts. For longer routes, the retry mechanism as described above comes into effect. For the time being, we give a warning whenever the server-side quota check triggers the retry mechanism. The warning may eventually be removed at a later stage.
2017-02-19 10:31:50 +01:00
if (session.ready_callback)
session.ready_callback->session_ready(session);
break;
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
case Parent::INSUFFICIENT_CAP_QUOTA:
session.phase = Session_state::INSUFFICIENT_CAP_QUOTA;
if (session.ready_callback)
session.ready_callback->session_ready(session);
break;
case Parent::SESSION_OK:
if (session.phase == Session_state::UPGRADE_REQUESTED) {
session.phase = Session_state::CAP_HANDED_OUT;
if (session.ready_callback)
session.ready_callback->session_ready(session);
}
break;
}
});
}
catch (Child_policy::Nonexistent_id_space) { }
catch (Id_space<Parent::Client>::Unknown_id) {
warning("unexpected session response for unknown session"); }
}
void Child::deliver_session_cap(Server::Id id, Session_capability cap)
{
try {
_policy.server_id_space().apply<Session_state>(id, [&] (Session_state &session) {
/* ignore responses after 'close_all_sessions' of the client */
if (session.phase != Session_state::CREATE_REQUESTED)
return;
if (session.cap.valid()) {
_error("attempt to assign session cap twice");
return;
}
/*
* If the client vanished during the session creation, the
* session-close state change must be reflected to the server
* as soon as the session becomes available. This enables the
* server to wind down the session. If we just discarded the
* session, the server's ID space would become inconsistent
* with ours.
*/
if (!session.client_exists()) {
session.phase = Session_state::CLOSE_REQUESTED;
session.service().initiate_request(session);
return;
}
session.cap = cap;
session.phase = Session_state::AVAILABLE;
if (session.ready_callback)
session.ready_callback->session_ready(session);
});
}
catch (Child_policy::Nonexistent_id_space) { }
catch (Id_space<Parent::Client>::Unknown_id) { }
}
void Child::exit(int exit_value)
{
/*
* This function receives the hint from the child that now, its a good time
* to kill it. An inherited child class could use this hint to schedule the
* destruction of the child object.
*
* Note that the child object must not be destructed from by this function
* because it is executed by the thread contained in the child object.
*/
return _policy.exit(exit_value);
}
Thread_capability Child::main_thread_cap() const
{
/*
* The '_initial_thread' is always constructed when this function is
* called because the RPC call originates from the active child.
*/
return _initial_thread.constructed() ? _initial_thread->cap()
: Thread_capability();
}
void Child::resource_avail_sigh(Signal_context_capability sigh)
{
_resource_avail_sigh = sigh;
}
void Child::resource_request(Resource_args const &args)
{
_policy.resource_request(args);
}
void Child::yield_sigh(Signal_context_capability sigh) { _yield_sigh = sigh; }
Parent::Resource_args Child::yield_request()
{
Lock::Guard guard(_yield_request_lock);
return _yield_request_args;
}
void Child::yield_response() { _policy.yield_response(); }
void Child::heartbeat()
{
/*
* Issue heartbeat requests not before the component has registered a
* handler
*/
if (!_heartbeat_sigh.valid())
return;
_outstanding_heartbeats++;
Signal_transmitter(_heartbeat_sigh).submit();
}
unsigned Child::skipped_heartbeats() const
{
/*
* An '_outstanding_heartbeats' value of 1 is fine because the child needs
* some time to respond to the heartbeat signal. However, at the time when
* the second (or later) heartbeat signal is triggered, the first one
* should have been answered.
*/
return (_outstanding_heartbeats > 1) ? _outstanding_heartbeats - 1 : 0;
}
void Child::heartbeat_sigh(Signal_context_capability sigh)
{
_heartbeat_sigh = sigh;
}
void Child::heartbeat_response() { _outstanding_heartbeats = 0; }
namespace {
/**
* Return interface for interacting with the child's address space
*
* Depending on the return value of 'Child_policy::address_space', we
* either interact with a local object of via an RPC client stub.
*/
struct Child_address_space
{
Region_map_client _rm_client;
Region_map &_rm;
Child_address_space(Pd_session &pd, Child_policy &policy)
:
_rm_client(pd.address_space()),
_rm(policy.address_space(pd) ? *policy.address_space(pd) : _rm_client)
{ }
Region_map &region_map() { return _rm; }
};
}
void Child::_try_construct_env_dependent_members()
{
/* check if the environment sessions are complete */
if (!_pd.cap().valid() || !_cpu.cap().valid() || !_log.cap().valid()
|| !_binary.cap().valid())
return;
/*
* If the ROM-session request for the dynamic linker was granted but the
* response to the session request is still outstanding, we have to wait.
* Note that we proceed if the session request was denied by the policy,
* which may be the case when using a statically linked executable.
*/
if (_linker.constructed() && !_linker->cap().valid())
return;
/*
* Mark all environment sessions as handed out to prevent the triggering
* of signals by 'Child::session_sigh' for these sessions.
*/
_id_space.for_each<Session_state>([&] (Session_state &session) {
if (session.phase == Session_state::AVAILABLE)
session.phase = Session_state::CAP_HANDED_OUT; });
_policy.init(_cpu.session(), _cpu.cap());
Process::Type const type = _policy.forked()
? Process::TYPE_FORKED : Process::TYPE_LOADED;
try {
_initial_thread.construct(_cpu.session(), _pd.cap(), _policy.name());
_process.construct(type, _linker_dataspace(), _pd.session(),
*_initial_thread, _local_rm,
Child_address_space(_pd.session(), _policy).region_map(),
cap());
}
catch (Out_of_ram) { _error("out of RAM during ELF loading"); }
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
catch (Out_of_caps) { _error("out of caps during ELF loading"); }
catch (Cpu_session::Thread_creation_failed) { _error("unable to create initial thread"); }
catch (Process::Missing_dynamic_linker) { _error("dynamic linker unavailable"); }
catch (Process::Invalid_executable) { _error("invalid ELF executable"); }
catch (Region_map::Invalid_dataspace) { _error("ELF loading failed (Invalid_dataspace)"); }
catch (Region_map::Region_conflict) { _error("ELF loading failed (Region_conflict)"); }
}
void Child::_discard_env_session(Id_space<Parent::Client>::Id id)
{
auto discard_id_fn = [&] (Session_state &s) { s.discard_id_at_client(); };
try { _id_space.apply<Session_state>(id, discard_id_fn); }
catch (Id_space<Parent::Client>::Unknown_id) { }
}
void Child::initiate_env_pd_session()
{
_pd.initiate();
_policy.init(_pd.session(), _pd.cap());
}
void Child::initiate_env_sessions()
{
_cpu .initiate();
_log .initiate();
_binary.initiate();
/*
* Issue environment-session request for obtaining the linker binary. We
* accept this request to fail. In this case, the child creation may still
* succeed if the binary is statically linked.
*/
try {
_linker.construct(*this, Parent::Env::linker(), _policy.linker_name());
_linker->initiate();
}
catch (Service_denied) { }
_try_construct_env_dependent_members();
}
/**
* Return any CPU session that is initiated by the child
*
* \return client ID of a CPU session, or
* client ID 0 if no session exists
*/
static Parent::Client::Id any_cpu_session_id(Id_space<Parent::Client> const &id_space)
{
Parent::Client::Id result { 0 };
id_space.for_each<Session_state const>([&] (Session_state const &session) {
if (result.value)
return;
bool cpu = (session.service().name() == Cpu_session::service_name());
bool env = Parent::Env::session_id(session.id_at_client());
if (!env && cpu)
result = session.id_at_client();
});
return result;
}
void Child::close_all_sessions()
{
/*
* Destroy CPU sessions prior to other session types to avoid page-fault
* warnings generated by threads that are losing their PD while still
* running.
*/
while (unsigned long id_value = any_cpu_session_id(_id_space).value)
close(Parent::Client::Id{id_value});
_initial_thread.destruct();
if (KERNEL_SUPPORTS_EAGER_CHILD_DESTRUCTION)
_cpu._connection.destruct();
/*
* Purge the meta data about any dangling sessions provided by the child to
* other children.
*
* Note that the session quota is not transferred back to the respective
* clients.
*
* All the session meta data is lost after this point. In principle, we
* could accumulate the to-be-replenished quota at each client. Once the
* server is completely destroyed (and we thereby regained all of the
* server's resources, the RAM sessions of the clients could be updated.
* However, a client of a suddenly disappearing server is expected to be in
* trouble anyway and likely to get stuck on the next attempt to interact
* with the server. So the added complexity of reverting the session quotas
* would be to no benefit.
*/
try {
auto lambda = [&] (Session_state &s) { _revert_quota_and_destroy(s); };
while (_policy.server_id_space().apply_any<Session_state>(lambda));
}
catch (Child_policy::Nonexistent_id_space) { }
/*
* Issue close requests to the providers of the environment sessions,
* which may be async services.
*/
_log.close();
_binary.close();
if (_linker.constructed())
_linker->close();
_pd.close();
/*
* Remove statically created env sessions from the child's ID space.
*/
_discard_env_session(Env::cpu());
_discard_env_session(Env::pd());
_discard_env_session(Env::log());
_discard_env_session(Env::binary());
_discard_env_session(Env::linker());
/*
* Remove dynamically created sessions from the child's ID space.
*/
auto close_fn = [&] (Session_state &session) {
session.closed_callback = nullptr;
session.ready_callback = nullptr;
_close(session);
};
while (_id_space.apply_any<Session_state>(close_fn));
if (!KERNEL_SUPPORTS_EAGER_CHILD_DESTRUCTION)
_cpu._connection.destruct();
}
Child::Child(Region_map &local_rm,
Rpc_entrypoint &entrypoint,
Child_policy &policy)
:
_policy(policy), _local_rm(local_rm), _parent_cap_guard(entrypoint, *this)
{
if (_policy.initiate_env_sessions()) {
initiate_env_pd_session();
initiate_env_sessions();
}
}
Child::~Child()
{
close_all_sessions();
_process.destruct();
}