2017-03-03 15:57:41 +00:00
|
|
|
/*
|
|
|
|
* \brief Child representation
|
|
|
|
* \author Norman Feske
|
|
|
|
* \date 2010-05-04
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (C) 2010-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.
|
|
|
|
*/
|
|
|
|
|
2019-01-11 14:40:49 +00:00
|
|
|
#include <vm_session/vm_session.h>
|
|
|
|
|
2017-03-03 15:57:41 +00:00
|
|
|
/* local includes */
|
|
|
|
#include <child.h>
|
|
|
|
|
|
|
|
|
2018-05-22 09:32:36 +00:00
|
|
|
void Init::Child::destroy_services()
|
|
|
|
{
|
|
|
|
_child_services.for_each([&] (Routed_service &service) {
|
|
|
|
if (service.has_id_space(_session_requester.id_space()))
|
|
|
|
destroy(_alloc, &service); });
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-03-06 14:19:35 +00:00
|
|
|
Init::Child::Apply_config_result
|
|
|
|
Init::Child::apply_config(Xml_node start_node)
|
2017-03-03 15:57:41 +00:00
|
|
|
{
|
2018-06-21 09:46:44 +00:00
|
|
|
if (_state == STATE_ABANDONED || _exited)
|
2017-03-03 15:57:41 +00:00
|
|
|
return NO_SIDE_EFFECTS;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the child's environment is incomplete, restart it to attempt
|
|
|
|
* the re-routing of its environment sessions.
|
|
|
|
*/
|
2018-06-12 13:52:49 +00:00
|
|
|
{
|
|
|
|
bool env_log_exists = false, env_binary_exists = false;
|
|
|
|
_child.for_each_session([&] (Session_state const &session) {
|
|
|
|
Parent::Client::Id const id = session.id_at_client();
|
|
|
|
env_log_exists |= (id == Parent::Env::log());
|
|
|
|
env_binary_exists |= (id == Parent::Env::binary());
|
|
|
|
});
|
|
|
|
|
|
|
|
if (!env_binary_exists || !env_log_exists) {
|
|
|
|
abandon();
|
|
|
|
return MAY_HAVE_SIDE_EFFECTS;
|
|
|
|
}
|
2017-03-03 15:57:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool provided_services_changed = false;
|
|
|
|
|
|
|
|
enum Config_update { CONFIG_APPEARED, CONFIG_VANISHED,
|
|
|
|
CONFIG_CHANGED, CONFIG_UNCHANGED };
|
|
|
|
|
|
|
|
Config_update config_update = CONFIG_UNCHANGED;
|
|
|
|
|
2019-01-21 09:48:39 +00:00
|
|
|
/*
|
2019-03-12 16:55:17 +00:00
|
|
|
* Import new start node if it differs
|
2019-01-21 09:48:39 +00:00
|
|
|
*/
|
|
|
|
if (start_node.differs_from(_start_node->xml())) {
|
|
|
|
|
2017-03-03 15:57:41 +00:00
|
|
|
/*
|
|
|
|
* Start node changed
|
|
|
|
*
|
|
|
|
* Determine how the inline config is affected.
|
|
|
|
*/
|
|
|
|
char const * const tag = "config";
|
|
|
|
bool const config_was_present = _start_node->xml().has_sub_node(tag);
|
|
|
|
bool const config_is_present = start_node.has_sub_node(tag);
|
|
|
|
|
|
|
|
if (config_was_present && !config_is_present)
|
|
|
|
config_update = CONFIG_VANISHED;
|
|
|
|
|
|
|
|
if (!config_was_present && config_is_present)
|
|
|
|
config_update = CONFIG_APPEARED;
|
|
|
|
|
|
|
|
if (config_was_present && config_is_present) {
|
|
|
|
|
2019-01-21 09:48:39 +00:00
|
|
|
Xml_node const old_config = _start_node->xml().sub_node(tag);
|
|
|
|
Xml_node const new_config = start_node.sub_node(tag);
|
2017-03-03 15:57:41 +00:00
|
|
|
|
2019-01-21 09:48:39 +00:00
|
|
|
if (new_config.differs_from(old_config))
|
2017-03-03 15:57:41 +00:00
|
|
|
config_update = CONFIG_CHANGED;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Import updated <provides> node
|
|
|
|
*
|
|
|
|
* First abandon services that are no longer present in the
|
|
|
|
* <provides> node. Then add services that have newly appeared.
|
|
|
|
*/
|
|
|
|
_child_services.for_each([&] (Routed_service &service) {
|
|
|
|
|
|
|
|
if (!_provided_by_this(service))
|
|
|
|
return;
|
|
|
|
|
|
|
|
typedef Service::Name Name;
|
|
|
|
Name const name = service.name();
|
|
|
|
|
|
|
|
bool still_provided = false;
|
|
|
|
_provides_sub_node(start_node)
|
|
|
|
.for_each_sub_node("service", [&] (Xml_node node) {
|
|
|
|
if (name == node.attribute_value("name", Name()))
|
|
|
|
still_provided = true; });
|
|
|
|
|
|
|
|
if (!still_provided) {
|
|
|
|
service.abandon();
|
|
|
|
provided_services_changed = true;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
_provides_sub_node(start_node).for_each_sub_node("service",
|
|
|
|
[&] (Xml_node node) {
|
|
|
|
if (_service_exists(node))
|
|
|
|
return;
|
|
|
|
|
|
|
|
_add_service(node);
|
|
|
|
provided_services_changed = true;
|
|
|
|
});
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Import new binary name. A change may affect the route for
|
|
|
|
* the binary's ROM session, triggering the restart of the
|
|
|
|
* child.
|
|
|
|
*/
|
|
|
|
_binary_name = _binary_from_xml(start_node, _unique_name);
|
|
|
|
|
2018-11-14 15:19:30 +00:00
|
|
|
_heartbeat_enabled = start_node.has_sub_node("heartbeat");
|
|
|
|
|
2017-03-03 15:57:41 +00:00
|
|
|
/* import new start node */
|
|
|
|
_start_node.construct(_alloc, start_node);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Apply change to '_config_rom_service'. This will
|
|
|
|
* potentially result in a change of the "config" ROM route, which
|
|
|
|
* may in turn prompt the routing-check below to abandon (restart)
|
|
|
|
* the child.
|
|
|
|
*/
|
|
|
|
switch (config_update) {
|
|
|
|
case CONFIG_UNCHANGED: break;
|
|
|
|
case CONFIG_CHANGED: _config_rom_service->trigger_update(); break;
|
|
|
|
case CONFIG_APPEARED: _config_rom_service.construct(*this); break;
|
|
|
|
case CONFIG_VANISHED: _config_rom_service->abandon(); break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* validate that the routes of all existing sessions remain intact */
|
|
|
|
{
|
|
|
|
bool routing_changed = false;
|
|
|
|
_child.for_each_session([&] (Session_state const &session) {
|
|
|
|
if (!_route_valid(session))
|
|
|
|
routing_changed = true; });
|
|
|
|
|
|
|
|
if (routing_changed) {
|
|
|
|
abandon();
|
|
|
|
return MAY_HAVE_SIDE_EFFECTS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (provided_services_changed)
|
|
|
|
return MAY_HAVE_SIDE_EFFECTS;
|
|
|
|
|
|
|
|
return NO_SIDE_EFFECTS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-06-04 13:49:29 +00:00
|
|
|
Init::Ram_quota Init::Child::_configured_ram_quota() const
|
2017-03-06 14:19:35 +00:00
|
|
|
{
|
|
|
|
size_t assigned = 0;
|
|
|
|
|
2018-06-04 13:49:29 +00:00
|
|
|
_start_node->xml().for_each_sub_node("resource", [&] (Xml_node resource) {
|
2017-03-06 14:19:35 +00:00
|
|
|
if (resource.attribute_value("name", String<8>()) == "RAM")
|
|
|
|
assigned = resource.attribute_value("quantum", Number_of_bytes()); });
|
|
|
|
|
|
|
|
return Ram_quota { assigned };
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-06-04 13:49:29 +00:00
|
|
|
Init::Cap_quota Init::Child::_configured_cap_quota() const
|
2017-03-06 14:19:35 +00:00
|
|
|
{
|
2018-06-04 13:49:29 +00:00
|
|
|
size_t const default_caps = _default_caps_accessor.default_caps().value;
|
|
|
|
|
|
|
|
return Cap_quota { _start_node->xml().attribute_value("caps", default_caps) };
|
|
|
|
}
|
2017-03-06 14:19:35 +00:00
|
|
|
|
2018-06-04 13:49:29 +00:00
|
|
|
|
|
|
|
template <typename QUOTA, typename LIMIT_ACCESSOR>
|
|
|
|
void Init::Child::_apply_resource_upgrade(QUOTA &assigned, QUOTA const configured,
|
|
|
|
LIMIT_ACCESSOR const &limit_accessor)
|
|
|
|
{
|
|
|
|
if (configured.value <= assigned.value)
|
2017-03-06 14:19:35 +00:00
|
|
|
return;
|
|
|
|
|
2018-06-04 13:49:29 +00:00
|
|
|
QUOTA const limit = limit_accessor.resource_limit(QUOTA{});
|
|
|
|
size_t const increment = configured.value - assigned.value;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the configured quota exceeds our own quota, we donate all remaining
|
|
|
|
* quota to the child.
|
|
|
|
*/
|
|
|
|
if (increment > limit.value)
|
|
|
|
if (_verbose.enabled())
|
|
|
|
warn_insuff_quota(limit.value);
|
2017-03-06 14:19:35 +00:00
|
|
|
|
2018-06-04 13:49:29 +00:00
|
|
|
QUOTA const transfer { min(increment, limit.value) };
|
2017-03-06 14:19:35 +00:00
|
|
|
|
|
|
|
/*
|
2018-06-04 13:49:29 +00:00
|
|
|
* Remember assignment and apply upgrade to child
|
2017-03-06 14:19:35 +00:00
|
|
|
*
|
2018-06-04 13:49:29 +00:00
|
|
|
* Note that we remember the actually transferred amount as the assigned
|
|
|
|
* amount. In the case where the value is clamped to to the limit, the
|
|
|
|
* value as given in the config remains diverged from the assigned value.
|
|
|
|
* This way, a future config update will attempt the completion of the
|
|
|
|
* upgrade if memory become available.
|
2017-03-06 14:19:35 +00:00
|
|
|
*/
|
2018-06-04 13:49:29 +00:00
|
|
|
if (transfer.value) {
|
2017-03-06 14:19:35 +00:00
|
|
|
|
2018-06-04 13:49:29 +00:00
|
|
|
assigned.value += transfer.value;
|
2017-03-06 14:19:35 +00:00
|
|
|
|
2018-06-04 13:49:29 +00:00
|
|
|
ref_pd().transfer_quota(_child.pd_session_cap(), transfer);
|
2017-03-06 17:04:10 +00:00
|
|
|
|
|
|
|
/* wake up child that blocks on a resource request */
|
|
|
|
if (_requested_resources.constructed()) {
|
|
|
|
_child.notify_resource_avail();
|
|
|
|
_requested_resources.destruct();
|
|
|
|
}
|
2017-03-06 14:19:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-06-04 13:49:29 +00:00
|
|
|
void Init::Child::apply_upgrade()
|
2017-03-06 14:19:35 +00:00
|
|
|
{
|
2019-02-27 16:36:44 +00:00
|
|
|
/* pd_session_cap of exited child is invalid and unusable for transfers */
|
|
|
|
if (_exited)
|
|
|
|
return;
|
|
|
|
|
2018-06-04 13:49:29 +00:00
|
|
|
if (_resources.effective_ram_quota().value == 0)
|
|
|
|
warning(name(), ": no valid RAM quota defined");
|
|
|
|
|
|
|
|
_apply_resource_upgrade(_resources.assigned_ram_quota,
|
|
|
|
_configured_ram_quota(), _ram_limit_accessor);
|
|
|
|
|
|
|
|
if (_resources.effective_cap_quota().value == 0)
|
|
|
|
warning(name(), ": no valid capability quota defined");
|
|
|
|
|
|
|
|
_apply_resource_upgrade(_resources.assigned_cap_quota,
|
|
|
|
_configured_cap_quota(), _cap_limit_accessor);
|
|
|
|
}
|
2017-03-06 14:19:35 +00:00
|
|
|
|
2018-06-04 13:49:29 +00:00
|
|
|
|
|
|
|
template <typename QUOTA, typename CHILD_AVAIL_QUOTA_FN>
|
|
|
|
void Init::Child::_apply_resource_downgrade(QUOTA &assigned, QUOTA const configured,
|
|
|
|
QUOTA const preserved,
|
|
|
|
CHILD_AVAIL_QUOTA_FN const &child_avail_quota_fn)
|
|
|
|
{
|
|
|
|
if (configured.value >= assigned.value)
|
2017-03-06 14:19:35 +00:00
|
|
|
return;
|
|
|
|
|
2018-06-04 13:49:29 +00:00
|
|
|
QUOTA const decrement { assigned.value - configured.value };
|
2017-03-06 14:19:35 +00:00
|
|
|
|
|
|
|
/*
|
2018-06-04 13:49:29 +00:00
|
|
|
* The child may concurrently consume quota from its PD session,
|
2017-03-06 14:19:35 +00:00
|
|
|
* causing the 'transfer_quota' to fail. For this reason, we repeatedly
|
|
|
|
* attempt the transfer.
|
|
|
|
*/
|
|
|
|
unsigned max_attempts = 4, attempts = 0;
|
|
|
|
for (; attempts < max_attempts; attempts++) {
|
|
|
|
|
2018-06-04 13:49:29 +00:00
|
|
|
/* give up if the child's available quota is exhausted */
|
|
|
|
size_t const avail = child_avail_quota_fn().value;
|
|
|
|
if (avail < preserved.value)
|
2017-03-06 14:19:35 +00:00
|
|
|
break;
|
|
|
|
|
2018-06-04 13:49:29 +00:00
|
|
|
QUOTA const transfer { min(avail - preserved.value, decrement.value) };
|
2017-03-06 14:19:35 +00:00
|
|
|
|
2017-05-08 10:33:56 +00:00
|
|
|
try {
|
2018-06-04 13:49:29 +00:00
|
|
|
_child.pd().transfer_quota(ref_pd_cap(), transfer);
|
|
|
|
assigned.value -= transfer.value;
|
2017-03-06 14:19:35 +00:00
|
|
|
break;
|
2017-05-08 10:33:56 +00:00
|
|
|
} catch (...) { }
|
2017-03-06 14:19:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (attempts == max_attempts)
|
2018-06-04 13:49:29 +00:00
|
|
|
warning(name(), ": downgrade failed after ", max_attempts, " attempts");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Init::Child::apply_downgrade()
|
|
|
|
{
|
|
|
|
Ram_quota const configured_ram_quota = _configured_ram_quota();
|
|
|
|
Cap_quota const configured_cap_quota = _configured_cap_quota();
|
|
|
|
|
|
|
|
_apply_resource_downgrade(_resources.assigned_ram_quota,
|
|
|
|
configured_ram_quota, Ram_quota{16*1024},
|
|
|
|
[&] () { return _child.pd().avail_ram(); });
|
|
|
|
|
|
|
|
_apply_resource_downgrade(_resources.assigned_cap_quota,
|
|
|
|
configured_cap_quota, Cap_quota{5},
|
|
|
|
[&] () { return _child.pd().avail_caps(); });
|
2017-03-06 14:19:35 +00:00
|
|
|
|
|
|
|
/*
|
2018-06-04 13:49:29 +00:00
|
|
|
* If designated resource quota is lower than the child's consumed quota,
|
|
|
|
* issue a yield request to the child.
|
2017-03-06 14:19:35 +00:00
|
|
|
*/
|
2018-06-04 13:49:29 +00:00
|
|
|
size_t demanded_ram_quota = 0;
|
|
|
|
size_t demanded_cap_quota = 0;
|
2017-03-06 14:19:35 +00:00
|
|
|
|
2018-06-04 13:49:29 +00:00
|
|
|
if (configured_ram_quota.value < _resources.assigned_ram_quota.value)
|
|
|
|
demanded_ram_quota = _resources.assigned_ram_quota.value - configured_ram_quota.value;
|
2017-03-06 14:19:35 +00:00
|
|
|
|
2018-06-04 13:49:29 +00:00
|
|
|
if (configured_cap_quota.value < _resources.assigned_cap_quota.value)
|
|
|
|
demanded_cap_quota = _resources.assigned_cap_quota.value - configured_cap_quota.value;
|
|
|
|
|
|
|
|
if (demanded_ram_quota || demanded_cap_quota) {
|
|
|
|
Parent::Resource_args const
|
|
|
|
args { "ram_quota=", Number_of_bytes(demanded_ram_quota), ", ",
|
|
|
|
"cap_quota=", demanded_cap_quota};
|
2017-03-06 14:19:35 +00:00
|
|
|
_child.yield(args);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-03-03 15:57:41 +00:00
|
|
|
void Init::Child::report_state(Xml_generator &xml, Report_detail const &detail) const
|
|
|
|
{
|
2018-06-12 13:49:17 +00:00
|
|
|
if (abandoned())
|
|
|
|
return;
|
|
|
|
|
2018-05-22 09:32:36 +00:00
|
|
|
/* true if it's safe to call the PD for requesting resource information */
|
|
|
|
bool const pd_alive = !abandoned() && !_exited;
|
|
|
|
|
2017-03-03 15:57:41 +00:00
|
|
|
xml.node("child", [&] () {
|
|
|
|
|
|
|
|
xml.attribute("name", _unique_name);
|
|
|
|
xml.attribute("binary", _binary_name);
|
|
|
|
|
|
|
|
if (_version.valid())
|
|
|
|
xml.attribute("version", _version);
|
|
|
|
|
|
|
|
if (detail.ids())
|
|
|
|
xml.attribute("id", _id.value);
|
|
|
|
|
|
|
|
if (!_child.active())
|
|
|
|
xml.attribute("state", "incomplete");
|
|
|
|
|
2017-10-26 14:04:58 +00:00
|
|
|
if (_exited)
|
|
|
|
xml.attribute("exited", _exit_value);
|
|
|
|
|
2018-11-14 15:19:30 +00:00
|
|
|
if (_heartbeat_enabled && _child.skipped_heartbeats())
|
|
|
|
xml.attribute("skipped_heartbeats", _child.skipped_heartbeats());
|
|
|
|
|
2019-01-21 09:48:39 +00:00
|
|
|
if (detail.child_ram() && _child.pd_session_cap().valid()) {
|
2017-03-03 15:57:41 +00:00
|
|
|
xml.node("ram", [&] () {
|
2017-03-06 14:19:35 +00:00
|
|
|
|
|
|
|
xml.attribute("assigned", String<32> {
|
|
|
|
Number_of_bytes(_resources.assigned_ram_quota.value) });
|
|
|
|
|
2018-05-22 09:32:36 +00:00
|
|
|
if (pd_alive)
|
2019-01-21 09:48:39 +00:00
|
|
|
generate_ram_info(xml, _child.pd());
|
2017-03-06 17:04:10 +00:00
|
|
|
|
Capability quota accounting and trading
This patch mirrors the accounting and trading scheme that Genode employs
for physical memory to the accounting of capability allocations.
Capability quotas must now be explicitly assigned to subsystems by
specifying a 'caps=<amount>' attribute to init's start nodes.
Analogously to RAM quotas, cap quotas can be traded between clients and
servers as part of the session protocol. The capability budget of each
component is maintained by the component's corresponding PD session at
core.
At the current stage, the accounting is applied to RPC capabilities,
signal-context capabilities, and dataspace capabilities. Capabilities
that are dynamically allocated via core's CPU and TRACE service are not
yet covered. Also, the capabilities allocated by resource multiplexers
outside of core (like nitpicker) must be accounted by the respective
servers, which is not covered yet.
If a component runs out of capabilities, core's PD service prints a
warning to the log. To observe the consumption of capabilities per
component in detail, the PD service is equipped with a diagnostic
mode, which can be enabled via the 'diag' attribute in the target
node of init's routing rules. E.g., the following route enables the
diagnostic mode for the PD session of the "timer" component:
<default-route>
<service name="PD" unscoped_label="timer">
<parent diag="yes"/>
</service>
...
</default-route>
For subsystems based on a sub-init instance, init can be configured
to report the capability-quota information of its subsystems by
adding the attribute 'child_caps="yes"' to init's '<report>'
config node. Init's own capability quota can be reported by adding
the attribute 'init_caps="yes"'.
Fixes #2398
2017-05-08 19:35:43 +00:00
|
|
|
if (_requested_resources.constructed() && _requested_resources->ram.value)
|
|
|
|
xml.attribute("requested", String<32>(_requested_resources->ram));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (detail.child_caps() && _child.pd_session_cap().valid()) {
|
|
|
|
xml.node("caps", [&] () {
|
|
|
|
|
|
|
|
xml.attribute("assigned", String<32>(_resources.assigned_cap_quota));
|
|
|
|
|
2018-05-22 09:32:36 +00:00
|
|
|
if (pd_alive)
|
|
|
|
generate_caps_info(xml, _child.pd());
|
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 19:35:43 +00:00
|
|
|
|
|
|
|
if (_requested_resources.constructed() && _requested_resources->caps.value)
|
|
|
|
xml.attribute("requested", String<32>(_requested_resources->caps));
|
2017-03-03 15:57:41 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
Session_state::Detail const
|
|
|
|
session_detail { detail.session_args() ? Session_state::Detail::ARGS
|
|
|
|
: Session_state::Detail::NO_ARGS};
|
|
|
|
|
|
|
|
if (detail.requested()) {
|
|
|
|
xml.node("requested", [&] () {
|
|
|
|
_child.for_each_session([&] (Session_state const &session) {
|
|
|
|
xml.node("session", [&] () {
|
|
|
|
session.generate_client_side_info(xml, session_detail); }); }); });
|
|
|
|
}
|
|
|
|
|
|
|
|
if (detail.provided()) {
|
|
|
|
xml.node("provided", [&] () {
|
|
|
|
|
|
|
|
auto fn = [&] (Session_state const &session) {
|
|
|
|
xml.node("session", [&] () {
|
|
|
|
session.generate_server_side_info(xml, session_detail); }); };
|
|
|
|
|
2017-04-24 09:25:54 +00:00
|
|
|
_session_requester.id_space().for_each<Session_state const>(fn);
|
2017-03-03 15:57:41 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
|
Capability quota accounting and trading
This patch mirrors the accounting and trading scheme that Genode employs
for physical memory to the accounting of capability allocations.
Capability quotas must now be explicitly assigned to subsystems by
specifying a 'caps=<amount>' attribute to init's start nodes.
Analogously to RAM quotas, cap quotas can be traded between clients and
servers as part of the session protocol. The capability budget of each
component is maintained by the component's corresponding PD session at
core.
At the current stage, the accounting is applied to RPC capabilities,
signal-context capabilities, and dataspace capabilities. Capabilities
that are dynamically allocated via core's CPU and TRACE service are not
yet covered. Also, the capabilities allocated by resource multiplexers
outside of core (like nitpicker) must be accounted by the respective
servers, which is not covered yet.
If a component runs out of capabilities, core's PD service prints a
warning to the log. To observe the consumption of capabilities per
component in detail, the PD service is equipped with a diagnostic
mode, which can be enabled via the 'diag' attribute in the target
node of init's routing rules. E.g., the following route enables the
diagnostic mode for the PD session of the "timer" component:
<default-route>
<service name="PD" unscoped_label="timer">
<parent diag="yes"/>
</service>
...
</default-route>
For subsystems based on a sub-init instance, init can be configured
to report the capability-quota information of its subsystems by
adding the attribute 'child_caps="yes"' to init's '<report>'
config node. Init's own capability quota can be reported by adding
the attribute 'init_caps="yes"'.
Fixes #2398
2017-05-08 19:35:43 +00:00
|
|
|
void Init::Child::init(Pd_session &session, Pd_session_capability cap)
|
|
|
|
{
|
|
|
|
session.ref_account(_env.pd_session_cap());
|
|
|
|
|
2017-03-03 15:57:41 +00:00
|
|
|
size_t const initial_session_costs =
|
|
|
|
session_alloc_batch_size()*_child.session_factory().session_costs();
|
|
|
|
|
2017-05-11 18:03:28 +00:00
|
|
|
Ram_quota const ram_quota { _resources.effective_ram_quota().value > initial_session_costs
|
2017-03-06 14:19:35 +00:00
|
|
|
? _resources.effective_ram_quota().value - initial_session_costs
|
2017-05-11 18:03:28 +00:00
|
|
|
: 0 };
|
|
|
|
|
|
|
|
Cap_quota const cap_quota { _resources.effective_cap_quota().value };
|
|
|
|
|
|
|
|
try { _env.pd().transfer_quota(cap, cap_quota); }
|
|
|
|
catch (Out_of_caps) {
|
|
|
|
error(name(), ": unable to initialize cap quota of PD"); }
|
|
|
|
|
2019-01-21 09:48:39 +00:00
|
|
|
try { _env.pd().transfer_quota(cap, ram_quota); }
|
2017-05-11 18:03:28 +00:00
|
|
|
catch (Out_of_ram) {
|
|
|
|
error(name(), ": unable to initialize RAM quota of PD"); }
|
2017-03-03 15:57:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Init::Child::init(Cpu_session &session, Cpu_session_capability cap)
|
|
|
|
{
|
|
|
|
static size_t avail = Cpu_session::quota_lim_upscale( 100, 100);
|
|
|
|
size_t const need = Cpu_session::quota_lim_upscale(_resources.cpu_quota_pc, 100);
|
|
|
|
size_t need_adj = 0;
|
|
|
|
|
|
|
|
if (need > avail || avail == 0) {
|
|
|
|
warn_insuff_quota(Cpu_session::quota_lim_downscale(avail, 100));
|
|
|
|
need_adj = Cpu_session::quota_lim_upscale(100, 100);
|
|
|
|
avail = 0;
|
|
|
|
} else {
|
|
|
|
need_adj = Cpu_session::quota_lim_upscale(need, avail);
|
|
|
|
avail -= need;
|
|
|
|
}
|
|
|
|
session.ref_account(_env.cpu_session_cap());
|
|
|
|
_env.cpu().transfer_quota(cap, need_adj);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Init::Child::Route Init::Child::resolve_session_request(Service::Name const &service_name,
|
|
|
|
Session_label const &label)
|
|
|
|
{
|
|
|
|
/* check for "config" ROM request */
|
|
|
|
if (service_name == Rom_session::service_name() &&
|
|
|
|
label.last_element() == "config") {
|
|
|
|
|
|
|
|
if (_config_rom_service.constructed() &&
|
|
|
|
!_config_rom_service->abandoned())
|
Follow practices suggested by "Effective C++"
The patch adjust the code of the base, base-<kernel>, and os repository.
To adapt existing components to fix violations of the best practices
suggested by "Effective C++" as reported by the -Weffc++ compiler
argument. The changes follow the patterns outlined below:
* A class with virtual functions can no longer publicly inherit base
classed without a vtable. The inherited object may either be moved
to a member variable, or inherited privately. The latter would be
used for classes that inherit 'List::Element' or 'Avl_node'. In order
to enable the 'List' and 'Avl_tree' to access the meta data, the
'List' must become a friend.
* Instead of adding a virtual destructor to abstract base classes,
we inherit the new 'Interface' class, which contains a virtual
destructor. This way, single-line abstract base classes can stay
as compact as they are now. The 'Interface' utility resides in
base/include/util/interface.h.
* With the new warnings enabled, all member variables must be explicitly
initialized. Basic types may be initialized with '='. All other types
are initialized with braces '{ ... }' or as class initializers. If
basic types and non-basic types appear in a row, it is nice to only
use the brace syntax (also for basic types) and align the braces.
* If a class contains pointers as members, it must now also provide a
copy constructor and assignment operator. In the most cases, one
would make them private, effectively disallowing the objects to be
copied. Unfortunately, this warning cannot be fixed be inheriting
our existing 'Noncopyable' class (the compiler fails to detect that
the inheriting class cannot be copied and still gives the error).
For now, we have to manually add declarations for both the copy
constructor and assignment operator as private class members. Those
declarations should be prepended with a comment like this:
/*
* Noncopyable
*/
Thread(Thread const &);
Thread &operator = (Thread const &);
In the future, we should revisit these places and try to replace
the pointers with references. In the presence of at least one
reference member, the compiler would no longer implicitly generate
a copy constructor. So we could remove the manual declaration.
Issue #465
2017-12-21 14:42:15 +00:00
|
|
|
return Route { _config_rom_service->service(), label,
|
|
|
|
Session::Diag{false} };
|
2017-03-03 15:57:41 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* \deprecated the support for the <configfile> tag will
|
|
|
|
* be removed
|
|
|
|
*/
|
|
|
|
if (_start_node->xml().has_sub_node("configfile")) {
|
|
|
|
|
|
|
|
typedef String<50> Name;
|
|
|
|
Name const rom =
|
|
|
|
_start_node->xml().sub_node("configfile")
|
|
|
|
.attribute_value("name", Name());
|
|
|
|
|
|
|
|
/* prevent infinite recursion */
|
|
|
|
if (rom == "config") {
|
|
|
|
error("configfile must not be named 'config'");
|
Streamline exception types
This patch reduces the number of exception types by facilitating
globally defined exceptions for common usage patterns shared by most
services. In particular, RPC functions that demand a session-resource
upgrade not longer reflect this condition via a session-specific
exception but via the 'Out_of_ram' or 'Out_of_caps' types.
Furthermore, the 'Parent::Service_denied', 'Parent::Unavailable',
'Root::Invalid_args', 'Root::Unavailable', 'Service::Invalid_args',
'Service::Unavailable', and 'Local_service::Factory::Denied' types have
been replaced by the single 'Service_denied' exception type defined in
'session/session.h'.
This consolidation eases the error handling (there are fewer exceptions
to handle), alleviates the need to convert exceptions along the
session-creation call chain, and avoids possible aliasing problems
(catching the wrong type with the same name but living in a different
scope).
2017-05-07 20:03:22 +00:00
|
|
|
throw Service_denied();
|
2017-03-03 15:57:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return resolve_session_request(service_name,
|
|
|
|
prefixed_label(name(), rom));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If there is neither an inline '<config>' nor a
|
|
|
|
* '<configfile>' node present, we apply the regular session
|
|
|
|
* routing to the "config" ROM request.
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check for the binary's ROM request
|
|
|
|
*
|
|
|
|
* The binary is requested as a ROM with the child's unique
|
|
|
|
* name ('Child_policy::binary_name' equals 'Child_policy::name').
|
|
|
|
* If the binary name differs from the child's unique name,
|
|
|
|
* we resolve the session request with the binary name as label.
|
|
|
|
* Otherwise the regular routing is applied.
|
|
|
|
*/
|
|
|
|
if (service_name == Rom_session::service_name() &&
|
|
|
|
label == _unique_name && _unique_name != _binary_name)
|
|
|
|
return resolve_session_request(service_name, _binary_name);
|
|
|
|
|
2018-07-04 16:48:04 +00:00
|
|
|
/* supply binary as dynamic linker if '<start ld="no">' */
|
|
|
|
if (!_use_ld && service_name == Rom_session::service_name() && label == "ld.lib.so")
|
|
|
|
return resolve_session_request(service_name, _binary_name);
|
|
|
|
|
2017-03-03 15:57:41 +00:00
|
|
|
/* check for "session_requests" ROM request */
|
|
|
|
if (service_name == Rom_session::service_name()
|
|
|
|
&& label.last_element() == Session_requester::rom_name())
|
Follow practices suggested by "Effective C++"
The patch adjust the code of the base, base-<kernel>, and os repository.
To adapt existing components to fix violations of the best practices
suggested by "Effective C++" as reported by the -Weffc++ compiler
argument. The changes follow the patterns outlined below:
* A class with virtual functions can no longer publicly inherit base
classed without a vtable. The inherited object may either be moved
to a member variable, or inherited privately. The latter would be
used for classes that inherit 'List::Element' or 'Avl_node'. In order
to enable the 'List' and 'Avl_tree' to access the meta data, the
'List' must become a friend.
* Instead of adding a virtual destructor to abstract base classes,
we inherit the new 'Interface' class, which contains a virtual
destructor. This way, single-line abstract base classes can stay
as compact as they are now. The 'Interface' utility resides in
base/include/util/interface.h.
* With the new warnings enabled, all member variables must be explicitly
initialized. Basic types may be initialized with '='. All other types
are initialized with braces '{ ... }' or as class initializers. If
basic types and non-basic types appear in a row, it is nice to only
use the brace syntax (also for basic types) and align the braces.
* If a class contains pointers as members, it must now also provide a
copy constructor and assignment operator. In the most cases, one
would make them private, effectively disallowing the objects to be
copied. Unfortunately, this warning cannot be fixed be inheriting
our existing 'Noncopyable' class (the compiler fails to detect that
the inheriting class cannot be copied and still gives the error).
For now, we have to manually add declarations for both the copy
constructor and assignment operator as private class members. Those
declarations should be prepended with a comment like this:
/*
* Noncopyable
*/
Thread(Thread const &);
Thread &operator = (Thread const &);
In the future, we should revisit these places and try to replace
the pointers with references. In the presence of at least one
reference member, the compiler would no longer implicitly generate
a copy constructor. So we could remove the manual declaration.
Issue #465
2017-12-21 14:42:15 +00:00
|
|
|
return Route { _session_requester.service(),
|
|
|
|
Session::Label(), Session::Diag{false} };
|
2017-03-03 15:57:41 +00:00
|
|
|
|
|
|
|
try {
|
|
|
|
Xml_node route_node = _default_route_accessor.default_route();
|
|
|
|
try {
|
|
|
|
route_node = _start_node->xml().sub_node("route"); }
|
|
|
|
catch (...) { }
|
|
|
|
Xml_node service_node = route_node.sub_node();
|
|
|
|
|
|
|
|
for (; ; service_node = service_node.next()) {
|
|
|
|
|
|
|
|
bool service_wildcard = service_node.has_type("any-service");
|
|
|
|
|
|
|
|
if (!service_node_matches(service_node, label, name(), service_name))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
Xml_node target = service_node.sub_node();
|
|
|
|
for (; ; target = target.next()) {
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Determine session label to be provided to the server
|
|
|
|
*
|
|
|
|
* By default, the client's identity (accompanied with the a
|
|
|
|
* client-provided label) is presented as session label to the
|
|
|
|
* server. However, the target node can explicitly override the
|
|
|
|
* client's identity by a custom label via the 'label'
|
|
|
|
* attribute.
|
|
|
|
*/
|
|
|
|
typedef String<Session_label::capacity()> Label;
|
|
|
|
Label const target_label =
|
|
|
|
target.attribute_value("label", Label(label.string()));
|
|
|
|
|
2017-05-08 17:45:47 +00:00
|
|
|
Session::Diag const
|
|
|
|
target_diag { target.attribute_value("diag", false) };
|
|
|
|
|
2017-08-15 12:42:20 +00:00
|
|
|
auto no_filter = [] (Service &) -> bool { return false; };
|
2017-03-03 15:57:41 +00:00
|
|
|
|
2017-08-15 12:42:20 +00:00
|
|
|
if (target.has_type("parent")) {
|
2017-03-03 15:57:41 +00:00
|
|
|
|
2017-08-15 12:42:20 +00:00
|
|
|
try {
|
|
|
|
return Route { find_service(_parent_services, service_name, no_filter),
|
|
|
|
target_label, target_diag };
|
|
|
|
} catch (Service_denied) { }
|
2017-03-03 15:57:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (target.has_type("child")) {
|
|
|
|
|
|
|
|
typedef Name_registry::Name Name;
|
|
|
|
Name server_name = target.attribute_value("name", Name());
|
|
|
|
server_name = _name_registry.deref_alias(server_name);
|
|
|
|
|
2017-08-15 12:42:20 +00:00
|
|
|
auto filter_server_name = [&] (Routed_service &s) -> bool {
|
|
|
|
return s.child_name() != server_name; };
|
2017-03-03 15:57:41 +00:00
|
|
|
|
2017-08-15 12:42:20 +00:00
|
|
|
try {
|
|
|
|
return Route { find_service(_child_services, service_name, filter_server_name),
|
|
|
|
target_label, target_diag };
|
2017-03-03 15:57:41 +00:00
|
|
|
|
2017-08-15 12:42:20 +00:00
|
|
|
} catch (Service_denied) { }
|
2017-03-03 15:57:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (target.has_type("any-child")) {
|
|
|
|
|
|
|
|
if (is_ambiguous(_child_services, service_name)) {
|
|
|
|
error(name(), ": ambiguous routes to "
|
|
|
|
"service \"", service_name, "\"");
|
Streamline exception types
This patch reduces the number of exception types by facilitating
globally defined exceptions for common usage patterns shared by most
services. In particular, RPC functions that demand a session-resource
upgrade not longer reflect this condition via a session-specific
exception but via the 'Out_of_ram' or 'Out_of_caps' types.
Furthermore, the 'Parent::Service_denied', 'Parent::Unavailable',
'Root::Invalid_args', 'Root::Unavailable', 'Service::Invalid_args',
'Service::Unavailable', and 'Local_service::Factory::Denied' types have
been replaced by the single 'Service_denied' exception type defined in
'session/session.h'.
This consolidation eases the error handling (there are fewer exceptions
to handle), alleviates the need to convert exceptions along the
session-creation call chain, and avoids possible aliasing problems
(catching the wrong type with the same name but living in a different
scope).
2017-05-07 20:03:22 +00:00
|
|
|
throw Service_denied();
|
2017-03-03 15:57:41 +00:00
|
|
|
}
|
2017-08-15 12:42:20 +00:00
|
|
|
try {
|
|
|
|
return Route { find_service(_child_services, service_name, no_filter),
|
|
|
|
target_label, target_diag };
|
2017-03-03 15:57:41 +00:00
|
|
|
|
2017-08-15 12:42:20 +00:00
|
|
|
} catch (Service_denied) { }
|
|
|
|
}
|
2017-03-03 15:57:41 +00:00
|
|
|
|
2017-08-15 12:42:20 +00:00
|
|
|
if (!service_wildcard) {
|
|
|
|
warning(name(), ": lookup for service \"", service_name, "\" failed");
|
|
|
|
throw Service_denied();
|
2017-03-03 15:57:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (target.last())
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (Xml_node::Nonexistent_sub_node) { }
|
|
|
|
|
2018-11-04 16:11:19 +00:00
|
|
|
warning(name(), ": no route to service \"", service_name, "\" (label=\"", label, "\")");
|
Streamline exception types
This patch reduces the number of exception types by facilitating
globally defined exceptions for common usage patterns shared by most
services. In particular, RPC functions that demand a session-resource
upgrade not longer reflect this condition via a session-specific
exception but via the 'Out_of_ram' or 'Out_of_caps' types.
Furthermore, the 'Parent::Service_denied', 'Parent::Unavailable',
'Root::Invalid_args', 'Root::Unavailable', 'Service::Invalid_args',
'Service::Unavailable', and 'Local_service::Factory::Denied' types have
been replaced by the single 'Service_denied' exception type defined in
'session/session.h'.
This consolidation eases the error handling (there are fewer exceptions
to handle), alleviates the need to convert exceptions along the
session-creation call chain, and avoids possible aliasing problems
(catching the wrong type with the same name but living in a different
scope).
2017-05-07 20:03:22 +00:00
|
|
|
throw Service_denied();
|
2017-03-03 15:57:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Init::Child::filter_session_args(Service::Name const &service,
|
|
|
|
char *args, size_t args_len)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Intercept CPU session requests to scale priorities
|
|
|
|
*/
|
2019-01-11 14:40:49 +00:00
|
|
|
if ((service == Cpu_session::service_name() ||
|
|
|
|
service == Vm_session::service_name())
|
|
|
|
&& _prio_levels_log2 > 0) {
|
2017-03-03 15:57:41 +00:00
|
|
|
|
|
|
|
unsigned long priority = Arg_string::find_arg(args, "priority").ulong_value(0);
|
|
|
|
|
|
|
|
/* clamp priority value to valid range */
|
|
|
|
priority = min((unsigned)Cpu_session::PRIORITY_LIMIT - 1, priority);
|
|
|
|
|
|
|
|
long discarded_prio_lsb_bits_mask = (1 << _prio_levels_log2) - 1;
|
|
|
|
if (priority & discarded_prio_lsb_bits_mask)
|
|
|
|
warning("priority band too small, losing least-significant priority bits");
|
|
|
|
|
|
|
|
priority >>= _prio_levels_log2;
|
|
|
|
|
|
|
|
/* assign child priority to the most significant priority bits */
|
|
|
|
priority |= _priority*(Cpu_session::PRIORITY_LIMIT >> _prio_levels_log2);
|
|
|
|
|
|
|
|
/* override priority when delegating the session request to the parent */
|
|
|
|
String<64> value { Hex(priority) };
|
|
|
|
Arg_string::set_arg(args, args_len, "priority", value.string());
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Remove phys_start and phys_size RAM-session arguments unless
|
|
|
|
* explicitly permitted by the child configuration.
|
|
|
|
*/
|
2017-05-26 14:41:01 +00:00
|
|
|
if (service == Pd_session::service_name()) {
|
2017-05-09 14:43:49 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If the child is allowed to constrain physical memory allocations,
|
|
|
|
* pass the child-provided constraints as session arguments to core.
|
|
|
|
* If no constraints are specified, we apply the constraints for
|
|
|
|
* allocating DMA memory (as the only use case for the constrain-phys
|
|
|
|
* mechanism).
|
|
|
|
*/
|
|
|
|
if (_constrain_phys) {
|
|
|
|
addr_t start = 0;
|
|
|
|
addr_t size = (sizeof(long) == 4) ? 0xc0000000UL : 0x100000000UL;
|
|
|
|
|
|
|
|
Arg_string::find_arg(args, "phys_start").ulong_value(start);
|
|
|
|
Arg_string::find_arg(args, "phys_size") .ulong_value(size);
|
|
|
|
|
|
|
|
Arg_string::set_arg(args, args_len, "phys_start", String<32>(Hex(start)).string());
|
|
|
|
Arg_string::set_arg(args, args_len, "phys_size", String<32>(Hex(size)) .string());
|
|
|
|
} else {
|
|
|
|
Arg_string::remove_arg(args, "phys_start");
|
|
|
|
Arg_string::remove_arg(args, "phys_size");
|
|
|
|
}
|
2017-03-03 15:57:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Genode::Affinity Init::Child::filter_session_affinity(Affinity const &session_affinity)
|
|
|
|
{
|
|
|
|
Affinity::Space const &child_space = _resources.affinity.space();
|
|
|
|
Affinity::Location const &child_location = _resources.affinity.location();
|
|
|
|
|
|
|
|
/* check if no valid affinity space was specified */
|
|
|
|
if (session_affinity.space().total() == 0)
|
|
|
|
return Affinity(child_space, child_location);
|
|
|
|
|
|
|
|
Affinity::Space const &session_space = session_affinity.space();
|
|
|
|
Affinity::Location const &session_location = session_affinity.location();
|
|
|
|
|
|
|
|
/* scale resolution of resulting space */
|
|
|
|
Affinity::Space space(child_space.multiply(session_space));
|
|
|
|
|
|
|
|
/* subordinate session affinity to child affinity subspace */
|
|
|
|
Affinity::Location location(child_location
|
|
|
|
.multiply_position(session_space)
|
|
|
|
.transpose(session_location.xpos(),
|
|
|
|
session_location.ypos()));
|
|
|
|
|
|
|
|
return Affinity(space, location);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Init::Child::announce_service(Service::Name const &service_name)
|
|
|
|
{
|
2017-12-13 19:14:46 +00:00
|
|
|
if (_verbose.enabled())
|
|
|
|
log("child \"", name(), "\" announces service \"", service_name, "\"");
|
2017-03-03 15:57:41 +00:00
|
|
|
|
|
|
|
bool found = false;
|
|
|
|
_child_services.for_each([&] (Routed_service &service) {
|
|
|
|
if (service.has_id_space(_session_requester.id_space())
|
|
|
|
&& service.name() == service_name)
|
|
|
|
found = true; });
|
|
|
|
|
|
|
|
if (!found)
|
|
|
|
error(name(), ": illegal announcement of "
|
|
|
|
"service \"", service_name, "\"");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Init::Child::resource_request(Parent::Resource_args const &args)
|
|
|
|
{
|
2017-03-06 17:04:10 +00:00
|
|
|
log("child \"", name(), "\" requests resources: ", args);
|
2017-03-03 15:57:41 +00:00
|
|
|
|
2017-03-06 17:04:10 +00:00
|
|
|
_requested_resources.construct(args);
|
2018-06-01 11:55:07 +00:00
|
|
|
_report_update_trigger.trigger_immediate_report_update();
|
2017-03-03 15:57:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Init::Child::Child(Env &env,
|
|
|
|
Allocator &alloc,
|
|
|
|
Verbose const &verbose,
|
|
|
|
Id id,
|
|
|
|
Report_update_trigger &report_update_trigger,
|
|
|
|
Xml_node start_node,
|
|
|
|
Default_route_accessor &default_route_accessor,
|
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 19:35:43 +00:00
|
|
|
Default_caps_accessor &default_caps_accessor,
|
2017-03-03 15:57:41 +00:00
|
|
|
Name_registry &name_registry,
|
2017-03-06 14:19:35 +00:00
|
|
|
Ram_quota ram_limit,
|
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 19:35:43 +00:00
|
|
|
Cap_quota cap_limit,
|
2017-03-03 15:57:41 +00:00
|
|
|
Ram_limit_accessor &ram_limit_accessor,
|
2018-06-04 13:49:29 +00:00
|
|
|
Cap_limit_accessor &cap_limit_accessor,
|
2017-03-06 14:42:30 +00:00
|
|
|
Prio_levels prio_levels,
|
2017-03-03 15:57:41 +00:00
|
|
|
Affinity::Space const &affinity_space,
|
|
|
|
Registry<Parent_service> &parent_services,
|
|
|
|
Registry<Routed_service> &child_services)
|
|
|
|
:
|
|
|
|
_env(env), _alloc(alloc), _verbose(verbose), _id(id),
|
|
|
|
_report_update_trigger(report_update_trigger),
|
|
|
|
_list_element(this),
|
|
|
|
_start_node(_alloc, start_node),
|
|
|
|
_default_route_accessor(default_route_accessor),
|
2018-06-04 13:49:29 +00:00
|
|
|
_default_caps_accessor(default_caps_accessor),
|
2017-03-03 15:57:41 +00:00
|
|
|
_ram_limit_accessor(ram_limit_accessor),
|
2018-06-04 13:49:29 +00:00
|
|
|
_cap_limit_accessor(cap_limit_accessor),
|
2017-03-03 15:57:41 +00:00
|
|
|
_name_registry(name_registry),
|
2018-11-14 15:19:30 +00:00
|
|
|
_heartbeat_enabled(start_node.has_sub_node("heartbeat")),
|
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 19:35:43 +00:00
|
|
|
_resources(_resources_from_start_node(start_node, prio_levels, affinity_space,
|
|
|
|
default_caps_accessor.default_caps(), cap_limit)),
|
2018-06-04 13:49:29 +00:00
|
|
|
_resources_clamped_to_limit((_clamp_resources(ram_limit, cap_limit), true)),
|
2017-03-03 15:57:41 +00:00
|
|
|
_parent_services(parent_services),
|
|
|
|
_child_services(child_services),
|
|
|
|
_session_requester(_env.ep().rpc_ep(), _env.ram(), _env.rm())
|
|
|
|
{
|
|
|
|
if (_verbose.enabled()) {
|
|
|
|
log("child \"", _unique_name, "\"");
|
2017-05-07 23:33:40 +00:00
|
|
|
log(" RAM quota: ", _resources.effective_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 19:35:43 +00:00
|
|
|
log(" cap quota: ", _resources.effective_cap_quota());
|
2017-03-03 15:57:41 +00:00
|
|
|
log(" ELF binary: ", _binary_name);
|
|
|
|
log(" priority: ", _resources.priority);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Determine services provided by the child
|
|
|
|
*/
|
|
|
|
_provides_sub_node(start_node)
|
|
|
|
.for_each_sub_node("service",
|
|
|
|
[&] (Xml_node node) { _add_service(node); });
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Construct inline config ROM service if "config" node is present.
|
|
|
|
*/
|
|
|
|
if (start_node.has_sub_node("config"))
|
|
|
|
_config_rom_service.construct(*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-05-22 09:32:36 +00:00
|
|
|
Init::Child::~Child() { }
|