diff --git a/repos/os/include/init/child.h b/repos/os/include/init/child.h
deleted file mode 100644
index 530f78b28b..0000000000
--- a/repos/os/include/init/child.h
+++ /dev/null
@@ -1,1323 +0,0 @@
-/*
- * \brief Representation used for children of the init process
- * \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.
- */
-
-#ifndef _INCLUDE__INIT__CHILD_H_
-#define _INCLUDE__INIT__CHILD_H_
-
-/* Genode includes */
-#include
-#include
-#include
-#include
-
-/* init includes */
-#include
-#include
-#include
-
-namespace Init {
-
- class Abandonable;
- class Parent_service;
- class Buffered_xml;
- class Routed_service;
- class Name_registry;
- class Child_registry;
- class Child;
-
- using namespace Genode;
- using Genode::size_t;
- using Genode::strlen;
-
- struct Ram_quota { size_t value; };
-}
-
-
-/***************
- ** Utilities **
- ***************/
-
-namespace Init {
-
- static void warn_insuff_quota(size_t const avail)
- {
- warning("specified quota exceeds available quota, "
- "proceeding with a quota of ", avail);
- }
-
- inline long read_priority(Xml_node start_node, long prio_levels)
- {
- long priority = Cpu_session::DEFAULT_PRIORITY;
- try { start_node.attribute("priority").value(&priority); }
- catch (...) { }
-
- /*
- * All priority declarations in the config file are
- * negative because child priorities can never be higher
- * than parent priorities. To simplify priority
- * calculations, we use inverted values. Lower values
- * correspond to higher priorities.
- */
- priority = -priority;
-
- if (priority && (priority >= prio_levels)) {
- long new_prio = prio_levels ? prio_levels-1 : 0;
- char name[Service::Name::capacity()];
- start_node.attribute("name").value(name, sizeof(name));
- warning(Cstring(name), ": invalid priority, upgrading "
- "from ", -priority, " to ", -new_prio);
- return new_prio;
- }
-
- return priority;
- }
-
-
- inline Affinity::Location
- read_affinity_location(Affinity::Space const &space,
- Xml_node start_node)
- {
- typedef Affinity::Location Location;
- try {
- Xml_node node = start_node.sub_node("affinity");
-
- /* if no position value is specified, select the whole row/column */
- unsigned long const
- default_width = node.has_attribute("xpos") ? 1 : space.width(),
- default_height = node.has_attribute("ypos") ? 1 : space.height();
-
- unsigned long const
- width = node.attribute_value("width", default_width),
- height = node.attribute_value("height", default_height);
-
- long const x1 = node.attribute_value("xpos", 0),
- y1 = node.attribute_value("ypos", 0),
- x2 = x1 + width - 1,
- y2 = y1 + height - 1;
-
- /* clip location to space boundary */
- return Location(max(x1, 0L), max(y1, 0L),
- min((unsigned)(x2 - x1 + 1), space.width()),
- min((unsigned)(y2 - y1 + 1), space.height()));
- }
- catch (...) { return Location(0, 0, space.width(), space.height()); }
- }
-
- /**
- * Return sub string of label with the leading child name stripped out
- *
- * \return character pointer to the scoped part of the label,
- * or nullptr if the label is not correctly prefixed with the child's
- * name
- */
- inline char const *skip_label_prefix(char const *child_name, char const *label)
- {
- size_t const child_name_len = strlen(child_name);
-
- if (strcmp(child_name, label, child_name_len) != 0)
- return nullptr;
-
- label += child_name_len;
-
- /*
- * Skip label separator. This condition should be always satisfied.
- */
- if (strcmp(" -> ", label, 4) != 0)
- return nullptr;
-
- return label + 4;
- }
-
-
- /**
- * Return true if service XML node matches service request
- *
- * \param args session arguments, inspected for the session label
- * \param child_name name of the originator of the session request
- * \param service_name name of the requested service
- */
- inline bool service_node_matches(Xml_node const service_node,
- Session_label const &label,
- Child_policy::Name const &child_name,
- Service::Name const &service_name)
- {
- bool const service_matches =
- service_node.has_type("any-service") ||
- (service_node.has_type("service") &&
- service_node.attribute("name").has_value(service_name.string()));
-
- if (!service_matches)
- return false;
-
- bool const route_depends_on_child_provided_label =
- service_node.has_attribute("label") ||
- service_node.has_attribute("label_prefix") ||
- service_node.has_attribute("label_suffix");
-
- char const *unscoped_attr = "unscoped_label";
- if (service_node.has_attribute(unscoped_attr)) {
-
- /*
- * If an 'unscoped_label' attribute is provided, don't consider any
- * scoped label attribute.
- */
- if (route_depends_on_child_provided_label)
- warning("service node contains both scoped and unscoped label attributes");
-
- typedef String Label;
- return label == service_node.attribute_value(unscoped_attr, Label());
- }
-
- if (!route_depends_on_child_provided_label)
- return true;
-
- char const * const scoped_label = skip_label_prefix(
- child_name.string(), label.string());
-
- if (!scoped_label)
- return false;
-
- Session_label const session_label(scoped_label);
-
- return !Xml_node_label_score(service_node, session_label).conflict();
- }
-
-
- /**
- * Check if service name is ambiguous
- *
- * \return true if the same service is provided multiple
- * times
- *
- * \deprecated
- */
- template
- inline bool is_ambiguous(Registry const &services,
- Service::Name const &name)
- {
- /* count number of services with the specified name */
- unsigned cnt = 0;
- services.for_each([&] (T const &service) {
- cnt += (service.name() == name); });
-
- return cnt > 1;
- }
-
-
- template
- inline T *find_service(Registry &services,
- Service::Name const &name)
- {
- T *service = nullptr;
- services.for_each([&] (T &s) {
- if (!service && (s.name() == name))
- service = &s; });
- return service;
- }
-
-
- inline void generate_ram_info(Xml_generator &xml, Ram_session const &ram)
- {
- /*
- * The const cast is needed because the 'Ram_session' accessors are
- * non-const methods.
- */
- Ram_session &ram_nonconst = const_cast(ram);
-
- typedef String<32> Value;
- xml.attribute("quota", Value(Number_of_bytes(ram_nonconst.quota())));
- xml.attribute("used", Value(Number_of_bytes(ram_nonconst.used())));
- xml.attribute("avail", Value(Number_of_bytes(ram_nonconst.avail())));
- }
-}
-
-
-class Init::Abandonable
-{
- private:
-
- bool _abandoned = false;
-
- public:
-
- void abandon() { _abandoned = true; }
-
- bool abandoned() const { return _abandoned; }
-};
-
-
-class Init::Parent_service : public Genode::Parent_service, public Abandonable
-{
- private:
-
- Registry::Element _reg_elem;
-
- public:
-
- Parent_service(Registry ®istry, Env &env,
- Service::Name const &name)
- :
- Genode::Parent_service(env, name), _reg_elem(registry, *this)
- { }
-};
-
-
-class Init::Buffered_xml
-{
- private:
-
- Allocator &_alloc;
- char const * const _ptr; /* pointer to dynamically allocated buffer */
- Xml_node const _xml; /* referring to buffer of '_ptr' */
-
- /**
- * \throw Allocator::Out_of_memory
- */
- static char const *_init_ptr(Allocator &alloc, Xml_node node)
- {
- char *ptr = (char *)alloc.alloc(node.size());
- Genode::memcpy(ptr, node.addr(), node.size());
- return ptr;
- }
-
- public:
-
- /**
- * Constructor
- *
- * \throw Allocator::Out_of_memory
- */
- Buffered_xml(Allocator &alloc, Xml_node node)
- :
- _alloc(alloc), _ptr(_init_ptr(alloc, node)), _xml(_ptr, node.size())
- { }
-
- ~Buffered_xml() { _alloc.free(const_cast(_ptr), _xml.size()); }
-
- Xml_node xml() const { return _xml; }
-};
-
-
-/**
- * Init-specific representation of a child service
- */
-class Init::Routed_service : public Child_service, public Abandonable
-{
- public:
-
- typedef Child_policy::Name Child_name;
-
- struct Ram_accessor { virtual Ram_session_capability ram() const = 0; };
-
- private:
-
- Child_name _child_name;
-
- Ram_accessor &_ram_accessor;
-
- Registry::Element _registry_element;
-
- public:
-
- /**
- * Constructor
- *
- * \param services registry of all services provides by children
- * \param child_name child name of server, used for session routing
- *
- * The other arguments correspond to the arguments of 'Child_service'.
- */
- Routed_service(Registry &services,
- Child_name const &child_name,
- Ram_accessor &ram_accessor,
- Id_space &server_id_space,
- Session_state::Factory &factory,
- Service::Name const &name,
- Child_service::Wakeup &wakeup)
- :
- Child_service(server_id_space, factory, name,
- Ram_session_capability(), wakeup),
- _child_name(child_name), _ram_accessor(ram_accessor),
- _registry_element(services, *this)
- { }
-
- Child_name const &child_name() const { return _child_name; }
-
- Ram_session_capability ram() const { return _ram_accessor.ram(); }
-};
-
-
-/**
- * Interface for name database
- */
-struct Init::Name_registry
-{
- virtual ~Name_registry() { }
-
- typedef Child_policy::Name Name;
-
- /**
- * Check if specified name is unique
- *
- * \return false if name already exists
- */
- virtual bool unique(const char *name) const = 0;
-
- /**
- * Return child name for a given alias name
- *
- * If there is no alias, the function returns the original name.
- */
- virtual Name deref_alias(Name const &) = 0;
-};
-
-
-class Init::Child : Child_policy, Child_service::Wakeup
-{
- public:
-
- /**
- * Exception types
- */
- struct Child_name_is_not_unique : Exception { };
- struct Missing_name_attribute : Exception { };
-
- /**
- * Unique ID of the child, solely used for diagnostic purposes
- */
- struct Id { unsigned value; };
-
- struct Default_route_accessor { virtual Xml_node default_route() = 0; };
-
- struct Ram_limit_accessor { virtual Ram_quota ram_limit() = 0; };
-
- private:
-
- friend class Child_registry;
-
- Env &_env;
-
- Allocator &_alloc;
-
- Verbose const &_verbose;
-
- Id const _id;
-
- enum State { STATE_INITIAL, STATE_RAM_INITIALIZED, STATE_ALIVE,
- STATE_ABANDONED };
-
- State _state = STATE_INITIAL;
-
- Report_update_trigger &_report_update_trigger;
-
- List_element _list_element;
-
- Reconstructible _start_node;
-
- /*
- * Version attribute of the start node, used to force child restarts.
- */
- typedef String<80> Version;
- Version _version { _start_node->xml().attribute_value("version", Version()) };
-
- Default_route_accessor &_default_route_accessor;
-
- Ram_limit_accessor &_ram_limit_accessor;
-
- Name_registry &_name_registry;
-
- typedef String<64> Name;
-
- struct Unique_name : Name
- {
- /**
- * Read name from XML and check for name confict with other children
- *
- * \throw Missing_name_attribute
- */
- static Name _checked(Xml_node start_node, Name_registry const ®istry)
- {
- Name const name = start_node.attribute_value("name", Name());
- if (!name.valid()) {
- warning("missing 'name' attribute in '' entry");
- throw Missing_name_attribute();
- }
-
- if (registry.unique(name.string()))
- return name;
-
- error("child name \"", name, "\" is not unique");
- throw Child_name_is_not_unique();
- }
-
- /**
- * Constructor
- *
- * Obtains file name and unique process name from XML node
- *
- * \param start_node XML start node
- * \param registry registry tracking unique names
- *
- * \throw Missing_name_attribute
- */
- Unique_name(Xml_node start_node, Name_registry const ®istry)
- : Name(_checked(start_node, registry)) { }
-
- } _unique_name;
-
- static Binary_name _binary_name_from_xml(Xml_node start_node,
- Unique_name const &unique_name)
- {
- if (!start_node.has_sub_node("binary"))
- return unique_name;
-
- return start_node.sub_node("binary").attribute_value("name", Name());
- }
-
- /* updated on configuration update */
- Binary_name _binary_name;
-
- struct Read_quota
- {
- Read_quota(Xml_node start_node,
- size_t &ram_quota,
- size_t &cpu_quota_pc,
- bool &constrain_phys,
- Ram_quota const ram_limit,
- Verbose const &verbose)
- {
- cpu_quota_pc = 0;
- constrain_phys = false;
-
- Number_of_bytes ram_bytes = 0;
-
- try {
- Xml_node rsc = start_node.sub_node("resource");
- for (;; rsc = rsc.next("resource")) {
- try {
- if (rsc.attribute("name").has_value("RAM")) {
- rsc.attribute("quantum").value(&ram_bytes);
- constrain_phys = rsc.attribute_value("constrain_phys", false);
- } else if (rsc.attribute("name").has_value("CPU")) {
- rsc.attribute("quantum").value(&cpu_quota_pc); }
- } catch (...) { }
- }
- } catch (...) { }
- ram_quota = ram_bytes;
-
- /*
- * If the configured RAM quota exceeds our own quota, we donate
- * all remaining quota to the child.
- */
- if (ram_quota > ram_limit.value) {
- ram_quota = ram_limit.value;
-
- if (verbose.enabled())
- warn_insuff_quota(ram_limit.value);
- }
- }
- };
-
- /**
- * Resources assigned to the child
- */
- struct Resources : Read_quota
- {
- long prio_levels_log2;
- long priority;
- Affinity affinity;
- size_t assigned_ram_quota;
- size_t effective_ram_quota;
- size_t cpu_quota_pc;
- bool constrain_phys;
-
- Resources(Xml_node start_node, long prio_levels,
- Affinity::Space const &affinity_space, Ram_quota ram_limit,
- Verbose const &verbose)
- :
- Read_quota(start_node, assigned_ram_quota, cpu_quota_pc,
- constrain_phys, ram_limit, verbose),
- prio_levels_log2(log2(prio_levels)),
- priority(read_priority(start_node, prio_levels)),
- affinity(affinity_space,
- read_affinity_location(affinity_space, start_node))
- {
- effective_ram_quota = Genode::Child::effective_ram_quota(assigned_ram_quota);
- }
- } _resources;
-
- Genode::Parent_service _env_ram_service { _env, Ram_session::service_name() };
- Genode::Parent_service _env_cpu_service { _env, Cpu_session::service_name() };
- Genode::Parent_service _env_pd_service { _env, Pd_session::service_name() };
- Genode::Parent_service _env_log_service { _env, Log_session::service_name() };
- Genode::Parent_service _env_rom_service { _env, Rom_session::service_name() };
-
- Registry &_parent_services;
- Registry &_child_services;
-
- struct Inline_config_rom_service : Abandonable, Dynamic_rom_session::Content_producer
- {
- typedef Local_service Service;
-
- Child &_child;
-
- Dynamic_rom_session _session { _child._env.ep().rpc_ep(),
- _child.ref_ram(), _child._env.rm(),
- *this };
-
- Service::Single_session_factory _factory { _session };
- Service _service { _factory };
-
- Inline_config_rom_service(Child &child) : _child(child) { }
-
- /**
- * Dynamic_rom_session::Content_producer interface
- */
- void produce_content(char *dst, Genode::size_t dst_len) override
- {
- Xml_node config = _child._start_node->xml().has_sub_node("config")
- ? _child._start_node->xml().sub_node("config")
- : Xml_node("");
-
- size_t const config_len = config.size();
-
- if (config_len + 1 /* null termination */ >= dst_len)
- throw Buffer_capacity_exceeded();
-
- /*
- * The 'config.size()' method returns the number of bytes of
- * the config-node content, which is not null-terminated. Since
- * 'Genode::strncpy' always null-terminates the result, the
- * last byte of the source string is not copied. Hence, it is
- * safe to add '1' to 'config_len' and thereby include the
- * last actual config-content character in the result.
- */
- Genode::strncpy(dst, config.addr(), config_len + 1);
- }
-
- void trigger_update() { _session.trigger_update(); }
-
- Service &service() { return _service; }
- };
-
- Constructible _config_rom_service;
-
- Session_requester _session_requester;
-
- /**
- * Policy helpers
- */
- Init::Child_policy_handle_cpu_priorities _priority_policy;
- Init::Child_policy_ram_phys _ram_session_policy;
-
- Genode::Child _child { _env.rm(), _env.ep().rpc_ep(), *this };
-
- struct Ram_accessor : Routed_service::Ram_accessor
- {
- Genode::Child &_child;
- Ram_accessor(Genode::Child &child) : _child(child) { }
- Ram_session_capability ram() const override {
- return _child.ram_session_cap(); }
- } _ram_accessor { _child };
-
- /**
- * Child_service::Wakeup callback
- */
- void wakeup_child_service() override
- {
- _session_requester.trigger_update();
- }
-
- /**
- * Return true if the policy results in the current route of the session
- *
- * This method is used to check if a policy change affects an existing
- * client session of a child, i.e., to determine whether the child must
- * be restarted.
- */
- bool _route_valid(Session_state const &session)
- {
- try {
- Route const route =
- resolve_session_request(session.service().name(),
- session.client_label());
-
- return (session.service() == route.service)
- && (route.label == session.label());
- }
- catch (Parent::Service_denied) { return false; }
- }
-
- static Xml_node _provides_sub_node(Xml_node start_node)
- {
- return start_node.has_sub_node("provides")
- ? start_node.sub_node("provides") : Xml_node("");
- }
-
- /**
- * Return true if service is provided by this child
- */
- bool _provided_by_this(Routed_service const &service)
- {
- return service.has_id_space(_session_requester.id_space());
- }
-
- /**
- * Return true if service of specified sub node is known
- */
- bool _service_exists(Xml_node node) const
- {
- bool exists = false;
- _child_services.for_each([&] (Routed_service const &service) {
- if (_provided_by_this(service) &&
- service.name() == node.attribute_value("name", Service::Name()))
- exists = true; });
-
- return exists;
- }
-
- void _add_service(Xml_node service)
- {
- Service::Name const name =
- service.attribute_value("name", Service::Name());
-
- if (_verbose.enabled())
- log(" provides service ", name);
-
- new (_alloc)
- Routed_service(_child_services, this->name(), _ram_accessor,
- _session_requester.id_space(),
- _child.session_factory(),
- name, *this);
- }
-
- public:
-
- /**
- * Constructor
- *
- * \param alloc allocator solely used for configuration-dependent
- * allocations. It is not used for allocations on behalf
- * of the child's behavior.
- *
- *
- * \throw Ram_session::Alloc_failed allocation of config buffer failed
- * \throw Region_map::Attach_failed failed to temporarily attach
- * config dataspace to local address
- * space
- * \throw Allocator::Out_of_memory could not buffer the XML start node
- */
- 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,
- Name_registry &name_registry,
- Ram_limit_accessor &ram_limit_accessor,
- long prio_levels,
- Affinity::Space const &affinity_space,
- Registry &parent_services,
- Registry &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),
- _ram_limit_accessor(ram_limit_accessor),
- _name_registry(name_registry),
- _unique_name(start_node, name_registry),
- _binary_name(_binary_name_from_xml(start_node, _unique_name)),
- _resources(start_node, prio_levels, affinity_space,
- ram_limit_accessor.ram_limit(), _verbose),
- _parent_services(parent_services),
- _child_services(child_services),
- _session_requester(_env.ep().rpc_ep(), _env.ram(), _env.rm()),
- _priority_policy(_resources.prio_levels_log2, _resources.priority),
- _ram_session_policy(_resources.constrain_phys)
- {
- if (_resources.effective_ram_quota == 0)
- warning("no valid RAM resource for child "
- "\"", _unique_name, "\"");
-
- if (_verbose.enabled()) {
- log("child \"", _unique_name, "\"");
- log(" RAM quota: ", _resources.effective_ram_quota);
- 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);
- }
-
- virtual ~Child()
- {
- _child_services.for_each([&] (Routed_service &service) {
- if (service.has_id_space(_session_requester.id_space()))
- destroy(_alloc, &service); });
- }
-
- /**
- * Return true if the child has the specified name
- */
- bool has_name(Child_policy::Name const &str) const { return str == name(); }
-
- Ram_quota ram_quota() const { return Ram_quota { _resources.assigned_ram_quota }; }
-
- void initiate_env_ram_session()
- {
- if (_state == STATE_INITIAL) {
- _child.initiate_env_ram_session();
- _state = STATE_RAM_INITIALIZED;
- }
- }
-
- void initiate_env_sessions()
- {
- if (_state == STATE_RAM_INITIALIZED) {
-
- _child.initiate_env_sessions();
-
- /* check for completeness of the child's environment */
- if (_verbose.enabled())
- _child.for_each_session([&] (Session_state const &session) {
- if (!session.alive())
- warning(name(), ": incomplete environment ",
- session.service().name(), " session "
- "(", session.label(), ")"); });
-
- _state = STATE_ALIVE;
- }
- }
-
- void abandon()
- {
- _state = STATE_ABANDONED;
-
- _child_services.for_each([&] (Routed_service &service) {
- if (service.has_id_space(_session_requester.id_space()))
- service.abandon(); });
- }
-
- bool abandoned() const { return _state == STATE_ABANDONED; }
-
- enum Apply_config_result { MAY_HAVE_SIDE_EFFECTS, NO_SIDE_EFFECTS };
-
- /**
- * Apply new configuration to child
- *
- * \throw Allocator::Out_of_memory unable to allocate buffer for new
- * config
- */
- Apply_config_result apply_config(Xml_node start_node)
- {
- Child_policy &policy = *this;
-
- if (_state == STATE_ABANDONED)
- return NO_SIDE_EFFECTS;
-
- /*
- * If the child's environment is incomplete, restart it to attempt
- * the re-routing of its environment sessions.
- */
- if (!_child.active()) {
- abandon();
- return MAY_HAVE_SIDE_EFFECTS;
- }
-
- bool provided_services_changed = false;
-
- enum Config_update { CONFIG_APPEARED, CONFIG_VANISHED,
- CONFIG_CHANGED, CONFIG_UNCHANGED };
-
- Config_update config_update = CONFIG_UNCHANGED;
-
- /* import new start node if new version differs */
- if (start_node.size() != _start_node->xml().size() ||
- Genode::memcmp(start_node.addr(), _start_node->xml().addr(),
- start_node.size()) != 0)
- {
- /*
- * Check for a change of the version attribute, force restart
- * if the version changed.
- */
- if (_version != start_node.attribute_value("version", Version())) {
- abandon();
- return MAY_HAVE_SIDE_EFFECTS;
- }
-
- /*
- * 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) {
-
- Xml_node old_config = _start_node->xml().sub_node(tag);
- Xml_node new_config = start_node.sub_node(tag);
-
- if (Genode::memcmp(old_config.addr(), new_config.addr(),
- min(old_config.size(), new_config.size())))
- config_update = CONFIG_CHANGED;
- }
-
- /*
- * Import updated node
- *
- * First abandon services that are no longer present in the
- * 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_name_from_xml(start_node, _unique_name);
-
- /* 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;
- }
-
- void report_state(Xml_generator &xml, Report_detail const &detail) const
- {
- 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");
-
- if (detail.child_ram() && _child.ram_session_cap().valid()) {
- xml.node("ram", [&] () {
- /*
- * The const cast is needed because there is no const
- * accessor for the RAM session of the child.
- */
- auto &nonconst_child = const_cast(_child);
- generate_ram_info(xml, nonconst_child.ram());
- });
- }
-
- 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); }); };
-
- server_id_space().for_each(fn);
- });
- }
- });
- }
-
-
- /****************************
- ** Child-policy interface **
- ****************************/
-
- Child_policy::Name name() const override { return _unique_name; }
-
- Binary_name binary_name() const override { return _unique_name; }
-
- Ram_session &ref_ram() override { return _env.ram(); }
- Ram_session_capability ref_ram_cap() const override { return _env.ram_session_cap(); }
-
- void init(Ram_session &session, Ram_session_capability cap) override
- {
- session.ref_account(_env.ram_session_cap());
-
- size_t const initial_session_costs =
- session_alloc_batch_size()*_child.session_factory().session_costs();
-
- size_t const transfer_ram = _resources.effective_ram_quota > initial_session_costs
- ? _resources.effective_ram_quota - initial_session_costs
- : 0;
- if (transfer_ram)
- _env.ram().transfer_quota(cap, transfer_ram);
- }
-
- void init(Cpu_session &session, Cpu_session_capability cap) override
- {
- 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);
- }
-
- Id_space &server_id_space() override {
- return _session_requester.id_space(); }
-
- Route resolve_session_request(Service::Name const &service_name,
- Session_label const &label) override
- {
- /* 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())
- return Route { _config_rom_service->service(), label };
-
- /*
- * \deprecated the support for the 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'");
- throw Parent::Service_denied();
- }
-
- return resolve_session_request(service_name,
- prefixed_label(name(), rom));
- }
-
- /*
- * If there is neither an inline '' nor a
- * '' 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);
-
- /* check for "session_requests" ROM request */
- if (service_name == Rom_session::service_name()
- && label.last_element() == Session_requester::rom_name())
- return Route { _session_requester.service() };
-
- 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 Label;
- Label const target_label =
- target.attribute_value("label", Label(label.string()));
-
- if (target.has_type("parent")) {
-
- Parent_service *service = nullptr;
-
- if ((service = find_service(_parent_services, service_name)))
- return Route { *service, target_label };
-
- if (service && service->abandoned())
- throw Parent::Service_denied();
-
- if (!service_wildcard) {
- warning(name(), ": service lookup for "
- "\"", service_name, "\" at parent failed");
- throw Parent::Service_denied();
- }
- }
-
- 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);
-
- Routed_service *service = nullptr;
-
- _child_services.for_each([&] (Routed_service &s) {
- if (s.name() == Service::Name(service_name)
- && s.child_name() == server_name)
- service = &s; });
-
- if (service && service->abandoned())
- throw Parent::Service_denied();
-
- if (service)
- return Route { *service, target_label };
-
- if (!service_wildcard) {
- warning(name(), ": lookup to child "
- "server \"", server_name, "\" failed");
- throw Parent::Service_denied();
- }
- }
-
- if (target.has_type("any-child")) {
-
- if (is_ambiguous(_child_services, service_name)) {
- error(name(), ": ambiguous routes to "
- "service \"", service_name, "\"");
- throw Parent::Service_denied();
- }
-
- Routed_service *service = nullptr;
-
- if ((service = find_service(_child_services, service_name)))
- return Route { *service, target_label };
-
- if (!service_wildcard) {
- warning(name(), ": lookup for service "
- "\"", service_name, "\" failed");
- throw Parent::Service_denied();
- }
- }
-
- if (target.last())
- break;
- }
- }
- } catch (Xml_node::Nonexistent_sub_node) { }
-
- warning(name(), ": no route to service \"", service_name, "\"");
- throw Parent::Service_denied();
- }
-
- void filter_session_args(Service::Name const &service,
- char *args, size_t args_len) override
- {
- _priority_policy. filter_session_args(service.string(), args, args_len);
- _ram_session_policy.filter_session_args(service.string(), args, args_len);
- }
-
- Affinity filter_session_affinity(Affinity const &session_affinity) override
- {
- 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 announce_service(Service::Name const &service_name) override
- {
- log("child \"", name(), "\" announces service \"", service_name, "\"");
-
- 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 resource_request(Parent::Resource_args const &args) override
- {
- log("child \"", name(), "\" requests resources: ", args.string());
-
- size_t const requested_ram_quota =
- Arg_string::find_arg(args.string(), "ram_quota")
- .ulong_value(0);
-
- if (_ram_limit_accessor.ram_limit().value < requested_ram_quota) {
- warning("cannot respond to resource request - out of memory");
- return;
- }
-
- _env.ram().transfer_quota(_child.ram_session_cap(),
- requested_ram_quota);
-
- /* wake up child that was starved for resources */
- _child.notify_resource_avail();
- }
-
- void exit(int exit_value) override
- {
- try {
- if (_start_node->xml().sub_node("exit").attribute_value("propagate", false)) {
- _env.parent().exit(exit_value);
- return;
- }
- } catch (...) { }
-
- /*
- * Print a message as the exit is not handled otherwise. There are
- * a number of automated tests that rely on this message. It is
- * printed by the default implementation of 'Child_policy::exit'.
- */
- Child_policy::exit(exit_value);
- }
-
- void session_state_changed() override
- {
- _report_update_trigger.trigger_report_update();
- }
-
- bool initiate_env_sessions() const override { return false; }
-};
-
-#endif /* _INCLUDE__INIT__CHILD_H_ */
diff --git a/repos/os/include/init/child_config.h b/repos/os/include/init/child_config.h
deleted file mode 100644
index 4987232dbf..0000000000
--- a/repos/os/include/init/child_config.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * \brief Utility for handling child configuration
- * \author Norman Feske
- * \date 2008-03-22
- */
-
-/*
- * Copyright (C) 2008-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.
- */
-
-#ifndef _INCLUDE__INIT__CHILD_CONFIG_H_
-#define _INCLUDE__INIT__CHILD_CONFIG_H_
-
-#warning header is deprecated, used os/dynamic_rom_session.h instead
-
-#include
-#include
-#include
-
-namespace Init { class Child_config; }
-
-
-class Init::Child_config
-{
- private:
-
- Genode::Ram_session &_ram;
-
- typedef Genode::String<64> Rom_name;
- Rom_name const _rom_name;
-
- Genode::Ram_dataspace_capability const _ram_ds;
-
- Rom_name _rom_name_from_start_node(Genode::Xml_node start)
- {
- if (!start.has_sub_node("configfile"))
- return Rom_name();
-
- return start.sub_node("configfile").attribute_value("name", Rom_name());
- }
-
- /**
- * Buffer '' sub node in a dedicated RAM dataspace
- *
- * \throw Ram_session::Alloc_failed
- * \throw Rm_session::Attach_failed
- */
- Genode::Ram_dataspace_capability
- _ram_ds_from_start_node(Genode::Xml_node start,
- Genode::Ram_session &ram, Genode::Region_map &rm)
- {
- /*
- * If the start node contains a 'config' entry, we copy this entry
- * into a fresh dataspace to be provided to our child.
- */
- Genode::Xml_node const config = start.has_sub_node("config")
- ? start.sub_node("config")
- : Genode::Xml_node("");
-
- Genode::Ram_dataspace_capability ram_ds;
- try {
- /*
- * Allocate RAM dataspace that is big enough to hold the
- * configuration and the null termination.
- */
- ram_ds = ram.alloc(config.size() + 1);
-
- /*
- * Make dataspace locally accessible, copy configuration into the
- * dataspace, and append a string-terminating zero.
- */
- Genode::Attached_dataspace attached(rm, ram_ds);
-
- Genode::memcpy(attached.local_addr(),
- config.addr(), config.size());
-
- attached.local_addr()[config.size()] = 0;
-
- return ram_ds;
- }
- catch (Genode::Region_map::Attach_failed) { ram.free(ram_ds); throw; }
- }
-
- public:
-
- /**
- * Constructor
- *
- * The provided RAM session is used to obtain a dataspace for
- * holding the copy of the child's configuration data unless the
- * configuration is supplied via a config ROM module.
- *
- * \throw Ram_session::Alloc_failed failed to allocate the backing
- * store for holding config data
- *
- * \throw Region_map::Attach_failed failed to temporarily attach the
- * config dataspace to the local
- * address space
- *
- * If the start node contains a 'filename' entry, we only keep the
- * information about the ROM module name.
- */
- Child_config(Genode::Ram_session &ram, Genode::Region_map &local_rm,
- Genode::Xml_node start)
- :
- _ram(ram),
- _rom_name(_rom_name_from_start_node(start)),
- _ram_ds(_rom_name.valid() ? Genode::Ram_dataspace_capability()
- : _ram_ds_from_start_node(start, ram, local_rm))
- { }
-
- /**
- * Destructor
- */
- ~Child_config() { if (_ram_ds.valid()) _ram.free(_ram_ds); }
-
- /**
- * Return file name if configuration comes from a file
- *
- * If the configuration is provided inline, the method returns 0.
- */
- char const *filename() const {
- return _rom_name.valid() ? _rom_name.string() : nullptr; }
-
- /**
- * Request dataspace holding the start node's configuration data
- *
- * This method returns a valid dataspace only when using an
- * inline configuration (if 'filename()' returns 0).
- */
- Genode::Dataspace_capability dataspace() {
- return Genode::Dataspace_capability(_ram_ds); }
-};
-
-#endif /* _INCLUDE__INIT__CHILD_CONFIG_H_ */
diff --git a/repos/os/src/init/alias.h b/repos/os/src/init/alias.h
new file mode 100644
index 0000000000..89f07df225
--- /dev/null
+++ b/repos/os/src/init/alias.h
@@ -0,0 +1,53 @@
+/*
+ * \brief Representation of an alias for a child
+ * \author Norman Feske
+ * \date 2010-04-27
+ */
+
+/*
+ * 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.
+ */
+
+#ifndef _SRC__INIT__ALIAS_H_
+#define _SRC__INIT__ALIAS_H_
+
+/* local includes */
+#include
+
+namespace Init { struct Alias; }
+
+struct Init::Alias : List::Element
+{
+ typedef String<128> Name;
+ typedef String<128> Child;
+
+ Name name;
+ Child child;
+
+ /**
+ * Exception types
+ */
+ class Name_is_missing : Exception { };
+ class Child_is_missing : Exception { };
+
+ /**
+ * Constructor
+ *
+ * \throw Name_is_missing
+ * \throw Child_is_missing
+ */
+ Alias(Genode::Xml_node alias)
+ :
+ name (alias.attribute_value("name", Name())),
+ child(alias.attribute_value("child", Child()))
+ {
+
+ if (!name.valid()) throw Name_is_missing();
+ if (!child.valid()) throw Child_is_missing();
+ }
+};
+
+#endif /* _SRC__INIT__ALIAS_H_ */
diff --git a/repos/os/src/init/buffered_xml.h b/repos/os/src/init/buffered_xml.h
new file mode 100644
index 0000000000..8efda75b71
--- /dev/null
+++ b/repos/os/src/init/buffered_xml.h
@@ -0,0 +1,55 @@
+/*
+ * \brief Utility for buffering XML nodes
+ * \author Norman Feske
+ * \date 2017-03-03
+ */
+
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef _SRC__INIT__BUFFERED_XML_H_
+#define _SRC__INIT__BUFFERED_XML_H_
+
+namespace Init { class Buffered_xml; }
+
+
+class Init::Buffered_xml
+{
+ private:
+
+ Allocator &_alloc;
+ char const * const _ptr; /* pointer to dynamically allocated buffer */
+ Xml_node const _xml; /* referring to buffer of '_ptr' */
+
+ /**
+ * \throw Allocator::Out_of_memory
+ */
+ static char const *_init_ptr(Allocator &alloc, Xml_node node)
+ {
+ char *ptr = (char *)alloc.alloc(node.size());
+ Genode::memcpy(ptr, node.addr(), node.size());
+ return ptr;
+ }
+
+ public:
+
+ /**
+ * Constructor
+ *
+ * \throw Allocator::Out_of_memory
+ */
+ Buffered_xml(Allocator &alloc, Xml_node node)
+ :
+ _alloc(alloc), _ptr(_init_ptr(alloc, node)), _xml(_ptr, node.size())
+ { }
+
+ ~Buffered_xml() { _alloc.free(const_cast(_ptr), _xml.size()); }
+
+ Xml_node xml() const { return _xml; }
+};
+
+#endif /* _SRC__INIT__BUFFERED_XML_H_ */
diff --git a/repos/os/src/init/child.cc b/repos/os/src/init/child.cc
new file mode 100644
index 0000000000..a9faa91e7b
--- /dev/null
+++ b/repos/os/src/init/child.cc
@@ -0,0 +1,559 @@
+/*
+ * \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.
+ */
+
+/* local includes */
+#include
+
+
+Init::Child::Apply_config_result Init::Child::apply_config(Xml_node start_node)
+{
+ Child_policy &policy = *this;
+
+ if (_state == STATE_ABANDONED)
+ return NO_SIDE_EFFECTS;
+
+ /*
+ * If the child's environment is incomplete, restart it to attempt
+ * the re-routing of its environment sessions.
+ */
+ if (!_child.active()) {
+ abandon();
+ return MAY_HAVE_SIDE_EFFECTS;
+ }
+
+ bool provided_services_changed = false;
+
+ enum Config_update { CONFIG_APPEARED, CONFIG_VANISHED,
+ CONFIG_CHANGED, CONFIG_UNCHANGED };
+
+ Config_update config_update = CONFIG_UNCHANGED;
+
+ /* import new start node if new version differs */
+ if (start_node.size() != _start_node->xml().size() ||
+ Genode::memcmp(start_node.addr(), _start_node->xml().addr(),
+ start_node.size()) != 0)
+ {
+ /*
+ * Check for a change of the version attribute, force restart
+ * if the version changed.
+ */
+ if (_version != start_node.attribute_value("version", Version())) {
+ abandon();
+ return MAY_HAVE_SIDE_EFFECTS;
+ }
+
+ /*
+ * 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) {
+
+ Xml_node old_config = _start_node->xml().sub_node(tag);
+ Xml_node new_config = start_node.sub_node(tag);
+
+ if (Genode::memcmp(old_config.addr(), new_config.addr(),
+ min(old_config.size(), new_config.size())))
+ config_update = CONFIG_CHANGED;
+ }
+
+ /*
+ * Import updated node
+ *
+ * First abandon services that are no longer present in the
+ * 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);
+
+ /* 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;
+}
+
+
+void Init::Child::report_state(Xml_generator &xml, Report_detail const &detail) const
+{
+ 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");
+
+ if (detail.child_ram() && _child.ram_session_cap().valid()) {
+ xml.node("ram", [&] () {
+ /*
+ * The const cast is needed because there is no const
+ * accessor for the RAM session of the child.
+ */
+ auto &nonconst_child = const_cast(_child);
+ generate_ram_info(xml, nonconst_child.ram());
+ });
+ }
+
+ 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); }); };
+
+ server_id_space().for_each(fn);
+ });
+ }
+ });
+}
+
+
+void Init::Child::init(Ram_session &session, Ram_session_capability cap)
+{
+ session.ref_account(_env.ram_session_cap());
+
+ size_t const initial_session_costs =
+ session_alloc_batch_size()*_child.session_factory().session_costs();
+
+ size_t const transfer_ram = _resources.effective_ram_quota.value > initial_session_costs
+ ? _resources.effective_ram_quota.value - initial_session_costs
+ : 0;
+ if (transfer_ram)
+ _env.ram().transfer_quota(cap, transfer_ram);
+}
+
+
+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())
+ return Route { _config_rom_service->service(), label };
+
+ /*
+ * \deprecated the support for the 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'");
+ throw Parent::Service_denied();
+ }
+
+ return resolve_session_request(service_name,
+ prefixed_label(name(), rom));
+ }
+
+ /*
+ * If there is neither an inline '' nor a
+ * '' 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);
+
+ /* check for "session_requests" ROM request */
+ if (service_name == Rom_session::service_name()
+ && label.last_element() == Session_requester::rom_name())
+ return Route { _session_requester.service() };
+
+ 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 Label;
+ Label const target_label =
+ target.attribute_value("label", Label(label.string()));
+
+ if (target.has_type("parent")) {
+
+ Parent_service *service = nullptr;
+
+ if ((service = find_service(_parent_services, service_name)))
+ return Route { *service, target_label };
+
+ if (service && service->abandoned())
+ throw Parent::Service_denied();
+
+ if (!service_wildcard) {
+ warning(name(), ": service lookup for "
+ "\"", service_name, "\" at parent failed");
+ throw Parent::Service_denied();
+ }
+ }
+
+ 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);
+
+ Routed_service *service = nullptr;
+
+ _child_services.for_each([&] (Routed_service &s) {
+ if (s.name() == Service::Name(service_name)
+ && s.child_name() == server_name)
+ service = &s; });
+
+ if (service && service->abandoned())
+ throw Parent::Service_denied();
+
+ if (service)
+ return Route { *service, target_label };
+
+ if (!service_wildcard) {
+ warning(name(), ": lookup to child "
+ "server \"", server_name, "\" failed");
+ throw Parent::Service_denied();
+ }
+ }
+
+ if (target.has_type("any-child")) {
+
+ if (is_ambiguous(_child_services, service_name)) {
+ error(name(), ": ambiguous routes to "
+ "service \"", service_name, "\"");
+ throw Parent::Service_denied();
+ }
+
+ Routed_service *service = nullptr;
+
+ if ((service = find_service(_child_services, service_name)))
+ return Route { *service, target_label };
+
+ if (!service_wildcard) {
+ warning(name(), ": lookup for service "
+ "\"", service_name, "\" failed");
+ throw Parent::Service_denied();
+ }
+ }
+
+ if (target.last())
+ break;
+ }
+ }
+ } catch (Xml_node::Nonexistent_sub_node) { }
+
+ warning(name(), ": no route to service \"", service_name, "\"");
+ throw Parent::Service_denied();
+}
+
+
+void Init::Child::filter_session_args(Service::Name const &service,
+ char *args, size_t args_len)
+{
+ /*
+ * Intercept CPU session requests to scale priorities
+ */
+ if (service == "CPU" && _prio_levels_log2 > 0) {
+
+ 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.
+ */
+ if (service == "RAM" && !_constrain_phys) {
+ Arg_string::remove_arg(args, "phys_start");
+ Arg_string::remove_arg(args, "phys_size");
+ }
+}
+
+
+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)
+{
+ log("child \"", name(), "\" announces service \"", service_name, "\"");
+
+ 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)
+{
+ log("child \"", name(), "\" requests resources: ", args.string());
+
+ size_t const requested_ram_quota =
+ Arg_string::find_arg(args.string(), "ram_quota")
+ .ulong_value(0);
+
+ if (_ram_limit_accessor.ram_limit().value < requested_ram_quota) {
+ warning("cannot respond to resource request - out of memory");
+ return;
+ }
+
+ _env.ram().transfer_quota(_child.ram_session_cap(),
+ requested_ram_quota);
+
+ /* wake up child that was starved for resources */
+ _child.notify_resource_avail();
+}
+
+
+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,
+ Name_registry &name_registry,
+ Ram_limit_accessor &ram_limit_accessor,
+ long prio_levels,
+ Affinity::Space const &affinity_space,
+ Registry &parent_services,
+ Registry &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),
+ _ram_limit_accessor(ram_limit_accessor),
+ _name_registry(name_registry),
+ _resources(_resources_from_start_node(start_node, prio_levels, affinity_space)),
+ _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, "\"");
+ log(" RAM quota: ", Number_of_bytes(_resources.effective_ram_quota.value));
+ 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);
+}
+
+
+Init::Child::~Child()
+{
+ _child_services.for_each([&] (Routed_service &service) {
+ if (service.has_id_space(_session_requester.id_space()))
+ destroy(_alloc, &service); });
+}
diff --git a/repos/os/src/init/child.h b/repos/os/src/init/child.h
new file mode 100644
index 0000000000..73183798b0
--- /dev/null
+++ b/repos/os/src/init/child.h
@@ -0,0 +1,465 @@
+/*
+ * \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.
+ */
+
+#ifndef _SRC__INIT__CHILD_H_
+#define _SRC__INIT__CHILD_H_
+
+/* Genode includes */
+#include
+#include
+#include
+#include
+
+/* local includes */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace Init { class Child; }
+
+
+class Init::Child : Child_policy, Child_service::Wakeup
+{
+ public:
+
+ /**
+ * Exception types
+ */
+ struct Child_name_is_not_unique : Exception { };
+ struct Missing_name_attribute : Exception { };
+
+ /**
+ * Unique ID of the child, solely used for diagnostic purposes
+ */
+ struct Id { unsigned value; };
+
+ struct Default_route_accessor { virtual Xml_node default_route() = 0; };
+
+ struct Ram_limit_accessor { virtual Ram_quota ram_limit() = 0; };
+
+ private:
+
+ friend class Child_registry;
+
+ Env &_env;
+
+ Allocator &_alloc;
+
+ Verbose const &_verbose;
+
+ Id const _id;
+
+ enum State { STATE_INITIAL, STATE_RAM_INITIALIZED, STATE_ALIVE,
+ STATE_ABANDONED };
+
+ State _state = STATE_INITIAL;
+
+ Report_update_trigger &_report_update_trigger;
+
+ List_element _list_element;
+
+ Reconstructible _start_node;
+
+ /*
+ * Version attribute of the start node, used to force child restarts.
+ */
+ typedef String<80> Version;
+ Version _version { _start_node->xml().attribute_value("version", Version()) };
+
+ Default_route_accessor &_default_route_accessor;
+
+ Ram_limit_accessor &_ram_limit_accessor;
+
+ Name_registry &_name_registry;
+
+ /**
+ * Read name from XML and check for name confict with other children
+ *
+ * \throw Missing_name_attribute
+ */
+ static Name _name_from_xml(Xml_node start_node)
+ {
+ Name const name = start_node.attribute_value("name", Name());
+ if (name.valid())
+ return name;
+
+ warning("missing 'name' attribute in '' entry");
+ throw Missing_name_attribute();
+ }
+
+ typedef String<64> Name;
+ Name const _unique_name { _name_from_xml(_start_node->xml()) };
+
+ static Binary_name _binary_from_xml(Xml_node start_node,
+ Name const &unique_name)
+ {
+ if (!start_node.has_sub_node("binary"))
+ return unique_name;
+
+ return start_node.sub_node("binary").attribute_value("name", Name());
+ }
+
+ /* updated on configuration update */
+ Binary_name _binary_name { _binary_from_xml(_start_node->xml(), _unique_name) };
+
+ /**
+ * Resources assigned to the child
+ */
+ struct Resources
+ {
+ long prio_levels_log2;
+ long priority;
+ Affinity affinity;
+ Ram_quota assigned_ram_quota;
+ Ram_quota effective_ram_quota;
+ size_t cpu_quota_pc;
+ bool constrain_phys;
+ };
+
+ Resources _resources_from_start_node(Xml_node start_node, long prio_levels,
+ Affinity::Space const &affinity_space)
+ {
+ size_t cpu_quota_pc = 0;
+ bool constrain_phys = false;
+ Number_of_bytes ram_bytes = 0;
+
+ start_node.for_each_sub_node("resource", [&] (Xml_node rsc) {
+
+ typedef String<8> Name;
+ Name const name = rsc.attribute_value("name", Name());
+
+ if (name == "RAM") {
+ ram_bytes = rsc.attribute_value("quantum", ram_bytes);
+ constrain_phys = rsc.attribute_value("constrain_phys", false);
+ }
+
+ if (name == "CPU") {
+ cpu_quota_pc = rsc.attribute_value("quantum", 0UL);
+ }
+ });
+
+ return Resources { log2(prio_levels),
+ priority_from_xml(start_node, prio_levels),
+ Affinity(affinity_space,
+ affinity_location_from_xml(affinity_space, start_node)),
+ Ram_quota { ram_bytes },
+ Ram_quota { Genode::Child::effective_ram_quota(ram_bytes) },
+ cpu_quota_pc,
+ constrain_phys };
+ }
+
+ Resources _resources;
+
+ void _check_resource_constraints()
+ {
+ if (_resources.effective_ram_quota.value == 0)
+ warning("no valid RAM RESOURCE for child \"", _unique_name, "\"");
+
+ Ram_quota const ram_limit = _ram_limit_accessor.ram_limit();
+
+ /*
+ * If the configured RAM quota exceeds our own quota, we donate
+ * all remaining quota to the child.
+ */
+ if (_resources.assigned_ram_quota.value > ram_limit.value) {
+ _resources.assigned_ram_quota.value = ram_limit.value;
+
+ if (_verbose.enabled())
+ warn_insuff_quota(ram_limit.value);
+ }
+ }
+
+ bool const _resources_checked = (_check_resource_constraints(), true);
+
+ Registry &_parent_services;
+ Registry &_child_services;
+
+ struct Inline_config_rom_service : Abandonable, Dynamic_rom_session::Content_producer
+ {
+ typedef Local_service Service;
+
+ Child &_child;
+
+ Dynamic_rom_session _session { _child._env.ep().rpc_ep(),
+ _child.ref_ram(), _child._env.rm(),
+ *this };
+
+ Service::Single_session_factory _factory { _session };
+ Service _service { _factory };
+
+ Inline_config_rom_service(Child &child) : _child(child) { }
+
+ /**
+ * Dynamic_rom_session::Content_producer interface
+ */
+ void produce_content(char *dst, Genode::size_t dst_len) override
+ {
+ Xml_node config = _child._start_node->xml().has_sub_node("config")
+ ? _child._start_node->xml().sub_node("config")
+ : Xml_node("");
+
+ size_t const config_len = config.size();
+
+ if (config_len + 1 /* null termination */ >= dst_len)
+ throw Buffer_capacity_exceeded();
+
+ /*
+ * The 'config.size()' method returns the number of bytes of
+ * the config-node content, which is not null-terminated. Since
+ * 'Genode::strncpy' always null-terminates the result, the
+ * last byte of the source string is not copied. Hence, it is
+ * safe to add '1' to 'config_len' and thereby include the
+ * last actual config-content character in the result.
+ */
+ Genode::strncpy(dst, config.addr(), config_len + 1);
+ }
+
+ void trigger_update() { _session.trigger_update(); }
+
+ Service &service() { return _service; }
+ };
+
+ Constructible _config_rom_service;
+
+ Session_requester _session_requester;
+
+ /**
+ * CPU-session priority parameters
+ */
+ long const _prio_levels_log2 { _resources.prio_levels_log2 };
+ long const _priority { _resources.priority };
+
+ /**
+ * If set to true, the child is allowed to constrain physical RAM
+ * allocations.
+ */
+ bool const _constrain_phys { _resources.constrain_phys };
+
+ Genode::Child _child { _env.rm(), _env.ep().rpc_ep(), *this };
+
+ struct Ram_accessor : Routed_service::Ram_accessor
+ {
+ Genode::Child &_child;
+ Ram_accessor(Genode::Child &child) : _child(child) { }
+ Ram_session_capability ram() const override {
+ return _child.ram_session_cap(); }
+ } _ram_accessor { _child };
+
+ /**
+ * Child_service::Wakeup callback
+ */
+ void wakeup_child_service() override
+ {
+ _session_requester.trigger_update();
+ }
+
+ /**
+ * Return true if the policy results in the current route of the session
+ *
+ * This method is used to check if a policy change affects an existing
+ * client session of a child, i.e., to determine whether the child must
+ * be restarted.
+ */
+ bool _route_valid(Session_state const &session)
+ {
+ try {
+ Route const route =
+ resolve_session_request(session.service().name(),
+ session.client_label());
+
+ return (session.service() == route.service)
+ && (route.label == session.label());
+ }
+ catch (Parent::Service_denied) { return false; }
+ }
+
+ static Xml_node _provides_sub_node(Xml_node start_node)
+ {
+ return start_node.has_sub_node("provides")
+ ? start_node.sub_node("provides") : Xml_node("");
+ }
+
+ /**
+ * Return true if service is provided by this child
+ */
+ bool _provided_by_this(Routed_service const &service)
+ {
+ return service.has_id_space(_session_requester.id_space());
+ }
+
+ /**
+ * Return true if service of specified sub node is known
+ */
+ bool _service_exists(Xml_node node) const
+ {
+ bool exists = false;
+ _child_services.for_each([&] (Routed_service const &service) {
+ if (_provided_by_this(service) &&
+ service.name() == node.attribute_value("name", Service::Name()))
+ exists = true; });
+
+ return exists;
+ }
+
+ void _add_service(Xml_node service)
+ {
+ Service::Name const name =
+ service.attribute_value("name", Service::Name());
+
+ if (_verbose.enabled())
+ log(" provides service ", name);
+
+ new (_alloc)
+ Routed_service(_child_services, this->name(), _ram_accessor,
+ _session_requester.id_space(),
+ _child.session_factory(),
+ name, *this);
+ }
+
+ public:
+
+ /**
+ * Constructor
+ *
+ * \param alloc allocator solely used for configuration-dependent
+ * allocations. It is not used for allocations on behalf
+ * of the child's behavior.
+ *
+ * \throw Allocator::Out_of_memory could not buffer the XML start node
+ */
+ 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,
+ Name_registry &name_registry,
+ Ram_limit_accessor &ram_limit_accessor,
+ long prio_levels,
+ Affinity::Space const &affinity_space,
+ Registry &parent_services,
+ Registry &child_services);
+
+ virtual ~Child();
+
+ /**
+ * Return true if the child has the specified name
+ */
+ bool has_name(Child_policy::Name const &str) const { return str == name(); }
+
+ Ram_quota ram_quota() const { return _resources.assigned_ram_quota; }
+
+ void initiate_env_ram_session()
+ {
+ if (_state == STATE_INITIAL) {
+ _child.initiate_env_ram_session();
+ _state = STATE_RAM_INITIALIZED;
+ }
+ }
+
+ void initiate_env_sessions()
+ {
+ if (_state == STATE_RAM_INITIALIZED) {
+
+ _child.initiate_env_sessions();
+
+ /* check for completeness of the child's environment */
+ if (_verbose.enabled())
+ _child.for_each_session([&] (Session_state const &session) {
+ if (!session.alive())
+ warning(name(), ": incomplete environment ",
+ session.service().name(), " session "
+ "(", session.label(), ")"); });
+
+ _state = STATE_ALIVE;
+ }
+ }
+
+ void abandon()
+ {
+ _state = STATE_ABANDONED;
+
+ _child_services.for_each([&] (Routed_service &service) {
+ if (service.has_id_space(_session_requester.id_space()))
+ service.abandon(); });
+ }
+
+ bool abandoned() const { return _state == STATE_ABANDONED; }
+
+ enum Apply_config_result { MAY_HAVE_SIDE_EFFECTS, NO_SIDE_EFFECTS };
+
+ /**
+ * Apply new configuration to child
+ *
+ * \throw Allocator::Out_of_memory unable to allocate buffer for new
+ * config
+ */
+ Apply_config_result apply_config(Xml_node start_node);
+
+ void report_state(Xml_generator &xml, Report_detail const &detail) const;
+
+
+ /****************************
+ ** Child-policy interface **
+ ****************************/
+
+ Child_policy::Name name() const override { return _unique_name; }
+
+ Ram_session &ref_ram() override { return _env.ram(); }
+ Ram_session_capability ref_ram_cap() const override { return _env.ram_session_cap(); }
+
+ void init(Ram_session &, Ram_session_capability) override;
+ void init(Cpu_session &, Cpu_session_capability) override;
+
+ Id_space &server_id_space() override {
+ return _session_requester.id_space(); }
+
+ Route resolve_session_request(Service::Name const &,
+ Session_label const &) override;
+
+ void filter_session_args(Service::Name const &, char *, size_t) override;
+ Affinity filter_session_affinity(Affinity const &) override;
+ void announce_service(Service::Name const &) override;
+ void resource_request(Parent::Resource_args const &) override;
+
+ void exit(int exit_value) override
+ {
+ try {
+ if (_start_node->xml().sub_node("exit").attribute_value("propagate", false)) {
+ _env.parent().exit(exit_value);
+ return;
+ }
+ } catch (...) { }
+
+ /*
+ * Print a message as the exit is not handled otherwise. There are
+ * a number of automated tests that rely on this message. It is
+ * printed by the default implementation of 'Child_policy::exit'.
+ */
+ Child_policy::exit(exit_value);
+ }
+
+ void session_state_changed() override
+ {
+ _report_update_trigger.trigger_report_update();
+ }
+
+ bool initiate_env_sessions() const override { return false; }
+};
+
+#endif /* _SRC__INIT__CHILD_H_ */
diff --git a/repos/os/src/init/child_registry.h b/repos/os/src/init/child_registry.h
new file mode 100644
index 0000000000..c5d3e072ab
--- /dev/null
+++ b/repos/os/src/init/child_registry.h
@@ -0,0 +1,149 @@
+/*
+ * \brief Child registry
+ * \author Norman Feske
+ * \date 2010-04-27
+ */
+
+/*
+ * 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.
+ */
+
+#ifndef _SRC__INIT__CHILD_REGISTRY_H_
+#define _SRC__INIT__CHILD_REGISTRY_H_
+
+/* local includes */
+#include
+#include
+#include
+#include
+
+namespace Init { struct Child_registry; }
+
+
+class Init::Child_registry : public Name_registry, Child_list
+{
+ private:
+
+ List _aliases;
+
+ bool _unique(const char *name) const
+ {
+ /* check for name clash with an existing child */
+ Genode::List_element const *curr = first();
+ for (; curr; curr = curr->next())
+ if (curr->object()->has_name(name))
+ return false;
+
+ /* check for name clash with an existing alias */
+ for (Alias const *a = _aliases.first(); a; a = a->next()) {
+ if (Alias::Name(name) == a->name)
+ return false;
+ }
+
+ return true;
+ }
+
+ public:
+
+ /**
+ * Exception type
+ */
+ class Alias_name_is_not_unique { };
+
+ /**
+ * Register child
+ */
+ void insert(Child *child)
+ {
+ Child_list::insert(&child->_list_element);
+ }
+
+ /**
+ * Unregister child
+ */
+ void remove(Child *child)
+ {
+ Child_list::remove(&child->_list_element);
+ }
+
+ /**
+ * Register alias
+ */
+ void insert_alias(Alias *alias)
+ {
+ if (!_unique(alias->name.string())) {
+ error("alias name ", alias->name, " is not unique");
+ throw Alias_name_is_not_unique();
+ }
+ _aliases.insert(alias);
+ }
+
+ /**
+ * Unregister alias
+ */
+ void remove_alias(Alias *alias)
+ {
+ _aliases.remove(alias);
+ }
+
+ /**
+ * Return any of the registered children, or 0 if no child exists
+ */
+ Child *any()
+ {
+ return first() ? first()->object() : 0;
+ }
+
+ /**
+ * Return any of the registered aliases, or 0 if no alias exists
+ */
+ Alias *any_alias()
+ {
+ return _aliases.first() ? _aliases.first() : 0;
+ }
+
+ template
+ void for_each_child(FN const &fn) const
+ {
+ Genode::List_element const *curr = first();
+ for (; curr; curr = curr->next())
+ fn(*curr->object());
+ }
+
+ template
+ void for_each_child(FN const &fn)
+ {
+ Genode::List_element *curr = first(), *next = nullptr;
+ for (; curr; curr = next) {
+ next = curr->next();
+ fn(*curr->object());
+ }
+ }
+
+ void report_state(Xml_generator &xml, Report_detail const &detail) const
+ {
+ for_each_child([&] (Child &child) { child.report_state(xml, detail); });
+
+ /* check for name clash with an existing alias */
+ for (Alias const *a = _aliases.first(); a; a = a->next()) {
+ xml.node("alias", [&] () {
+ xml.attribute("name", a->name);
+ xml.attribute("child", a->child);
+ });
+ }
+ }
+
+ Child::Name deref_alias(Child::Name const &name) override
+ {
+ for (Alias const *a = _aliases.first(); a; a = a->next())
+ if (name == a->name)
+ return a->child;
+
+ return name;
+ }
+};
+
+#endif /* _SRC__INIT__CHILD_REGISTRY_H_ */
diff --git a/repos/os/src/init/main.cc b/repos/os/src/init/main.cc
index 9c9764d8b6..6dca3e2114 100644
--- a/repos/os/src/init/main.cc
+++ b/repos/os/src/init/main.cc
@@ -14,367 +14,14 @@
/* Genode includes */
#include
#include
-#include
-#include
-/* init includes */
-#include
+/* local includes */
+#include
+#include
+#include
+#include
-namespace Init {
-
- using namespace Genode;
-
- /**
- * Read priority-levels declaration from config
- */
- inline long read_prio_levels(Xml_node config)
- {
- long const prio_levels = config.attribute_value("prio_levels", 0UL);
-
- if (prio_levels && (prio_levels != (1 << log2(prio_levels)))) {
- warning("prio levels is not power of two, priorities are disabled");
- return 0;
- }
- return prio_levels;
- }
-
-
- /**
- * Read affinity-space parameters from config
- *
- * If no affinity space is declared, construct a space with a single element,
- * width and height being 1. If only one of both dimensions is specified, the
- * other dimension is set to 1.
- */
- inline Genode::Affinity::Space read_affinity_space(Xml_node config)
- {
- try {
- Xml_node node = config.sub_node("affinity-space");
- return Affinity::Space(node.attribute_value("width", 1),
- node.attribute_value("height", 1));
- } catch (...) {
- return Affinity::Space(1, 1); }
- }
-}
-
-
-/********************
- ** Child registry **
- ********************/
-
-namespace Init { struct Alias; }
-
-
-/**
- * Representation of an alias for a child
- */
-struct Init::Alias : Genode::List::Element
-{
- typedef Genode::String<128> Name;
- typedef Genode::String<128> Child;
-
- Name name;
- Child child;
-
- /**
- * Exception types
- */
- class Name_is_missing { };
- class Child_is_missing { };
-
- /**
- * Utility to read a string attribute from an XML node
- *
- * \param STR string type
- * \param EXC exception type raised if attribute is not present
- *
- * \param node XML node
- * \param attr_name name of attribute to read
- */
- template
- static STR _read_string_attr(Genode::Xml_node node, char const *attr_name)
- {
- char buf[STR::size()];
-
- if (!node.has_attribute(attr_name))
- throw EXC();
-
- node.attribute(attr_name).value(buf, sizeof(buf));
-
- return STR(buf);
- }
-
- /**
- * Constructor
- *
- * \throw Name_is_missing
- * \throw Child_is_missing
- */
- Alias(Genode::Xml_node alias)
- :
- name (_read_string_attr (alias, "name")),
- child(_read_string_attr(alias, "child"))
- { }
-};
-
-
-namespace Init {
-
- typedef Genode::List > Child_list;
-
- struct Child_registry;
-}
-
-
-class Init::Child_registry : public Name_registry, Child_list
-{
- private:
-
- List _aliases;
-
- public:
-
- /**
- * Exception type
- */
- class Alias_name_is_not_unique { };
-
- /**
- * Register child
- */
- void insert(Child *child)
- {
- Child_list::insert(&child->_list_element);
- }
-
- /**
- * Unregister child
- */
- void remove(Child *child)
- {
- Child_list::remove(&child->_list_element);
- }
-
- /**
- * Register alias
- */
- void insert_alias(Alias *alias)
- {
- if (!unique(alias->name.string())) {
- error("alias name ", alias->name, " is not unique");
- throw Alias_name_is_not_unique();
- }
- _aliases.insert(alias);
- }
-
- /**
- * Unregister alias
- */
- void remove_alias(Alias *alias)
- {
- _aliases.remove(alias);
- }
-
- /**
- * Return any of the registered children, or 0 if no child exists
- */
- Child *any()
- {
- return first() ? first()->object() : 0;
- }
-
- /**
- * Return any of the registered aliases, or 0 if no alias exists
- */
- Alias *any_alias()
- {
- return _aliases.first() ? _aliases.first() : 0;
- }
-
- template
- void for_each_child(FN const &fn) const
- {
- Genode::List_element const *curr = first();
- for (; curr; curr = curr->next())
- fn(*curr->object());
- }
-
- template
- void for_each_child(FN const &fn)
- {
- Genode::List_element *curr = first(), *next = nullptr;
- for (; curr; curr = next) {
- next = curr->next();
- fn(*curr->object());
- }
- }
-
- void report_state(Xml_generator &xml, Report_detail const &detail) const
- {
- for_each_child([&] (Child &child) { child.report_state(xml, detail); });
-
- /* check for name clash with an existing alias */
- for (Alias const *a = _aliases.first(); a; a = a->next()) {
- xml.node("alias", [&] () {
- xml.attribute("name", a->name);
- xml.attribute("child", a->child);
- });
- }
- }
-
-
- /*****************************
- ** Name-registry interface **
- *****************************/
-
- bool unique(const char *name) const
- {
- /* check for name clash with an existing child */
- Genode::List_element const *curr = first();
- for (; curr; curr = curr->next())
- if (curr->object()->has_name(name))
- return false;
-
- /* check for name clash with an existing alias */
- for (Alias const *a = _aliases.first(); a; a = a->next()) {
- if (Alias::Name(name) == a->name)
- return false;
- }
-
- return true;
- }
-
- Name deref_alias(Name const &name) override
- {
- for (Alias const *a = _aliases.first(); a; a = a->next())
- if (name == a->name)
- return a->child;
-
- return name;
- }
-};
-
-
-namespace Init {
- struct State_reporter;
- struct Main;
-}
-
-
-class Init::State_reporter : public Report_update_trigger
-{
- public:
-
- struct Producer
- {
- virtual void produce_state_report(Xml_generator &xml,
- Report_detail const &) const = 0;
- };
-
- private:
-
- Env &_env;
-
- Producer &_producer;
-
- Constructible _reporter;
-
- size_t _buffer_size = 0;
-
- Reconstructible _report_detail;
-
- unsigned _report_delay_ms = 0;
-
- /* version string from config, to be reflected in the report */
- typedef String<64> Version;
- Version _version;
-
- Constructible _timer;
-
- Signal_handler _timer_handler {
- _env.ep(), *this, &State_reporter::_handle_timer };
-
- bool _scheduled = false;
-
- void _handle_timer()
- {
- _scheduled = false;
-
- try {
- Reporter::Xml_generator xml(*_reporter, [&] () {
-
- if (_version.valid())
- xml.attribute("version", _version);
-
- _producer.produce_state_report(xml, *_report_detail);
- });
- }
- catch(Xml_generator::Buffer_exceeded) {
-
- error("state report exceeds maximum size");
-
- /* try to reflect the error condition as state report */
- try {
- Reporter::Xml_generator xml(*_reporter, [&] () {
- xml.attribute("error", "report buffer exceeded"); });
- }
- catch (...) { }
- }
- }
-
- public:
-
- State_reporter(Env &env, Producer &producer)
- :
- _env(env), _producer(producer)
- { }
-
- void apply_config(Xml_node config)
- {
- try {
- Xml_node report = config.sub_node("report");
-
- /* (re-)construct reporter whenever the buffer size is changed */
- Number_of_bytes const buffer_size =
- report.attribute_value("buffer", Number_of_bytes(4096));
-
- if (buffer_size != _buffer_size || !_reporter.constructed()) {
- _buffer_size = buffer_size;
- _reporter.construct(_env, "state", "state", _buffer_size);
- }
-
- _report_detail.construct(report);
- _report_delay_ms = report.attribute_value("delay_ms", 100UL);
- _reporter->enabled(true);
- }
- catch (Xml_node::Nonexistent_sub_node) {
- _report_detail.construct();
- _report_delay_ms = 0;
- if (_reporter.constructed())
- _reporter->enabled(false);
- }
-
- _version = config.attribute_value("version", Version());
-
- if (_report_delay_ms) {
-
- if (!_timer.constructed()) {
- _timer.construct(_env);
- _timer->sigh(_timer_handler);
- }
-
- trigger_report_update();
- }
- }
-
- void trigger_report_update() override
- {
- if (!_scheduled && _timer.constructed() && _report_delay_ms) {
- _timer->trigger_once(_report_delay_ms*1000);
- _scheduled = true;
- }
- }
-};
+namespace Init { struct Main; }
struct Init::Main : State_reporter::Producer, Child::Default_route_accessor,
@@ -651,8 +298,8 @@ void Init::Main::_handle_config()
Init::Child(_env, _heap, *_verbose,
Init::Child::Id { ++_child_cnt }, _state_reporter,
start_node, *this, _children, *this,
- read_prio_levels(_config.xml()),
- read_affinity_space(_config.xml()),
+ prio_levels_from_xml(_config.xml()),
+ affinity_space_from_xml(_config.xml()),
_parent_services, _child_services);
_children.insert(&child);
@@ -686,7 +333,6 @@ void Init::Main::_handle_config()
}
catch (Xml_node::Nonexistent_sub_node) { error("no children to start"); }
catch (Xml_node::Invalid_syntax) { error("config has invalid syntax"); }
- catch (Init::Child::Child_name_is_not_unique) { }
catch (Init::Child_registry::Alias_name_is_not_unique) { }
/*
diff --git a/repos/os/src/init/name_registry.h b/repos/os/src/init/name_registry.h
new file mode 100644
index 0000000000..4e85b29249
--- /dev/null
+++ b/repos/os/src/init/name_registry.h
@@ -0,0 +1,39 @@
+/*
+ * \brief Interface for database of child names
+ * \author Norman Feske
+ * \date 2017-03-03
+ */
+
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef _SRC__INIT__NAME_REGISTRY_H_
+#define _SRC__INIT__NAME_REGISTRY_H_
+
+/* Genode includes */
+#include
+
+/* local includes */
+#include
+
+namespace Init { struct Name_registry; }
+
+struct Init::Name_registry
+{
+ virtual ~Name_registry() { }
+
+ typedef Child_policy::Name Name;
+
+ /**
+ * Return child name for a given alias name
+ *
+ * If there is no alias, the function returns the original name.
+ */
+ virtual Name deref_alias(Name const &) = 0;
+};
+
+#endif /* _SRC__INIT__NAME_REGISTRY_H_ */
diff --git a/repos/os/include/init/report.h b/repos/os/src/init/report.h
similarity index 93%
rename from repos/os/include/init/report.h
rename to repos/os/src/init/report.h
index baa1ca3284..fcb6b08574 100644
--- a/repos/os/include/init/report.h
+++ b/repos/os/src/init/report.h
@@ -11,8 +11,8 @@
* under the terms of the GNU Affero General Public License version 3.
*/
-#ifndef _INCLUDE__INIT__REPORT_H_
-#define _INCLUDE__INIT__REPORT_H_
+#ifndef _SRC__INIT__REPORT_H_
+#define _SRC__INIT__REPORT_H_
#include
#include
@@ -65,4 +65,4 @@ struct Init::Report_update_trigger
virtual void trigger_report_update() = 0;
};
-#endif /* _INCLUDE__INIT__REPORT_H_ */
+#endif /* _SRC__INIT__REPORT_H_ */
diff --git a/repos/os/src/init/service.h b/repos/os/src/init/service.h
new file mode 100644
index 0000000000..3ee0cf33fb
--- /dev/null
+++ b/repos/os/src/init/service.h
@@ -0,0 +1,102 @@
+/*
+ * \brief Services as targeted by session routes
+ * \author Norman Feske
+ * \date 2017-03-03
+ */
+
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef _SRC__INIT__SERVICE_H_
+#define _SRC__INIT__SERVICE_H_
+
+namespace Init {
+ class Abandonable;
+ class Parent_service;
+ class Routed_service;
+}
+
+
+class Init::Abandonable
+{
+ private:
+
+ bool _abandoned = false;
+
+ public:
+
+ void abandon() { _abandoned = true; }
+
+ bool abandoned() const { return _abandoned; }
+};
+
+
+class Init::Parent_service : public Genode::Parent_service, public Abandonable
+{
+ private:
+
+ Registry::Element _reg_elem;
+
+ public:
+
+ Parent_service(Registry ®istry, Env &env,
+ Service::Name const &name)
+ :
+ Genode::Parent_service(env, name), _reg_elem(registry, *this)
+ { }
+};
+
+
+/**
+ * Init-specific representation of a child service
+ */
+class Init::Routed_service : public Child_service, public Abandonable
+{
+ public:
+
+ typedef Child_policy::Name Child_name;
+
+ struct Ram_accessor { virtual Ram_session_capability ram() const = 0; };
+
+ private:
+
+ Child_name _child_name;
+
+ Ram_accessor &_ram_accessor;
+
+ Registry::Element _registry_element;
+
+ public:
+
+ /**
+ * Constructor
+ *
+ * \param services registry of all services provides by children
+ * \param child_name child name of server, used for session routing
+ *
+ * The other arguments correspond to the arguments of 'Child_service'.
+ */
+ Routed_service(Registry &services,
+ Child_name const &child_name,
+ Ram_accessor &ram_accessor,
+ Id_space &server_id_space,
+ Session_state::Factory &factory,
+ Service::Name const &name,
+ Child_service::Wakeup &wakeup)
+ :
+ Child_service(server_id_space, factory, name,
+ Ram_session_capability(), wakeup),
+ _child_name(child_name), _ram_accessor(ram_accessor),
+ _registry_element(services, *this)
+ { }
+
+ Child_name const &child_name() const { return _child_name; }
+
+ Ram_session_capability ram() const { return _ram_accessor.ram(); }
+};
+
+#endif /* _SRC__INIT__SERVICE_H_ */
diff --git a/repos/os/src/init/state_reporter.h b/repos/os/src/init/state_reporter.h
new file mode 100644
index 0000000000..3391f8cea4
--- /dev/null
+++ b/repos/os/src/init/state_reporter.h
@@ -0,0 +1,137 @@
+/*
+ * \brief Init-state reporting mechanism
+ * \author Norman Feske
+ * \date 2017-03-03
+ */
+
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef _SRC__INIT__STATE_REPORTER_H_
+#define _SRC__INIT__STATE_REPORTER_H_
+
+#include
+#include
+
+namespace Init { class State_reporter; }
+
+class Init::State_reporter : public Report_update_trigger
+{
+ public:
+
+ struct Producer
+ {
+ virtual void produce_state_report(Xml_generator &xml,
+ Report_detail const &) const = 0;
+ };
+
+ private:
+
+ Env &_env;
+
+ Producer &_producer;
+
+ Constructible _reporter;
+
+ size_t _buffer_size = 0;
+
+ Reconstructible _report_detail;
+
+ unsigned _report_delay_ms = 0;
+
+ /* version string from config, to be reflected in the report */
+ typedef String<64> Version;
+ Version _version;
+
+ Constructible _timer;
+
+ Signal_handler _timer_handler {
+ _env.ep(), *this, &State_reporter::_handle_timer };
+
+ bool _scheduled = false;
+
+ void _handle_timer()
+ {
+ _scheduled = false;
+
+ try {
+ Reporter::Xml_generator xml(*_reporter, [&] () {
+
+ if (_version.valid())
+ xml.attribute("version", _version);
+
+ _producer.produce_state_report(xml, *_report_detail);
+ });
+ }
+ catch(Xml_generator::Buffer_exceeded) {
+
+ error("state report exceeds maximum size");
+
+ /* try to reflect the error condition as state report */
+ try {
+ Reporter::Xml_generator xml(*_reporter, [&] () {
+ xml.attribute("error", "report buffer exceeded"); });
+ }
+ catch (...) { }
+ }
+ }
+
+ public:
+
+ State_reporter(Env &env, Producer &producer)
+ :
+ _env(env), _producer(producer)
+ { }
+
+ void apply_config(Xml_node config)
+ {
+ try {
+ Xml_node report = config.sub_node("report");
+
+ /* (re-)construct reporter whenever the buffer size is changed */
+ Number_of_bytes const buffer_size =
+ report.attribute_value("buffer", Number_of_bytes(4096));
+
+ if (buffer_size != _buffer_size || !_reporter.constructed()) {
+ _buffer_size = buffer_size;
+ _reporter.construct(_env, "state", "state", _buffer_size);
+ }
+
+ _report_detail.construct(report);
+ _report_delay_ms = report.attribute_value("delay_ms", 100UL);
+ _reporter->enabled(true);
+ }
+ catch (Xml_node::Nonexistent_sub_node) {
+ _report_detail.construct();
+ _report_delay_ms = 0;
+ if (_reporter.constructed())
+ _reporter->enabled(false);
+ }
+
+ _version = config.attribute_value("version", Version());
+
+ if (_report_delay_ms) {
+
+ if (!_timer.constructed()) {
+ _timer.construct(_env);
+ _timer->sigh(_timer_handler);
+ }
+
+ trigger_report_update();
+ }
+ }
+
+ void trigger_report_update() override
+ {
+ if (!_scheduled && _timer.constructed() && _report_delay_ms) {
+ _timer->trigger_once(_report_delay_ms*1000);
+ _scheduled = true;
+ }
+ }
+};
+
+#endif /* _SRC__INIT__STATE_REPORTER_H_ */
diff --git a/repos/os/src/init/target.mk b/repos/os/src/init/target.mk
index d9468c7e36..9180584f62 100644
--- a/repos/os/src/init/target.mk
+++ b/repos/os/src/init/target.mk
@@ -1,3 +1,4 @@
-TARGET = init
-SRC_CC = main.cc
-LIBS = base config
+TARGET = init
+SRC_CC = main.cc child.cc
+LIBS = base
+INC_DIR += $(PRG_DIR)
diff --git a/repos/os/src/init/types.h b/repos/os/src/init/types.h
new file mode 100644
index 0000000000..cbf48111f8
--- /dev/null
+++ b/repos/os/src/init/types.h
@@ -0,0 +1,33 @@
+/*
+ * \brief Common types used within init
+ * \author Norman Feske
+ * \date 2017-03-03
+ */
+
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef _SRC__INIT__TYPES_H_
+#define _SRC__INIT__TYPES_H_
+
+#include
+
+namespace Init {
+
+ class Child;
+
+ using namespace Genode;
+ using Genode::size_t;
+ using Genode::strlen;
+
+ struct Ram_quota { size_t value; };
+
+ typedef List > Child_list;
+}
+
+#endif /* _SRC__INIT__TYPES_H_ */
+
diff --git a/repos/os/src/init/utils.h b/repos/os/src/init/utils.h
new file mode 100644
index 0000000000..ef29314ffc
--- /dev/null
+++ b/repos/os/src/init/utils.h
@@ -0,0 +1,242 @@
+/*
+ * \brief Utilities
+ * \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.
+ */
+
+#ifndef _SRC__INIT__UTIL_H_
+#define _SRC__INIT__UTIL_H_
+
+namespace Init {
+
+ static void warn_insuff_quota(size_t const avail)
+ {
+ warning("specified quota exceeds available quota, "
+ "proceeding with a quota of ", avail);
+ }
+
+
+ /**
+ * Return sub string of label with the leading child name stripped out
+ *
+ * \return character pointer to the scoped part of the label,
+ * or nullptr if the label is not correctly prefixed with the child's
+ * name
+ */
+ inline char const *skip_label_prefix(char const *child_name, char const *label)
+ {
+ size_t const child_name_len = strlen(child_name);
+
+ if (strcmp(child_name, label, child_name_len) != 0)
+ return nullptr;
+
+ label += child_name_len;
+
+ /*
+ * Skip label separator. This condition should be always satisfied.
+ */
+ if (strcmp(" -> ", label, 4) != 0)
+ return nullptr;
+
+ return label + 4;
+ }
+
+
+ /**
+ * Return true if service XML node matches service request
+ *
+ * \param args session arguments, inspected for the session label
+ * \param child_name name of the originator of the session request
+ * \param service_name name of the requested service
+ */
+ inline bool service_node_matches(Xml_node const service_node,
+ Session_label const &label,
+ Child_policy::Name const &child_name,
+ Service::Name const &service_name)
+ {
+ bool const service_matches =
+ service_node.has_type("any-service") ||
+ (service_node.has_type("service") &&
+ service_node.attribute("name").has_value(service_name.string()));
+
+ if (!service_matches)
+ return false;
+
+ bool const route_depends_on_child_provided_label =
+ service_node.has_attribute("label") ||
+ service_node.has_attribute("label_prefix") ||
+ service_node.has_attribute("label_suffix");
+
+ char const *unscoped_attr = "unscoped_label";
+ if (service_node.has_attribute(unscoped_attr)) {
+
+ /*
+ * If an 'unscoped_label' attribute is provided, don't consider any
+ * scoped label attribute.
+ */
+ if (route_depends_on_child_provided_label)
+ warning("service node contains both scoped and unscoped label attributes");
+
+ typedef String Label;
+ return label == service_node.attribute_value(unscoped_attr, Label());
+ }
+
+ if (!route_depends_on_child_provided_label)
+ return true;
+
+ char const * const scoped_label = skip_label_prefix(
+ child_name.string(), label.string());
+
+ if (!scoped_label)
+ return false;
+
+ Session_label const session_label(scoped_label);
+
+ return !Xml_node_label_score(service_node, session_label).conflict();
+ }
+
+
+ /**
+ * Check if service name is ambiguous
+ *
+ * \return true if the same service is provided multiple
+ * times
+ *
+ * \deprecated
+ */
+ template
+ inline bool is_ambiguous(Registry const &services, Service::Name const &name)
+ {
+ /* count number of services with the specified name */
+ unsigned cnt = 0;
+ services.for_each([&] (T const &service) {
+ cnt += (service.name() == name); });
+
+ return cnt > 1;
+ }
+
+
+ template
+ inline T *find_service(Registry &services, Service::Name const &name)
+ {
+ T *service = nullptr;
+ services.for_each([&] (T &s) {
+ if (!service && (s.name() == name))
+ service = &s; });
+ return service;
+ }
+
+
+ inline void generate_ram_info(Xml_generator &xml, Ram_session const &ram)
+ {
+ /*
+ * The const cast is needed because the 'Ram_session' accessors are
+ * non-const methods.
+ */
+ Ram_session &ram_nonconst = const_cast(ram);
+
+ typedef String<32> Value;
+ xml.attribute("quota", Value(Number_of_bytes(ram_nonconst.quota())));
+ xml.attribute("used", Value(Number_of_bytes(ram_nonconst.used())));
+ xml.attribute("avail", Value(Number_of_bytes(ram_nonconst.avail())));
+ }
+
+ /**
+ * Read priority-levels declaration from config
+ */
+ inline long prio_levels_from_xml(Xml_node config)
+ {
+ long const prio_levels = config.attribute_value("prio_levels", 0UL);
+
+ if (prio_levels && (prio_levels != (1 << log2(prio_levels)))) {
+ warning("prio levels is not power of two, priorities are disabled");
+ return 0;
+ }
+ return prio_levels;
+ }
+
+
+ inline long priority_from_xml(Xml_node start_node, long prio_levels)
+ {
+ long priority = Cpu_session::DEFAULT_PRIORITY;
+ try { start_node.attribute("priority").value(&priority); }
+ catch (...) { }
+
+ /*
+ * All priority declarations in the config file are
+ * negative because child priorities can never be higher
+ * than parent priorities. To simplify priority
+ * calculations, we use inverted values. Lower values
+ * correspond to higher priorities.
+ */
+ priority = -priority;
+
+ if (priority && (priority >= prio_levels)) {
+ long new_prio = prio_levels ? prio_levels-1 : 0;
+ char name[Service::Name::capacity()];
+ start_node.attribute("name").value(name, sizeof(name));
+ warning(Cstring(name), ": invalid priority, upgrading "
+ "from ", -priority, " to ", -new_prio);
+ return new_prio;
+ }
+
+ return priority;
+ }
+
+
+ inline Affinity::Location
+ affinity_location_from_xml(Affinity::Space const &space, Xml_node start_node)
+ {
+ typedef Affinity::Location Location;
+ try {
+ Xml_node node = start_node.sub_node("affinity");
+
+ /* if no position value is specified, select the whole row/column */
+ unsigned long const
+ default_width = node.has_attribute("xpos") ? 1 : space.width(),
+ default_height = node.has_attribute("ypos") ? 1 : space.height();
+
+ unsigned long const
+ width = node.attribute_value("width", default_width),
+ height = node.attribute_value("height", default_height);
+
+ long const x1 = node.attribute_value("xpos", 0),
+ y1 = node.attribute_value("ypos", 0),
+ x2 = x1 + width - 1,
+ y2 = y1 + height - 1;
+
+ /* clip location to space boundary */
+ return Location(max(x1, 0L), max(y1, 0L),
+ min((unsigned)(x2 - x1 + 1), space.width()),
+ min((unsigned)(y2 - y1 + 1), space.height()));
+ }
+ catch (...) { return Location(0, 0, space.width(), space.height()); }
+ }
+
+
+ /**
+ * Read affinity-space parameters from config
+ *
+ * If no affinity space is declared, construct a space with a single element,
+ * width and height being 1. If only one of both dimensions is specified, the
+ * other dimension is set to 1.
+ */
+ inline Affinity::Space affinity_space_from_xml(Xml_node config)
+ {
+ try {
+ Xml_node node = config.sub_node("affinity-space");
+ return Affinity::Space(node.attribute_value("width", 1),
+ node.attribute_value("height", 1));
+ } catch (...) {
+ return Affinity::Space(1, 1); }
+ }
+}
+
+#endif /* _SRC__INIT__UTIL_H_ */
diff --git a/repos/os/include/init/verbose.h b/repos/os/src/init/verbose.h
similarity index 84%
rename from repos/os/include/init/verbose.h
rename to repos/os/src/init/verbose.h
index 1f9d31888b..6a88e3616f 100644
--- a/repos/os/include/init/verbose.h
+++ b/repos/os/src/init/verbose.h
@@ -11,8 +11,8 @@
* under the terms of the GNU Affero General Public License version 3.
*/
-#ifndef _INCLUDE__INIT__VERBOSE_H_
-#define _INCLUDE__INIT__VERBOSE_H_
+#ifndef _SRC__INIT__VERBOSE_H_
+#define _SRC__INIT__VERBOSE_H_
#include
#include
@@ -34,4 +34,4 @@ class Init::Verbose : Genode::Noncopyable
bool enabled() const { return _enabled; }
};
-#endif /* _INCLUDE__INIT__VERBOSE_H_ */
+#endif /* _SRC__INIT__VERBOSE_H_ */