2011-12-22 16:19:25 +01:00
|
|
|
/*
|
|
|
|
* \brief Representation used for children of the init process
|
|
|
|
* \author Norman Feske
|
|
|
|
* \date 2010-05-04
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2016-01-12 14:11:58 +01:00
|
|
|
* Copyright (C) 2010-2016 Genode Labs GmbH
|
2011-12-22 16:19:25 +01:00
|
|
|
*
|
|
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
|
|
* under the terms of the GNU General Public License version 2.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _INCLUDE__INIT__CHILD_H_
|
|
|
|
#define _INCLUDE__INIT__CHILD_H_
|
|
|
|
|
|
|
|
/* Genode includes */
|
base: avoid use of deprecated base/printf.h
Besides adapting the components to the use of base/log.h, the patch
cleans up a few base headers, i.e., it removes unused includes from
root/component.h, specifically base/heap.h and
ram_session/ram_session.h. Hence, components that relied on the implicit
inclusion of those headers have to manually include those headers now.
While adjusting the log messages, I repeatedly stumbled over the problem
that printing char * arguments is ambiguous. It is unclear whether to
print the argument as pointer or null-terminated string. To overcome
this problem, the patch introduces a new type 'Cstring' that allows the
caller to express that the argument should be handled as null-terminated
string. As a nice side effect, with this type in place, the optional len
argument of the 'String' class could be removed. Instead of supplying a
pair of (char const *, size_t), the constructor accepts a 'Cstring'.
This, in turn, clears the way let the 'String' constructor use the new
output mechanism to assemble a string from multiple arguments (and
thereby getting rid of snprintf within Genode in the near future).
To enforce the explicit resolution of the char * ambiguity, the 'char *'
overload of the 'print' function is marked as deleted.
Issue #1987
2016-07-13 19:07:09 +02:00
|
|
|
#include <base/log.h>
|
2011-12-22 16:19:25 +01:00
|
|
|
#include <base/child.h>
|
2016-11-06 14:26:34 +01:00
|
|
|
#include <os/session_requester.h>
|
2015-10-03 21:32:42 +02:00
|
|
|
#include <os/session_policy.h>
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
/* init includes */
|
2017-01-03 18:12:53 +01:00
|
|
|
#include <init/verbose.h>
|
2011-12-22 16:19:25 +01:00
|
|
|
#include <init/child_policy.h>
|
2017-02-16 17:25:59 +01:00
|
|
|
#include <init/report.h>
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
namespace Init {
|
|
|
|
|
2017-02-21 23:07:20 +01:00
|
|
|
class Abandonable;
|
|
|
|
class Parent_service;
|
2017-02-21 17:01:02 +01:00
|
|
|
class Buffered_xml;
|
2015-03-04 21:12:14 +01:00
|
|
|
class Routed_service;
|
|
|
|
class Name_registry;
|
|
|
|
class Child_registry;
|
|
|
|
class Child;
|
2016-11-06 14:26:34 +01:00
|
|
|
|
2017-01-03 18:12:53 +01:00
|
|
|
using namespace Genode;
|
|
|
|
using Genode::size_t;
|
|
|
|
using Genode::strlen;
|
2015-03-04 21:12:14 +01:00
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
/***************
|
|
|
|
** Utilities **
|
|
|
|
***************/
|
|
|
|
|
|
|
|
namespace Init {
|
|
|
|
|
2017-01-03 18:12:53 +01:00
|
|
|
static void warn_insuff_quota(size_t const avail)
|
2015-03-27 14:05:55 +01:00
|
|
|
{
|
2017-01-03 18:12:53 +01:00
|
|
|
warning("specified quota exceeds available quota, "
|
|
|
|
"proceeding with a quota of ", avail);
|
2015-03-27 14:05:55 +01:00
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-03 18:12:53 +01:00
|
|
|
inline long read_priority(Xml_node start_node, long prio_levels)
|
2011-12-22 16:19:25 +01:00
|
|
|
{
|
2017-01-03 18:12:53 +01:00
|
|
|
long priority = Cpu_session::DEFAULT_PRIORITY;
|
2011-12-22 16:19:25 +01:00
|
|
|
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.
|
|
|
|
*/
|
2015-06-25 12:50:01 -05:00
|
|
|
priority = -priority;
|
|
|
|
|
|
|
|
if (priority && (priority >= prio_levels)) {
|
2015-10-03 19:23:32 +02:00
|
|
|
long new_prio = prio_levels ? prio_levels-1 : 0;
|
2017-01-03 18:12:53 +01:00
|
|
|
char name[Service::Name::capacity()];
|
2015-06-25 12:50:01 -05:00
|
|
|
start_node.attribute("name").value(name, sizeof(name));
|
2017-01-03 18:12:53 +01:00
|
|
|
warning(Cstring(name), ": invalid priority, upgrading "
|
|
|
|
"from ", -priority, " to ", -new_prio);
|
2015-06-25 12:50:01 -05:00
|
|
|
return new_prio;
|
|
|
|
}
|
|
|
|
|
|
|
|
return priority;
|
2011-12-22 16:19:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-01-03 18:12:53 +01:00
|
|
|
inline Affinity::Location
|
|
|
|
read_affinity_location(Affinity::Space const &space,
|
|
|
|
Xml_node start_node)
|
2013-08-08 14:18:20 +02:00
|
|
|
{
|
2017-01-03 18:12:53 +01:00
|
|
|
typedef Affinity::Location Location;
|
2013-08-08 14:18:20 +02:00
|
|
|
try {
|
2017-01-03 18:12:53 +01:00
|
|
|
Xml_node node = start_node.sub_node("affinity");
|
2013-08-08 14:18:20 +02:00
|
|
|
|
|
|
|
/* 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<unsigned long>("width", default_width),
|
|
|
|
height = node.attribute_value<unsigned long>("height", default_height);
|
|
|
|
|
|
|
|
long const x1 = node.attribute_value<long>("xpos", 0),
|
|
|
|
y1 = node.attribute_value<long>("ypos", 0),
|
|
|
|
x2 = x1 + width - 1,
|
|
|
|
y2 = y1 + height - 1;
|
|
|
|
|
|
|
|
/* clip location to space boundary */
|
2017-01-03 18:12:53 +01:00
|
|
|
return Location(max(x1, 0L), max(y1, 0L),
|
|
|
|
min((unsigned)(x2 - x1 + 1), space.width()),
|
|
|
|
min((unsigned)(y2 - y1 + 1), space.height()));
|
2013-08-08 14:18:20 +02:00
|
|
|
}
|
|
|
|
catch (...) { return Location(0, 0, space.width(), space.height()); }
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-09-26 21:26:50 +02:00
|
|
|
/**
|
|
|
|
* Return amount of RAM that is currently unused
|
|
|
|
*/
|
2017-01-03 18:12:53 +01:00
|
|
|
static inline size_t avail_slack_ram_quota(size_t ram_avail)
|
2013-09-26 21:26:50 +02:00
|
|
|
{
|
2017-01-03 18:12:53 +01:00
|
|
|
size_t const preserve = 148*1024;
|
2013-09-26 21:26:50 +02:00
|
|
|
|
2017-01-03 18:12:53 +01:00
|
|
|
return ram_avail > preserve ? ram_avail - preserve : 0;
|
2013-09-26 21:26:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-01-10 14:43:15 +01:00
|
|
|
/**
|
|
|
|
* Return sub string of label with the leading child name stripped out
|
2017-01-18 17:10:07 +01:00
|
|
|
*
|
|
|
|
* \return character pointer to the scoped part of the label,
|
|
|
|
* or nullptr if the label is not correctly prefixed with the child's
|
|
|
|
* name
|
2013-01-10 14:43:15 +01:00
|
|
|
*/
|
|
|
|
inline char const *skip_label_prefix(char const *child_name, char const *label)
|
|
|
|
{
|
2017-01-03 18:12:53 +01:00
|
|
|
size_t const child_name_len = strlen(child_name);
|
2013-01-10 14:43:15 +01:00
|
|
|
|
2017-01-18 17:10:07 +01:00
|
|
|
if (strcmp(child_name, label, child_name_len) != 0)
|
|
|
|
return nullptr;
|
2013-01-10 14:43:15 +01:00
|
|
|
|
2017-01-18 17:10:07 +01:00
|
|
|
label += child_name_len;
|
2013-01-10 14:43:15 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Skip label separator. This condition should be always satisfied.
|
|
|
|
*/
|
2017-01-18 17:10:07 +01:00
|
|
|
if (strcmp(" -> ", label, 4) != 0)
|
|
|
|
return nullptr;
|
2013-01-10 14:43:15 +01:00
|
|
|
|
2017-01-18 17:10:07 +01:00
|
|
|
return label + 4;
|
2013-01-10 14:43:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-03 21:32:42 +02:00
|
|
|
/**
|
|
|
|
* 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
|
|
|
|
*/
|
2017-02-15 16:42:49 +01:00
|
|
|
inline bool service_node_matches(Xml_node const service_node,
|
|
|
|
Session_label const &label,
|
2017-01-03 18:12:53 +01:00
|
|
|
Child_policy::Name const &child_name,
|
|
|
|
Service::Name const &service_name)
|
2015-10-03 21:32:42 +02:00
|
|
|
{
|
|
|
|
bool const service_matches =
|
|
|
|
service_node.has_type("any-service") ||
|
|
|
|
(service_node.has_type("service") &&
|
2016-11-06 14:26:34 +01:00
|
|
|
service_node.attribute("name").has_value(service_name.string()));
|
2015-10-03 21:32:42 +02:00
|
|
|
|
|
|
|
if (!service_matches)
|
|
|
|
return false;
|
|
|
|
|
2017-01-18 17:10:07 +01:00
|
|
|
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");
|
2015-10-03 21:32:42 +02:00
|
|
|
|
2017-02-14 16:24:27 +01:00
|
|
|
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<Session_label::capacity()> Label;
|
2017-02-15 16:42:49 +01:00
|
|
|
return label == service_node.attribute_value(unscoped_attr, Label());
|
2017-02-14 16:24:27 +01:00
|
|
|
}
|
|
|
|
|
2017-01-18 17:10:07 +01:00
|
|
|
if (!route_depends_on_child_provided_label)
|
|
|
|
return true;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-18 17:10:07 +01:00
|
|
|
char const * const scoped_label = skip_label_prefix(
|
2017-02-15 16:42:49 +01:00
|
|
|
child_name.string(), label.string());
|
2013-01-10 14:43:15 +01:00
|
|
|
|
2017-01-18 17:10:07 +01:00
|
|
|
if (!scoped_label)
|
|
|
|
return false;
|
2013-01-10 14:43:15 +01:00
|
|
|
|
2017-01-18 17:10:07 +01:00
|
|
|
Session_label const session_label(scoped_label);
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-18 17:10:07 +01:00
|
|
|
return !Xml_node_label_score(service_node, session_label).conflict();
|
2011-12-22 16:19:25 +01:00
|
|
|
}
|
2016-11-06 14:26:34 +01:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if service name is ambiguous
|
|
|
|
*
|
|
|
|
* \return true if the same service is provided multiple
|
|
|
|
* times
|
|
|
|
*
|
|
|
|
* \deprecated
|
|
|
|
*/
|
|
|
|
template <typename T>
|
2017-01-03 18:12:53 +01:00
|
|
|
inline bool is_ambiguous(Registry<T> const &services,
|
2016-11-06 14:26:34 +01:00
|
|
|
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 <typename T>
|
2017-02-21 23:07:20 +01:00
|
|
|
inline T *find_service(Registry<T> &services,
|
|
|
|
Service::Name const &name)
|
2016-11-06 14:26:34 +01:00
|
|
|
{
|
|
|
|
T *service = nullptr;
|
|
|
|
services.for_each([&] (T &s) {
|
|
|
|
if (!service && (s.name() == name))
|
|
|
|
service = &s; });
|
|
|
|
return service;
|
|
|
|
}
|
2017-02-16 17:25:59 +01:00
|
|
|
|
|
|
|
|
|
|
|
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_session &>(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())));
|
|
|
|
}
|
2015-03-04 21:12:14 +01:00
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
|
2017-02-21 23:07:20 +01:00
|
|
|
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<Parent_service>::Element _reg_elem;
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
Parent_service(Registry<Parent_service> ®istry, Env &env,
|
|
|
|
Service::Name const &name)
|
|
|
|
:
|
|
|
|
Genode::Parent_service(env, name), _reg_elem(registry, *this)
|
|
|
|
{ }
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2017-02-21 17:01:02 +01:00
|
|
|
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<char *>(_ptr), _xml.size()); }
|
|
|
|
|
|
|
|
Xml_node xml() const { return _xml; }
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
/**
|
|
|
|
* Init-specific representation of a child service
|
|
|
|
*/
|
2017-02-21 23:07:20 +01:00
|
|
|
class Init::Routed_service : public Child_service, public Abandonable
|
2015-03-04 21:12:14 +01:00
|
|
|
{
|
2016-11-06 14:26:34 +01:00
|
|
|
public:
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-03 18:12:53 +01:00
|
|
|
typedef Child_policy::Name Child_name;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-02-21 23:07:20 +01:00
|
|
|
struct Ram_accessor { virtual Ram_session_capability ram() const = 0; };
|
|
|
|
|
2016-11-06 14:26:34 +01:00
|
|
|
private:
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2016-11-06 14:26:34 +01:00
|
|
|
Child_name _child_name;
|
|
|
|
|
2017-02-21 23:07:20 +01:00
|
|
|
Ram_accessor &_ram_accessor;
|
|
|
|
|
2017-01-03 18:12:53 +01:00
|
|
|
Registry<Routed_service>::Element _registry_element;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
public:
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
/**
|
|
|
|
* Constructor
|
|
|
|
*
|
2016-11-06 14:26:34 +01:00
|
|
|
* \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'.
|
2015-03-04 21:12:14 +01:00
|
|
|
*/
|
2017-01-03 18:12:53 +01:00
|
|
|
Routed_service(Registry<Routed_service> &services,
|
2016-11-06 14:26:34 +01:00
|
|
|
Child_name const &child_name,
|
2017-02-21 23:07:20 +01:00
|
|
|
Ram_accessor &ram_accessor,
|
2016-11-06 14:26:34 +01:00
|
|
|
Id_space<Parent::Server> &server_id_space,
|
|
|
|
Session_state::Factory &factory,
|
|
|
|
Service::Name const &name,
|
|
|
|
Child_service::Wakeup &wakeup)
|
|
|
|
:
|
2017-02-21 23:07:20 +01:00
|
|
|
Child_service(server_id_space, factory, name,
|
|
|
|
Ram_session_capability(), wakeup),
|
|
|
|
_child_name(child_name), _ram_accessor(ram_accessor),
|
|
|
|
_registry_element(services, *this)
|
2016-11-06 14:26:34 +01:00
|
|
|
{ }
|
2015-03-04 21:12:14 +01:00
|
|
|
|
2016-11-06 14:26:34 +01:00
|
|
|
Child_name const &child_name() const { return _child_name; }
|
2017-02-21 23:07:20 +01:00
|
|
|
|
|
|
|
Ram_session_capability ram() const { return _ram_accessor.ram(); }
|
2015-03-04 21:12:14 +01:00
|
|
|
};
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
/**
|
|
|
|
* Interface for name database
|
|
|
|
*/
|
|
|
|
struct Init::Name_registry
|
|
|
|
{
|
|
|
|
virtual ~Name_registry() { }
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-03 18:12:53 +01:00
|
|
|
typedef Child_policy::Name Name;
|
2016-11-06 14:26:34 +01:00
|
|
|
|
2011-12-22 16:19:25 +01:00
|
|
|
/**
|
2015-03-04 21:12:14 +01:00
|
|
|
* Check if specified name is unique
|
|
|
|
*
|
|
|
|
* \return false if name already exists
|
2011-12-22 16:19:25 +01:00
|
|
|
*/
|
2016-05-11 18:21:47 +02:00
|
|
|
virtual bool unique(const char *name) const = 0;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
/**
|
2016-11-06 14:26:34 +01:00
|
|
|
* Return child name for a given alias name
|
|
|
|
*
|
|
|
|
* If there is no alias, the function returns the original name.
|
2015-03-04 21:12:14 +01:00
|
|
|
*/
|
2016-11-06 14:26:34 +01:00
|
|
|
virtual Name deref_alias(Name const &) = 0;
|
2015-03-04 21:12:14 +01:00
|
|
|
};
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
|
2017-01-03 18:12:53 +01:00
|
|
|
class Init::Child : Child_policy, Child_service::Wakeup
|
2015-03-04 21:12:14 +01:00
|
|
|
{
|
|
|
|
public:
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
/**
|
2017-02-19 18:39:46 +01:00
|
|
|
* Exception types
|
2015-03-04 21:12:14 +01:00
|
|
|
*/
|
2017-02-19 18:39:46 +01:00
|
|
|
struct Child_name_is_not_unique : Exception { };
|
|
|
|
struct Missing_name_attribute : Exception { };
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-02-16 17:25:59 +01:00
|
|
|
/**
|
|
|
|
* Unique ID of the child, solely used for diagnostic purposes
|
|
|
|
*/
|
|
|
|
struct Id { unsigned value; };
|
|
|
|
|
2017-02-21 17:01:02 +01:00
|
|
|
struct Default_route_accessor
|
|
|
|
{
|
|
|
|
virtual Xml_node default_route() = 0;
|
|
|
|
};
|
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
private:
|
2013-01-14 12:13:05 +01:00
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
friend class Child_registry;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-03 18:12:53 +01:00
|
|
|
Env &_env;
|
|
|
|
|
base: remove Child::heap
This patch improves the accounting for the backing store of
session-state meta data. Originally, the session state used to be
allocated by a child-local heap partition fed from the child's RAM
session. However, whereas this approach was somehow practical from a
runtime's (parent's) point of view, the child component could not count
on the quota in its own RAM session. I.e., if the Child::heap grew at
the parent side, the child's RAM session would magically diminish. This
caused two problems. First, it violates assumptions of components like
init that carefully manage their RAM resources (and giving most of them
away their children). Second, if a child transfers most of its RAM
session quota to another RAM session (like init does), the child's RAM
session may actually not allow the parent's heap to grow, which is a
very difficult error condition to deal with.
In the new version, there is no Child::heap anymore. Instead, session
states are allocated from the runtime's RAM session. In order to let
children pay for these costs, the parent withdraws the local session
costs from the session quota donated from the child when the child
initiates a new session. Hence, in principle, all components on the
route of the session request take a small bite from the session quota to
pay for their local book keeping
Consequently, the session quota that ends up at the server may become
depleted more or less, depending on the route. In the case where the
remaining quota is insufficient for the server, the server responds with
'QUOTA_EXCEEDED'. Since this behavior must generally be expected, this
patch equips the client-side 'Env::session' implementation with the
ability to re-issue session requests with successively growing quota
donations.
For several of core's services (ROM, IO_MEM, IRQ), the default session
quota has now increased by 2 KiB, which should suffice for session
requests to up to 3 hops as is the common case for most run scripts. For
longer routes, the retry mechanism as described above comes into effect.
For the time being, we give a warning whenever the server-side quota
check triggers the retry mechanism. The warning may eventually be
removed at a later stage.
2017-02-19 10:31:50 +01:00
|
|
|
Allocator &_alloc;
|
|
|
|
|
2017-01-03 18:12:53 +01:00
|
|
|
Verbose const &_verbose;
|
2016-11-06 14:26:34 +01:00
|
|
|
|
2017-02-16 17:25:59 +01:00
|
|
|
Id const _id;
|
|
|
|
|
2017-02-21 23:07:20 +01:00
|
|
|
enum State { STATE_INITIAL, STATE_RAM_INITIALIZED, STATE_ALIVE,
|
|
|
|
STATE_ABANDONED };
|
|
|
|
|
|
|
|
State _state = STATE_INITIAL;
|
|
|
|
|
2017-02-16 17:25:59 +01:00
|
|
|
Report_update_trigger &_report_update_trigger;
|
|
|
|
|
2017-01-03 18:12:53 +01:00
|
|
|
List_element<Child> _list_element;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-02-21 17:01:02 +01:00
|
|
|
Reconstructible<Buffered_xml> _start_node;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-02-21 17:01:02 +01:00
|
|
|
Default_route_accessor &_default_route_accessor;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2016-04-27 16:04:58 +02:00
|
|
|
Name_registry &_name_registry;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-02-19 18:39:46 +01:00
|
|
|
typedef String<64> Name;
|
|
|
|
|
|
|
|
struct Unique_name : Name
|
2015-03-04 21:12:14 +01:00
|
|
|
{
|
2017-02-19 18:39:46 +01:00
|
|
|
/**
|
|
|
|
* 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 '<start>' 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();
|
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
/**
|
2015-03-04 21:12:14 +01:00
|
|
|
* Constructor
|
|
|
|
*
|
|
|
|
* Obtains file name and unique process name from XML node
|
|
|
|
*
|
|
|
|
* \param start_node XML start node
|
|
|
|
* \param registry registry tracking unique names
|
2017-02-19 18:39:46 +01:00
|
|
|
*
|
|
|
|
* \throw Missing_name_attribute
|
2011-12-22 16:19:25 +01:00
|
|
|
*/
|
2017-02-19 18:39:46 +01:00
|
|
|
Unique_name(Xml_node start_node, Name_registry const ®istry)
|
|
|
|
: Name(_checked(start_node, registry)) { }
|
2015-03-04 21:12:14 +01:00
|
|
|
|
2017-02-19 18:39:46 +01:00
|
|
|
} _unique_name;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-02-19 18:39:46 +01:00
|
|
|
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;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-02-19 18:39:46 +01:00
|
|
|
return start_node.sub_node("binary").attribute_value("name", Name());
|
|
|
|
}
|
|
|
|
|
|
|
|
Binary_name const _binary_name;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
struct Read_quota
|
|
|
|
{
|
2017-01-03 18:12:53 +01:00
|
|
|
Read_quota(Xml_node start_node,
|
|
|
|
size_t &ram_quota,
|
|
|
|
size_t &cpu_quota_pc,
|
|
|
|
bool &constrain_phys,
|
|
|
|
size_t const ram_avail,
|
|
|
|
Verbose const &verbose)
|
2014-10-16 11:15:46 +02:00
|
|
|
{
|
2015-10-28 16:14:14 +01:00
|
|
|
cpu_quota_pc = 0;
|
|
|
|
constrain_phys = false;
|
|
|
|
|
2017-01-03 18:12:53 +01:00
|
|
|
Number_of_bytes ram_bytes = 0;
|
2014-10-16 11:15:46 +02:00
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
try {
|
2017-01-03 18:12:53 +01:00
|
|
|
Xml_node rsc = start_node.sub_node("resource");
|
2015-03-04 21:12:14 +01:00
|
|
|
for (;; rsc = rsc.next("resource")) {
|
|
|
|
try {
|
|
|
|
if (rsc.attribute("name").has_value("RAM")) {
|
|
|
|
rsc.attribute("quantum").value(&ram_bytes);
|
2016-06-09 15:55:13 +02:00
|
|
|
constrain_phys = rsc.attribute_value("constrain_phys", false);
|
2015-03-04 21:12:14 +01:00
|
|
|
} else if (rsc.attribute("name").has_value("CPU")) {
|
2015-03-27 14:05:55 +01:00
|
|
|
rsc.attribute("quantum").value(&cpu_quota_pc); }
|
2015-03-04 21:12:14 +01:00
|
|
|
} catch (...) { }
|
2014-10-16 11:15:46 +02:00
|
|
|
}
|
2015-03-04 21:12:14 +01:00
|
|
|
} catch (...) { }
|
|
|
|
ram_quota = ram_bytes;
|
2014-10-16 11:15:46 +02:00
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
/*
|
|
|
|
* If the configured RAM quota exceeds our own quota, we donate
|
base: remove Child::heap
This patch improves the accounting for the backing store of
session-state meta data. Originally, the session state used to be
allocated by a child-local heap partition fed from the child's RAM
session. However, whereas this approach was somehow practical from a
runtime's (parent's) point of view, the child component could not count
on the quota in its own RAM session. I.e., if the Child::heap grew at
the parent side, the child's RAM session would magically diminish. This
caused two problems. First, it violates assumptions of components like
init that carefully manage their RAM resources (and giving most of them
away their children). Second, if a child transfers most of its RAM
session quota to another RAM session (like init does), the child's RAM
session may actually not allow the parent's heap to grow, which is a
very difficult error condition to deal with.
In the new version, there is no Child::heap anymore. Instead, session
states are allocated from the runtime's RAM session. In order to let
children pay for these costs, the parent withdraws the local session
costs from the session quota donated from the child when the child
initiates a new session. Hence, in principle, all components on the
route of the session request take a small bite from the session quota to
pay for their local book keeping
Consequently, the session quota that ends up at the server may become
depleted more or less, depending on the route. In the case where the
remaining quota is insufficient for the server, the server responds with
'QUOTA_EXCEEDED'. Since this behavior must generally be expected, this
patch equips the client-side 'Env::session' implementation with the
ability to re-issue session requests with successively growing quota
donations.
For several of core's services (ROM, IO_MEM, IRQ), the default session
quota has now increased by 2 KiB, which should suffice for session
requests to up to 3 hops as is the common case for most run scripts. For
longer routes, the retry mechanism as described above comes into effect.
For the time being, we give a warning whenever the server-side quota
check triggers the retry mechanism. The warning may eventually be
removed at a later stage.
2017-02-19 10:31:50 +01:00
|
|
|
* all remaining quota to the child.
|
2015-03-04 21:12:14 +01:00
|
|
|
*/
|
|
|
|
if (ram_quota > ram_avail) {
|
|
|
|
ram_quota = ram_avail;
|
2017-01-03 18:12:53 +01:00
|
|
|
|
|
|
|
if (verbose.enabled())
|
|
|
|
warn_insuff_quota(ram_avail);
|
2011-12-22 16:19:25 +01:00
|
|
|
}
|
2015-03-04 21:12:14 +01:00
|
|
|
}
|
|
|
|
};
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
/**
|
|
|
|
* Resources assigned to the child
|
|
|
|
*/
|
|
|
|
struct Resources : Read_quota
|
|
|
|
{
|
2017-01-03 18:12:53 +01:00
|
|
|
long prio_levels_log2;
|
|
|
|
long priority;
|
|
|
|
Affinity affinity;
|
|
|
|
size_t ram_quota;
|
|
|
|
size_t cpu_quota_pc;
|
|
|
|
bool constrain_phys;
|
|
|
|
|
2017-02-19 18:39:46 +01:00
|
|
|
Resources(Xml_node start_node, long prio_levels,
|
|
|
|
Affinity::Space const &affinity_space, size_t ram_avail,
|
2017-01-03 18:12:53 +01:00
|
|
|
Verbose const &verbose)
|
2015-03-04 21:12:14 +01:00
|
|
|
:
|
2017-01-03 18:12:53 +01:00
|
|
|
Read_quota(start_node, ram_quota, cpu_quota_pc,
|
|
|
|
constrain_phys, ram_avail, verbose),
|
|
|
|
prio_levels_log2(log2(prio_levels)),
|
2015-06-25 12:50:01 -05:00
|
|
|
priority(read_priority(start_node, prio_levels)),
|
2015-03-04 21:12:14 +01:00
|
|
|
affinity(affinity_space,
|
2016-11-06 14:26:34 +01:00
|
|
|
read_affinity_location(affinity_space, start_node))
|
2015-03-04 21:12:14 +01:00
|
|
|
{
|
|
|
|
/* deduce session costs from usable ram quota */
|
2016-11-06 14:26:34 +01:00
|
|
|
ram_quota = Genode::Child::effective_ram_quota(ram_quota);
|
2015-03-04 21:12:14 +01:00
|
|
|
}
|
|
|
|
} _resources;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-03 18:12:53 +01:00
|
|
|
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() };
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-03 18:12:53 +01:00
|
|
|
Registry<Parent_service> &_parent_services;
|
|
|
|
Registry<Routed_service> &_child_services;
|
2016-11-06 14:26:34 +01:00
|
|
|
|
2017-02-21 23:07:20 +01:00
|
|
|
struct Inline_config_rom_service : Abandonable, Dynamic_rom_session::Content_producer
|
|
|
|
{
|
|
|
|
typedef Local_service<Dynamic_rom_session> 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("<config/>");
|
|
|
|
|
|
|
|
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<Inline_config_rom_service> _config_rom_service;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-03 18:12:53 +01:00
|
|
|
Session_requester _session_requester;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
/**
|
|
|
|
* Policy helpers
|
|
|
|
*/
|
|
|
|
Init::Child_policy_handle_cpu_priorities _priority_policy;
|
|
|
|
Init::Child_policy_ram_phys _ram_session_policy;
|
|
|
|
|
2017-01-03 18:12:53 +01:00
|
|
|
Genode::Child _child { _env.rm(), _env.ep().rpc_ep(), *this };
|
2016-11-06 14:26:34 +01:00
|
|
|
|
2017-02-21 23:07:20 +01:00
|
|
|
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 };
|
|
|
|
|
2016-11-06 14:26:34 +01:00
|
|
|
/**
|
|
|
|
* Child_service::Wakeup callback
|
|
|
|
*/
|
|
|
|
void wakeup_child_service() override
|
|
|
|
{
|
|
|
|
_session_requester.trigger_update();
|
|
|
|
}
|
|
|
|
|
2017-02-21 23:07:20 +01:00
|
|
|
/**
|
|
|
|
* 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; }
|
|
|
|
}
|
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
public:
|
|
|
|
|
2016-11-06 14:26:34 +01:00
|
|
|
/**
|
|
|
|
* Constructor
|
|
|
|
*
|
base: remove Child::heap
This patch improves the accounting for the backing store of
session-state meta data. Originally, the session state used to be
allocated by a child-local heap partition fed from the child's RAM
session. However, whereas this approach was somehow practical from a
runtime's (parent's) point of view, the child component could not count
on the quota in its own RAM session. I.e., if the Child::heap grew at
the parent side, the child's RAM session would magically diminish. This
caused two problems. First, it violates assumptions of components like
init that carefully manage their RAM resources (and giving most of them
away their children). Second, if a child transfers most of its RAM
session quota to another RAM session (like init does), the child's RAM
session may actually not allow the parent's heap to grow, which is a
very difficult error condition to deal with.
In the new version, there is no Child::heap anymore. Instead, session
states are allocated from the runtime's RAM session. In order to let
children pay for these costs, the parent withdraws the local session
costs from the session quota donated from the child when the child
initiates a new session. Hence, in principle, all components on the
route of the session request take a small bite from the session quota to
pay for their local book keeping
Consequently, the session quota that ends up at the server may become
depleted more or less, depending on the route. In the case where the
remaining quota is insufficient for the server, the server responds with
'QUOTA_EXCEEDED'. Since this behavior must generally be expected, this
patch equips the client-side 'Env::session' implementation with the
ability to re-issue session requests with successively growing quota
donations.
For several of core's services (ROM, IO_MEM, IRQ), the default session
quota has now increased by 2 KiB, which should suffice for session
requests to up to 3 hops as is the common case for most run scripts. For
longer routes, the retry mechanism as described above comes into effect.
For the time being, we give a warning whenever the server-side quota
check triggers the retry mechanism. The warning may eventually be
removed at a later stage.
2017-02-19 10:31:50 +01:00
|
|
|
* \param alloc allocator solely used for configuration-dependent
|
|
|
|
* allocations. It is not used for allocations on behalf
|
|
|
|
* of the child's behavior.
|
|
|
|
*
|
|
|
|
*
|
2016-11-06 14:26:34 +01:00
|
|
|
* \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
|
2017-02-21 17:01:02 +01:00
|
|
|
* \throw Allocator::Out_of_memory could not buffer the XML start node
|
2016-11-06 14:26:34 +01:00
|
|
|
*/
|
2017-01-03 18:12:53 +01:00
|
|
|
Child(Env &env,
|
base: remove Child::heap
This patch improves the accounting for the backing store of
session-state meta data. Originally, the session state used to be
allocated by a child-local heap partition fed from the child's RAM
session. However, whereas this approach was somehow practical from a
runtime's (parent's) point of view, the child component could not count
on the quota in its own RAM session. I.e., if the Child::heap grew at
the parent side, the child's RAM session would magically diminish. This
caused two problems. First, it violates assumptions of components like
init that carefully manage their RAM resources (and giving most of them
away their children). Second, if a child transfers most of its RAM
session quota to another RAM session (like init does), the child's RAM
session may actually not allow the parent's heap to grow, which is a
very difficult error condition to deal with.
In the new version, there is no Child::heap anymore. Instead, session
states are allocated from the runtime's RAM session. In order to let
children pay for these costs, the parent withdraws the local session
costs from the session quota donated from the child when the child
initiates a new session. Hence, in principle, all components on the
route of the session request take a small bite from the session quota to
pay for their local book keeping
Consequently, the session quota that ends up at the server may become
depleted more or less, depending on the route. In the case where the
remaining quota is insufficient for the server, the server responds with
'QUOTA_EXCEEDED'. Since this behavior must generally be expected, this
patch equips the client-side 'Env::session' implementation with the
ability to re-issue session requests with successively growing quota
donations.
For several of core's services (ROM, IO_MEM, IRQ), the default session
quota has now increased by 2 KiB, which should suffice for session
requests to up to 3 hops as is the common case for most run scripts. For
longer routes, the retry mechanism as described above comes into effect.
For the time being, we give a warning whenever the server-side quota
check triggers the retry mechanism. The warning may eventually be
removed at a later stage.
2017-02-19 10:31:50 +01:00
|
|
|
Allocator &alloc,
|
2017-01-03 18:12:53 +01:00
|
|
|
Verbose const &verbose,
|
2017-02-16 17:25:59 +01:00
|
|
|
Id id,
|
|
|
|
Report_update_trigger &report_update_trigger,
|
2017-01-03 18:12:53 +01:00
|
|
|
Xml_node start_node,
|
2017-02-21 17:01:02 +01:00
|
|
|
Default_route_accessor &default_route_accessor,
|
2017-01-03 18:12:53 +01:00
|
|
|
Name_registry &name_registry,
|
|
|
|
long prio_levels,
|
|
|
|
Affinity::Space const &affinity_space,
|
|
|
|
Registry<Parent_service> &parent_services,
|
|
|
|
Registry<Routed_service> &child_services)
|
2015-03-04 21:12:14 +01:00
|
|
|
:
|
base: remove Child::heap
This patch improves the accounting for the backing store of
session-state meta data. Originally, the session state used to be
allocated by a child-local heap partition fed from the child's RAM
session. However, whereas this approach was somehow practical from a
runtime's (parent's) point of view, the child component could not count
on the quota in its own RAM session. I.e., if the Child::heap grew at
the parent side, the child's RAM session would magically diminish. This
caused two problems. First, it violates assumptions of components like
init that carefully manage their RAM resources (and giving most of them
away their children). Second, if a child transfers most of its RAM
session quota to another RAM session (like init does), the child's RAM
session may actually not allow the parent's heap to grow, which is a
very difficult error condition to deal with.
In the new version, there is no Child::heap anymore. Instead, session
states are allocated from the runtime's RAM session. In order to let
children pay for these costs, the parent withdraws the local session
costs from the session quota donated from the child when the child
initiates a new session. Hence, in principle, all components on the
route of the session request take a small bite from the session quota to
pay for their local book keeping
Consequently, the session quota that ends up at the server may become
depleted more or less, depending on the route. In the case where the
remaining quota is insufficient for the server, the server responds with
'QUOTA_EXCEEDED'. Since this behavior must generally be expected, this
patch equips the client-side 'Env::session' implementation with the
ability to re-issue session requests with successively growing quota
donations.
For several of core's services (ROM, IO_MEM, IRQ), the default session
quota has now increased by 2 KiB, which should suffice for session
requests to up to 3 hops as is the common case for most run scripts. For
longer routes, the retry mechanism as described above comes into effect.
For the time being, we give a warning whenever the server-side quota
check triggers the retry mechanism. The warning may eventually be
removed at a later stage.
2017-02-19 10:31:50 +01:00
|
|
|
_env(env), _alloc(alloc), _verbose(verbose), _id(id),
|
2017-02-16 17:25:59 +01:00
|
|
|
_report_update_trigger(report_update_trigger),
|
2015-03-04 21:12:14 +01:00
|
|
|
_list_element(this),
|
2017-02-21 17:01:02 +01:00
|
|
|
_start_node(_alloc, start_node),
|
|
|
|
_default_route_accessor(default_route_accessor),
|
2015-03-04 21:12:14 +01:00
|
|
|
_name_registry(name_registry),
|
2017-02-19 18:39:46 +01:00
|
|
|
_unique_name(start_node, name_registry),
|
|
|
|
_binary_name(_binary_name_from_xml(start_node, _unique_name)),
|
|
|
|
_resources(start_node, prio_levels, affinity_space,
|
|
|
|
avail_slack_ram_quota(_env.ram().avail()), _verbose),
|
2015-03-04 21:12:14 +01:00
|
|
|
_parent_services(parent_services),
|
|
|
|
_child_services(child_services),
|
2017-01-03 18:12:53 +01:00
|
|
|
_session_requester(_env.ep().rpc_ep(), _env.ram(), _env.rm()),
|
2015-03-04 21:12:14 +01:00
|
|
|
_priority_policy(_resources.prio_levels_log2, _resources.priority),
|
|
|
|
_ram_session_policy(_resources.constrain_phys)
|
|
|
|
{
|
|
|
|
if (_resources.ram_quota == 0)
|
2017-01-03 18:12:53 +01:00
|
|
|
warning("no valid RAM resource for child "
|
2017-02-19 18:39:46 +01:00
|
|
|
"\"", _unique_name, "\"");
|
2015-03-04 21:12:14 +01:00
|
|
|
|
2017-01-03 18:12:53 +01:00
|
|
|
if (_verbose.enabled()) {
|
2017-02-19 18:39:46 +01:00
|
|
|
log("child \"", _unique_name, "\"");
|
2016-11-06 14:26:34 +01:00
|
|
|
log(" RAM quota: ", _resources.ram_quota);
|
2017-02-19 18:39:46 +01:00
|
|
|
log(" ELF binary: ", _binary_name);
|
2016-11-06 14:26:34 +01:00
|
|
|
log(" priority: ", _resources.priority);
|
2015-03-04 21:12:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Determine services provided by the child
|
|
|
|
*/
|
|
|
|
try {
|
|
|
|
Xml_node service_node = start_node.sub_node("provides").sub_node("service");
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
for (; ; service_node = service_node.next("service")) {
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-03 18:12:53 +01:00
|
|
|
char name[Service::Name::capacity()];
|
2015-03-04 21:12:14 +01:00
|
|
|
service_node.attribute("name").value(name, sizeof(name));
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-03 18:12:53 +01:00
|
|
|
if (_verbose.enabled())
|
|
|
|
log(" provides service ", Cstring(name));
|
2011-12-22 16:19:25 +01:00
|
|
|
|
base: remove Child::heap
This patch improves the accounting for the backing store of
session-state meta data. Originally, the session state used to be
allocated by a child-local heap partition fed from the child's RAM
session. However, whereas this approach was somehow practical from a
runtime's (parent's) point of view, the child component could not count
on the quota in its own RAM session. I.e., if the Child::heap grew at
the parent side, the child's RAM session would magically diminish. This
caused two problems. First, it violates assumptions of components like
init that carefully manage their RAM resources (and giving most of them
away their children). Second, if a child transfers most of its RAM
session quota to another RAM session (like init does), the child's RAM
session may actually not allow the parent's heap to grow, which is a
very difficult error condition to deal with.
In the new version, there is no Child::heap anymore. Instead, session
states are allocated from the runtime's RAM session. In order to let
children pay for these costs, the parent withdraws the local session
costs from the session quota donated from the child when the child
initiates a new session. Hence, in principle, all components on the
route of the session request take a small bite from the session quota to
pay for their local book keeping
Consequently, the session quota that ends up at the server may become
depleted more or less, depending on the route. In the case where the
remaining quota is insufficient for the server, the server responds with
'QUOTA_EXCEEDED'. Since this behavior must generally be expected, this
patch equips the client-side 'Env::session' implementation with the
ability to re-issue session requests with successively growing quota
donations.
For several of core's services (ROM, IO_MEM, IRQ), the default session
quota has now increased by 2 KiB, which should suffice for session
requests to up to 3 hops as is the common case for most run scripts. For
longer routes, the retry mechanism as described above comes into effect.
For the time being, we give a warning whenever the server-side quota
check triggers the retry mechanism. The warning may eventually be
removed at a later stage.
2017-02-19 10:31:50 +01:00
|
|
|
new (_alloc)
|
2017-02-21 23:07:20 +01:00
|
|
|
Routed_service(child_services, this->name(), _ram_accessor,
|
2016-11-06 14:26:34 +01:00
|
|
|
_session_requester.id_space(),
|
|
|
|
_child.session_factory(),
|
2017-02-21 23:07:20 +01:00
|
|
|
name, *this);
|
2014-03-13 13:13:21 +01:00
|
|
|
}
|
2017-01-18 17:10:07 +01:00
|
|
|
}
|
|
|
|
catch (Xml_node::Nonexistent_sub_node) { }
|
2017-02-21 23:07:20 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Construct inline config ROM service if "config" node is present.
|
|
|
|
*/
|
|
|
|
if (start_node.has_sub_node("config"))
|
|
|
|
_config_rom_service.construct(*this);
|
2015-03-04 21:12:14 +01:00
|
|
|
}
|
|
|
|
|
2016-11-06 14:26:34 +01:00
|
|
|
virtual ~Child()
|
|
|
|
{
|
|
|
|
_child_services.for_each([&] (Routed_service &service) {
|
|
|
|
if (service.has_id_space(_session_requester.id_space()))
|
base: remove Child::heap
This patch improves the accounting for the backing store of
session-state meta data. Originally, the session state used to be
allocated by a child-local heap partition fed from the child's RAM
session. However, whereas this approach was somehow practical from a
runtime's (parent's) point of view, the child component could not count
on the quota in its own RAM session. I.e., if the Child::heap grew at
the parent side, the child's RAM session would magically diminish. This
caused two problems. First, it violates assumptions of components like
init that carefully manage their RAM resources (and giving most of them
away their children). Second, if a child transfers most of its RAM
session quota to another RAM session (like init does), the child's RAM
session may actually not allow the parent's heap to grow, which is a
very difficult error condition to deal with.
In the new version, there is no Child::heap anymore. Instead, session
states are allocated from the runtime's RAM session. In order to let
children pay for these costs, the parent withdraws the local session
costs from the session quota donated from the child when the child
initiates a new session. Hence, in principle, all components on the
route of the session request take a small bite from the session quota to
pay for their local book keeping
Consequently, the session quota that ends up at the server may become
depleted more or less, depending on the route. In the case where the
remaining quota is insufficient for the server, the server responds with
'QUOTA_EXCEEDED'. Since this behavior must generally be expected, this
patch equips the client-side 'Env::session' implementation with the
ability to re-issue session requests with successively growing quota
donations.
For several of core's services (ROM, IO_MEM, IRQ), the default session
quota has now increased by 2 KiB, which should suffice for session
requests to up to 3 hops as is the common case for most run scripts. For
longer routes, the retry mechanism as described above comes into effect.
For the time being, we give a warning whenever the server-side quota
check triggers the retry mechanism. The warning may eventually be
removed at a later stage.
2017-02-19 10:31:50 +01:00
|
|
|
destroy(_alloc, &service); });
|
2015-03-04 21:12:14 +01:00
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
/**
|
|
|
|
* Return true if the child has the specified name
|
|
|
|
*/
|
2016-11-06 14:26:34 +01:00
|
|
|
bool has_name(Child_policy::Name const &str) const { return str == name(); }
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-02-21 23:07:20 +01:00
|
|
|
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.phase != Session_state::AVAILABLE)
|
|
|
|
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;
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* 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 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NO_SIDE_EFFECTS;
|
|
|
|
}
|
|
|
|
|
2017-02-16 17:25:59 +01:00
|
|
|
void report_state(Xml_generator &xml, Report_detail const &detail) const
|
|
|
|
{
|
|
|
|
xml.node("child", [&] () {
|
|
|
|
|
2017-02-19 18:39:46 +01:00
|
|
|
xml.attribute("name", _unique_name);
|
|
|
|
xml.attribute("binary", _binary_name);
|
2017-02-16 17:25:59 +01:00
|
|
|
|
|
|
|
if (detail.ids())
|
|
|
|
xml.attribute("id", _id.value);
|
|
|
|
|
|
|
|
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<Genode::Child &>(_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<Session_state const>(fn);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
/****************************
|
|
|
|
** Child-policy interface **
|
|
|
|
****************************/
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-02-19 18:39:46 +01:00
|
|
|
Child_policy::Name name() const override { return _unique_name; }
|
2016-11-06 14:26:34 +01:00
|
|
|
|
2017-02-19 18:39:46 +01:00
|
|
|
Binary_name binary_name() const override { return _binary_name; }
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-03 18:12:53 +01:00
|
|
|
Ram_session &ref_ram() override { return _env.ram(); }
|
|
|
|
Ram_session_capability ref_ram_cap() const override { return _env.ram_session_cap(); }
|
2016-11-06 14:26:34 +01:00
|
|
|
|
2017-01-03 18:12:53 +01:00
|
|
|
void init(Ram_session &session, Ram_session_capability cap) override
|
2015-03-04 21:12:14 +01:00
|
|
|
{
|
2017-01-03 18:12:53 +01:00
|
|
|
session.ref_account(_env.ram_session_cap());
|
|
|
|
_env.ram().transfer_quota(cap, _resources.ram_quota);
|
2016-11-06 14:26:34 +01:00
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-03 18:12:53 +01:00
|
|
|
void init(Cpu_session &session, Cpu_session_capability cap) override
|
2016-11-06 14:26:34 +01:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2017-01-03 18:12:53 +01:00
|
|
|
Id_space<Parent::Server> &server_id_space() override {
|
2016-11-06 14:26:34 +01:00
|
|
|
return _session_requester.id_space(); }
|
|
|
|
|
2017-02-15 16:42:49 +01:00
|
|
|
Route resolve_session_request(Service::Name const &service_name,
|
|
|
|
Session_label const &label) override
|
2016-11-06 14:26:34 +01:00
|
|
|
{
|
|
|
|
/* check for "config" ROM request */
|
2017-02-21 23:07:20 +01:00
|
|
|
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 <configfile> tag will
|
|
|
|
* be removed
|
|
|
|
*/
|
|
|
|
if (_start_node->xml().has_sub_node("configfile")) {
|
|
|
|
|
|
|
|
typedef String<50> Name;
|
|
|
|
Name const rom =
|
|
|
|
_start_node->xml().sub_node("configfile")
|
|
|
|
.attribute_value("name", Name());
|
|
|
|
|
|
|
|
/* prevent infinite recursion */
|
|
|
|
if (rom == "config") {
|
|
|
|
error("configfile must not be named 'config'");
|
|
|
|
throw Parent::Service_denied();
|
|
|
|
}
|
|
|
|
|
|
|
|
return resolve_session_request(service_name,
|
|
|
|
prefixed_label(name(), rom));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If there is neither an inline '<config>' nor a
|
|
|
|
* '<configfile>' node present, we apply the regular session
|
|
|
|
* routing to the "config" ROM request.
|
|
|
|
*/
|
|
|
|
}
|
2016-11-06 14:26:34 +01:00
|
|
|
|
|
|
|
/* check for "session_requests" ROM request */
|
2017-01-03 18:12:53 +01:00
|
|
|
if (service_name == Rom_session::service_name()
|
|
|
|
&& label.last_element() == Session_requester::rom_name())
|
2017-02-15 16:42:49 +01:00
|
|
|
return Route { _session_requester.service() };
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
try {
|
2017-02-21 17:01:02 +01:00
|
|
|
Xml_node route_node = _default_route_accessor.default_route();
|
2011-12-22 16:19:25 +01:00
|
|
|
try {
|
2017-02-21 17:01:02 +01:00
|
|
|
route_node = _start_node->xml().sub_node("route"); }
|
2015-03-04 21:12:14 +01:00
|
|
|
catch (...) { }
|
2017-01-03 18:12:53 +01:00
|
|
|
Xml_node service_node = route_node.sub_node();
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
for (; ; service_node = service_node.next()) {
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
bool service_wildcard = service_node.has_type("any-service");
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-02-15 16:42:49 +01:00
|
|
|
if (!service_node_matches(service_node, label, name(), service_name))
|
2015-03-04 21:12:14 +01:00
|
|
|
continue;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-03 18:12:53 +01:00
|
|
|
Xml_node target = service_node.sub_node();
|
2015-03-04 21:12:14 +01:00
|
|
|
for (; ; target = target.next()) {
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-02-15 16:42:49 +01:00
|
|
|
/*
|
|
|
|
* Determine session label to be provided to the server.
|
|
|
|
*
|
|
|
|
* By default, the client's identity (accompanied with
|
|
|
|
* the a client-provided label) is presented as session
|
|
|
|
* label to the server. However, the target node can
|
|
|
|
* explicitly override the client's identity by a
|
|
|
|
* custom label via the 'label' attribute.
|
|
|
|
*/
|
|
|
|
typedef String<Session_label::capacity()> Label;
|
|
|
|
Label const target_label =
|
|
|
|
target.attribute_value("label", Label(label.string()));
|
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
if (target.has_type("parent")) {
|
2016-11-06 14:26:34 +01:00
|
|
|
|
2017-02-21 23:07:20 +01:00
|
|
|
Parent_service *service = nullptr;
|
|
|
|
|
2016-11-06 14:26:34 +01:00
|
|
|
if ((service = find_service(_parent_services, service_name)))
|
2017-02-15 16:42:49 +01:00
|
|
|
return Route { *service, target_label };
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-02-21 23:07:20 +01:00
|
|
|
if (service && service->abandoned())
|
|
|
|
throw Parent::Service_denied();
|
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
if (!service_wildcard) {
|
base: avoid use of deprecated base/printf.h
Besides adapting the components to the use of base/log.h, the patch
cleans up a few base headers, i.e., it removes unused includes from
root/component.h, specifically base/heap.h and
ram_session/ram_session.h. Hence, components that relied on the implicit
inclusion of those headers have to manually include those headers now.
While adjusting the log messages, I repeatedly stumbled over the problem
that printing char * arguments is ambiguous. It is unclear whether to
print the argument as pointer or null-terminated string. To overcome
this problem, the patch introduces a new type 'Cstring' that allows the
caller to express that the argument should be handled as null-terminated
string. As a nice side effect, with this type in place, the optional len
argument of the 'String' class could be removed. Instead of supplying a
pair of (char const *, size_t), the constructor accepts a 'Cstring'.
This, in turn, clears the way let the 'String' constructor use the new
output mechanism to assemble a string from multiple arguments (and
thereby getting rid of snprintf within Genode in the near future).
To enforce the explicit resolution of the char * ambiguity, the 'char *'
overload of the 'print' function is marked as deleted.
Issue #1987
2016-07-13 19:07:09 +02:00
|
|
|
warning(name(), ": service lookup for "
|
|
|
|
"\"", service_name, "\" at parent failed");
|
2017-01-03 18:12:53 +01:00
|
|
|
throw Parent::Service_denied();
|
2011-12-22 16:19:25 +01:00
|
|
|
}
|
2015-03-04 21:12:14 +01:00
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
if (target.has_type("child")) {
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2016-11-06 14:26:34 +01:00
|
|
|
typedef Name_registry::Name Name;
|
|
|
|
Name server_name = target.attribute_value("name", Name());
|
|
|
|
server_name = _name_registry.deref_alias(server_name);
|
|
|
|
|
2017-02-21 23:07:20 +01:00
|
|
|
Routed_service *service = nullptr;
|
|
|
|
|
2016-11-06 14:26:34 +01:00
|
|
|
_child_services.for_each([&] (Routed_service &s) {
|
|
|
|
if (s.name() == Service::Name(service_name)
|
|
|
|
&& s.child_name() == server_name)
|
|
|
|
service = &s; });
|
2017-02-21 23:07:20 +01:00
|
|
|
|
|
|
|
if (service && service->abandoned())
|
|
|
|
throw Parent::Service_denied();
|
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
if (service)
|
2017-02-15 16:42:49 +01:00
|
|
|
return Route { *service, target_label };
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
if (!service_wildcard) {
|
2017-01-03 18:12:53 +01:00
|
|
|
warning(name(), ": lookup to child "
|
|
|
|
"server \"", server_name, "\" failed");
|
|
|
|
throw Parent::Service_denied();
|
2011-12-22 16:19:25 +01:00
|
|
|
}
|
2015-03-04 21:12:14 +01:00
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
if (target.has_type("any-child")) {
|
2017-02-21 23:07:20 +01:00
|
|
|
|
2016-11-06 14:26:34 +01:00
|
|
|
if (is_ambiguous(_child_services, service_name)) {
|
base: avoid use of deprecated base/printf.h
Besides adapting the components to the use of base/log.h, the patch
cleans up a few base headers, i.e., it removes unused includes from
root/component.h, specifically base/heap.h and
ram_session/ram_session.h. Hence, components that relied on the implicit
inclusion of those headers have to manually include those headers now.
While adjusting the log messages, I repeatedly stumbled over the problem
that printing char * arguments is ambiguous. It is unclear whether to
print the argument as pointer or null-terminated string. To overcome
this problem, the patch introduces a new type 'Cstring' that allows the
caller to express that the argument should be handled as null-terminated
string. As a nice side effect, with this type in place, the optional len
argument of the 'String' class could be removed. Instead of supplying a
pair of (char const *, size_t), the constructor accepts a 'Cstring'.
This, in turn, clears the way let the 'String' constructor use the new
output mechanism to assemble a string from multiple arguments (and
thereby getting rid of snprintf within Genode in the near future).
To enforce the explicit resolution of the char * ambiguity, the 'char *'
overload of the 'print' function is marked as deleted.
Issue #1987
2016-07-13 19:07:09 +02:00
|
|
|
error(name(), ": ambiguous routes to "
|
|
|
|
"service \"", service_name, "\"");
|
2017-01-03 18:12:53 +01:00
|
|
|
throw Parent::Service_denied();
|
2011-12-22 16:19:25 +01:00
|
|
|
}
|
2016-11-06 14:26:34 +01:00
|
|
|
|
2017-02-21 23:07:20 +01:00
|
|
|
Routed_service *service = nullptr;
|
|
|
|
|
2016-11-06 14:26:34 +01:00
|
|
|
if ((service = find_service(_child_services, service_name)))
|
2017-02-15 16:42:49 +01:00
|
|
|
return Route { *service, target_label };
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
if (!service_wildcard) {
|
base: avoid use of deprecated base/printf.h
Besides adapting the components to the use of base/log.h, the patch
cleans up a few base headers, i.e., it removes unused includes from
root/component.h, specifically base/heap.h and
ram_session/ram_session.h. Hence, components that relied on the implicit
inclusion of those headers have to manually include those headers now.
While adjusting the log messages, I repeatedly stumbled over the problem
that printing char * arguments is ambiguous. It is unclear whether to
print the argument as pointer or null-terminated string. To overcome
this problem, the patch introduces a new type 'Cstring' that allows the
caller to express that the argument should be handled as null-terminated
string. As a nice side effect, with this type in place, the optional len
argument of the 'String' class could be removed. Instead of supplying a
pair of (char const *, size_t), the constructor accepts a 'Cstring'.
This, in turn, clears the way let the 'String' constructor use the new
output mechanism to assemble a string from multiple arguments (and
thereby getting rid of snprintf within Genode in the near future).
To enforce the explicit resolution of the char * ambiguity, the 'char *'
overload of the 'print' function is marked as deleted.
Issue #1987
2016-07-13 19:07:09 +02:00
|
|
|
warning(name(), ": lookup for service "
|
|
|
|
"\"", service_name, "\" failed");
|
2017-01-03 18:12:53 +01:00
|
|
|
throw Parent::Service_denied();
|
2015-03-04 21:12:14 +01:00
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
}
|
2015-03-04 21:12:14 +01:00
|
|
|
|
2016-05-11 18:21:47 +02:00
|
|
|
if (target.last())
|
2015-03-04 21:12:14 +01:00
|
|
|
break;
|
2011-12-22 16:19:25 +01:00
|
|
|
}
|
|
|
|
}
|
2017-02-21 23:07:20 +01:00
|
|
|
} catch (Xml_node::Nonexistent_sub_node) { }
|
2016-11-06 14:26:34 +01:00
|
|
|
|
2017-02-21 23:07:20 +01:00
|
|
|
warning(name(), ": no route to service \"", service_name, "\"");
|
|
|
|
throw Parent::Service_denied();
|
2015-03-04 21:12:14 +01:00
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2016-11-06 14:26:34 +01:00
|
|
|
void filter_session_args(Service::Name const &service,
|
2017-01-03 18:12:53 +01:00
|
|
|
char *args, size_t args_len) override
|
2015-03-04 21:12:14 +01:00
|
|
|
{
|
2016-11-06 14:26:34 +01:00
|
|
|
_priority_policy. filter_session_args(service.string(), args, args_len);
|
|
|
|
_ram_session_policy.filter_session_args(service.string(), args, args_len);
|
2015-03-04 21:12:14 +01:00
|
|
|
}
|
2013-08-14 21:19:11 +02:00
|
|
|
|
2017-01-03 18:12:53 +01:00
|
|
|
Affinity filter_session_affinity(Affinity const &session_affinity) override
|
2015-03-04 21:12:14 +01:00
|
|
|
{
|
|
|
|
Affinity::Space const &child_space = _resources.affinity.space();
|
|
|
|
Affinity::Location const &child_location = _resources.affinity.location();
|
2013-08-14 21:19:11 +02:00
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
/* check if no valid affinity space was specified */
|
|
|
|
if (session_affinity.space().total() == 0)
|
|
|
|
return Affinity(child_space, child_location);
|
2013-08-14 21:19:11 +02:00
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
Affinity::Space const &session_space = session_affinity.space();
|
|
|
|
Affinity::Location const &session_location = session_affinity.location();
|
2013-08-14 21:19:11 +02:00
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
/* scale resolution of resulting space */
|
|
|
|
Affinity::Space space(child_space.multiply(session_space));
|
2013-08-14 21:19:11 +02:00
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
/* subordinate session affinity to child affinity subspace */
|
|
|
|
Affinity::Location location(child_location
|
|
|
|
.multiply_position(session_space)
|
|
|
|
.transpose(session_location.xpos(),
|
|
|
|
session_location.ypos()));
|
2013-08-14 21:19:11 +02:00
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
return Affinity(space, location);
|
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-03 18:12:53 +01:00
|
|
|
void announce_service(Service::Name const &service_name) override
|
2015-03-04 21:12:14 +01:00
|
|
|
{
|
2016-11-06 14:26:34 +01:00
|
|
|
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; });
|
2012-10-24 16:27:26 +02:00
|
|
|
|
2016-11-06 14:26:34 +01:00
|
|
|
if (!found)
|
2017-01-03 18:12:53 +01:00
|
|
|
error(name(), ": illegal announcement of "
|
|
|
|
"service \"", service_name, "\"");
|
2015-03-04 21:12:14 +01:00
|
|
|
}
|
2013-09-26 21:26:50 +02:00
|
|
|
|
2017-01-03 18:12:53 +01:00
|
|
|
void resource_request(Parent::Resource_args const &args) override
|
2015-03-04 21:12:14 +01:00
|
|
|
{
|
2016-11-06 14:26:34 +01:00
|
|
|
log("child \"", name(), "\" requests resources: ", args.string());
|
2013-09-26 21:26:50 +02:00
|
|
|
|
2017-01-03 18:12:53 +01:00
|
|
|
size_t const requested_ram_quota =
|
|
|
|
Arg_string::find_arg(args.string(), "ram_quota")
|
2015-03-04 21:12:14 +01:00
|
|
|
.ulong_value(0);
|
2013-09-26 21:26:50 +02:00
|
|
|
|
2017-01-03 18:12:53 +01:00
|
|
|
if (avail_slack_ram_quota(_env.ram().avail()) < requested_ram_quota) {
|
|
|
|
warning("cannot respond to resource request - out of memory");
|
2015-03-04 21:12:14 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-01-03 18:12:53 +01:00
|
|
|
_env.ram().transfer_quota(_child.ram_session_cap(),
|
|
|
|
requested_ram_quota);
|
2013-09-26 21:26:50 +02:00
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
/* wake up child that was starved for resources */
|
|
|
|
_child.notify_resource_avail();
|
|
|
|
}
|
2013-09-26 21:26:50 +02:00
|
|
|
|
2015-09-15 18:16:31 +02:00
|
|
|
void exit(int exit_value) override
|
|
|
|
{
|
|
|
|
try {
|
2017-02-21 17:01:02 +01:00
|
|
|
if (_start_node->xml().sub_node("exit").attribute_value("propagate", false)) {
|
2017-01-03 18:12:53 +01:00
|
|
|
_env.parent().exit(exit_value);
|
2015-09-15 18:16:31 +02:00
|
|
|
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);
|
|
|
|
}
|
2017-02-16 17:25:59 +01:00
|
|
|
|
|
|
|
void session_state_changed() override
|
|
|
|
{
|
|
|
|
_report_update_trigger.trigger_report_update();
|
|
|
|
}
|
2017-02-21 23:07:20 +01:00
|
|
|
|
|
|
|
bool initiate_env_sessions() const override { return false; }
|
2015-03-04 21:12:14 +01:00
|
|
|
};
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
#endif /* _INCLUDE__INIT__CHILD_H_ */
|