init: API transition

Ref #1987
This commit is contained in:
Norman Feske 2017-01-03 18:12:53 +01:00
parent 9bae4823a0
commit fa1a105d64
4 changed files with 372 additions and 401 deletions

View File

@ -15,16 +15,13 @@
#define _INCLUDE__INIT__CHILD_H_
/* Genode includes */
#include <pd_session/connection.h>
#include <ram_session/connection.h>
#include <cpu_session/connection.h>
#include <cap_session/connection.h>
#include <base/log.h>
#include <base/child.h>
#include <os/session_requester.h>
#include <os/session_policy.h>
/* init includes */
#include <init/verbose.h>
#include <init/child_config.h>
#include <init/child_policy.h>
@ -35,13 +32,10 @@ namespace Init {
class Child_registry;
class Child;
using Genode::log;
using Genode::error;
using Genode::warning;
using Genode::Session_state;
using Genode::Xml_generator;
using Genode::Parent;
using Genode::Id_space;
using namespace Genode;
using Genode::size_t;
using Genode::strlen;
using Genode::strncpy;
typedef Genode::Registered<Genode::Parent_service> Parent_service;
}
@ -53,18 +47,15 @@ namespace Init {
namespace Init {
extern bool config_verbose;
static void warn_insuff_quota(Genode::size_t const avail)
static void warn_insuff_quota(size_t const avail)
{
if (!config_verbose) { return; }
log("Warning: Specified quota exceeds available quota.");
log(" Proceeding with a quota of ", avail, ".");
warning("specified quota exceeds available quota, "
"proceeding with a quota of ", avail);
}
inline long read_priority(Genode::Xml_node start_node, long prio_levels)
inline long read_priority(Xml_node start_node, long prio_levels)
{
long priority = Genode::Cpu_session::DEFAULT_PRIORITY;
long priority = Cpu_session::DEFAULT_PRIORITY;
try { start_node.attribute("priority").value(&priority); }
catch (...) { }
@ -79,10 +70,10 @@ namespace Init {
if (priority && (priority >= prio_levels)) {
long new_prio = prio_levels ? prio_levels-1 : 0;
char name[Genode::Service::Name::capacity()];
char name[Service::Name::capacity()];
start_node.attribute("name").value(name, sizeof(name));
Genode::warning(Genode::Cstring(name), ": invalid priority, upgrading "
"from ", -priority, " to ", -new_prio);
warning(Cstring(name), ": invalid priority, upgrading "
"from ", -priority, " to ", -new_prio);
return new_prio;
}
@ -90,13 +81,13 @@ namespace Init {
}
inline Genode::Affinity::Location
read_affinity_location(Genode::Affinity::Space const &space,
Genode::Xml_node start_node)
inline Affinity::Location
read_affinity_location(Affinity::Space const &space,
Xml_node start_node)
{
typedef Genode::Affinity::Location Location;
typedef Affinity::Location Location;
try {
Genode::Xml_node node = start_node.sub_node("affinity");
Xml_node node = start_node.sub_node("affinity");
/* if no position value is specified, select the whole row/column */
unsigned long const
@ -113,9 +104,9 @@ namespace Init {
y2 = y1 + height - 1;
/* clip location to space boundary */
return Location(Genode::max(x1, 0L), Genode::max(y1, 0L),
Genode::min((unsigned)(x2 - x1 + 1), space.width()),
Genode::min((unsigned)(y2 - y1 + 1), space.height()));
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()); }
}
@ -124,12 +115,11 @@ namespace Init {
/**
* Return amount of RAM that is currently unused
*/
static inline Genode::size_t avail_slack_ram_quota()
static inline size_t avail_slack_ram_quota(size_t ram_avail)
{
Genode::size_t const preserve = 148*1024;
Genode::size_t const avail = Genode::env()->ram_session()->avail();
size_t const preserve = 148*1024;
return avail > preserve ? avail - preserve : 0;
return ram_avail > preserve ? ram_avail - preserve : 0;
}
@ -138,14 +128,14 @@ namespace Init {
*/
inline char const *skip_label_prefix(char const *child_name, char const *label)
{
Genode::size_t const child_name_len = Genode::strlen(child_name);
size_t const child_name_len = strlen(child_name);
/*
* If the method was called with a valid "label" string, the
* following condition should be always satisfied. See the
* comment in 'service_node_args_condition_satisfied'.
*/
if (Genode::strcmp(child_name, label, child_name_len) == 0)
if (strcmp(child_name, label, child_name_len) == 0)
label += child_name_len;
/*
@ -159,10 +149,10 @@ namespace Init {
/*
* Skip label separator. This condition should be always satisfied.
*/
if (Genode::strcmp(" -> ", label, 4) == 0)
if (strcmp(" -> ", label, 4) == 0)
return label + 4;
Genode::warning("cannot skip label prefix while processing <if-arg>");
warning("cannot skip label prefix while processing <if-arg>");
return label;
}
@ -174,9 +164,9 @@ namespace Init {
* \param child_name name of the originator of the session request
* \param service_name name of the requested service
*/
inline bool service_node_matches(Genode::Xml_node service_node, char const *args,
Genode::Child_policy::Name const &child_name,
Genode::Service::Name const &service_name)
inline bool service_node_matches(Xml_node service_node, char const *args,
Child_policy::Name const &child_name,
Service::Name const &service_name)
{
bool const service_matches =
service_node.has_type("any-service") ||
@ -186,22 +176,22 @@ namespace Init {
if (!service_matches)
return false;
Genode::Session_label const session_label(skip_label_prefix(
child_name.string(), Genode::label_from_args(args).string()));
Session_label const session_label(skip_label_prefix(
child_name.string(), label_from_args(args).string()));
return !Genode::Xml_node_label_score(service_node, session_label).conflict();
return !Xml_node_label_score(service_node, session_label).conflict();
}
/**
* Check if arguments satisfy the condition specified for the route
*/
inline bool service_node_args_condition_satisfied(Genode::Xml_node service_node,
Genode::Session_state::Args const &args,
Genode::Child_policy::Name const &child_name)
inline bool service_node_args_condition_satisfied(Xml_node service_node,
Session_state::Args const &args,
Child_policy::Name const &child_name)
{
try {
Genode::Xml_node if_arg = service_node.sub_node("if-arg");
Xml_node if_arg = service_node.sub_node("if-arg");
enum { KEY_MAX_LEN = 64, VALUE_MAX_LEN = 64 };
char key[KEY_MAX_LEN];
char value[VALUE_MAX_LEN];
@ -209,7 +199,7 @@ namespace Init {
if_arg.attribute("value").value(value, sizeof(value));
char arg_value[VALUE_MAX_LEN];
Genode::Arg_string::find_arg(args.string(), key).string(arg_value, sizeof(arg_value), "");
Arg_string::find_arg(args.string(), key).string(arg_value, sizeof(arg_value), "");
/*
* Skip child-name prefix if the key is the process "label".
@ -222,10 +212,10 @@ namespace Init {
* session route is specific to the named start node anyway. So
* the prefix information is redundant.
*/
if (Genode::strcmp("label", key) == 0)
return Genode::strcmp(value, skip_label_prefix(child_name.string(), arg_value)) == 0;
if (strcmp("label", key) == 0)
return strcmp(value, skip_label_prefix(child_name.string(), arg_value)) == 0;
return Genode::strcmp(value, arg_value) == 0;
return strcmp(value, arg_value) == 0;
} catch (...) { }
/* if no if-arg node exists, the condition is met */
@ -242,7 +232,7 @@ namespace Init {
* \deprecated
*/
template <typename T>
inline bool is_ambiguous(Genode::Registry<T> const &services,
inline bool is_ambiguous(Registry<T> const &services,
Service::Name const &name)
{
/* count number of services with the specified name */
@ -255,8 +245,8 @@ namespace Init {
template <typename T>
inline Genode::Service *find_service(Genode::Registry<T> &services,
Genode::Service::Name const &name)
inline Service *find_service(Registry<T> &services,
Service::Name const &name)
{
T *service = nullptr;
services.for_each([&] (T &s) {
@ -270,17 +260,17 @@ namespace Init {
/**
* Init-specific representation of a child service
*/
class Init::Routed_service : public Genode::Child_service
class Init::Routed_service : public Child_service
{
public:
typedef Genode::Child_policy::Name Child_name;
typedef Child_policy::Name Child_name;
private:
Child_name _child_name;
Genode::Registry<Routed_service>::Element _registry_element;
Registry<Routed_service>::Element _registry_element;
public:
@ -292,12 +282,12 @@ class Init::Routed_service : public Genode::Child_service
*
* The other arguments correspond to the arguments of 'Child_service'.
*/
Routed_service(Genode::Registry<Routed_service> &services,
Routed_service(Registry<Routed_service> &services,
Child_name const &child_name,
Id_space<Parent::Server> &server_id_space,
Session_state::Factory &factory,
Service::Name const &name,
Genode::Ram_session_capability ram,
Ram_session_capability ram,
Child_service::Wakeup &wakeup)
:
Child_service(server_id_space, factory, name, ram, wakeup),
@ -315,7 +305,7 @@ struct Init::Name_registry
{
virtual ~Name_registry() { }
typedef Genode::Child_policy::Name Name;
typedef Child_policy::Name Name;
/**
* Check if specified name is unique
@ -333,8 +323,7 @@ struct Init::Name_registry
};
class Init::Child : Genode::Child_policy,
Genode::Child_service::Wakeup
class Init::Child : Child_policy, Child_service::Wakeup
{
public:
@ -347,13 +336,15 @@ class Init::Child : Genode::Child_policy,
friend class Child_registry;
Genode::Env &_env;
Env &_env;
Genode::List_element<Child> _list_element;
Verbose const &_verbose;
Genode::Xml_node _start_node;
List_element<Child> _list_element;
Genode::Xml_node _default_route_node;
Xml_node _start_node;
Xml_node _default_route_node;
Name_registry &_name_registry;
@ -374,26 +365,25 @@ class Init::Child : Genode::Child_policy,
* \param start_node XML start node
* \param registry registry tracking unique names
*/
Name(Genode::Xml_node start_node, Name_registry const &registry) {
Name(Xml_node start_node, Name_registry const &registry) {
try {
start_node.attribute("name").value(unique, sizeof(unique)); }
catch (Genode::Xml_node::Nonexistent_attribute) {
Genode::warning("missing 'name' attribute in '<start>' entry");
catch (Xml_node::Nonexistent_attribute) {
warning("missing 'name' attribute in '<start>' entry");
throw; }
/* check for a name confict with the other children */
if (!registry.unique(unique)) {
Genode::error("child name \"", Genode::Cstring(unique), "\" "
"is not unique");
error("child name \"", Cstring(unique), "\" is not unique");
throw Child_name_is_not_unique();
}
/* use name as default file name if not declared otherwise */
Genode::strncpy(file, unique, sizeof(file));
strncpy(file, unique, sizeof(file));
/* check for a binary declaration */
try {
Genode::Xml_node binary = start_node.sub_node("binary");
Xml_node binary = start_node.sub_node("binary");
binary.attribute("name").value(file, sizeof(file));
} catch (...) { }
}
@ -401,18 +391,20 @@ class Init::Child : Genode::Child_policy,
struct Read_quota
{
Read_quota(Genode::Xml_node start_node,
Genode::size_t & ram_quota,
Genode::size_t & cpu_quota_pc,
bool & constrain_phys)
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)
{
cpu_quota_pc = 0;
constrain_phys = false;
Genode::Number_of_bytes ram_bytes = 0;
Number_of_bytes ram_bytes = 0;
try {
Genode::Xml_node rsc = start_node.sub_node("resource");
Xml_node rsc = start_node.sub_node("resource");
for (;; rsc = rsc.next("resource")) {
try {
if (rsc.attribute("name").has_value("RAM")) {
@ -431,10 +423,11 @@ class Init::Child : Genode::Child_policy,
* our allocation of the child meta data from the heap.
* Hence, we preserve some of our own quota.
*/
Genode::size_t const ram_avail = avail_slack_ram_quota();
if (ram_quota > ram_avail) {
ram_quota = ram_avail;
warn_insuff_quota(ram_avail);
if (verbose.enabled())
warn_insuff_quota(ram_avail);
}
}
};
@ -444,19 +437,22 @@ class Init::Child : Genode::Child_policy,
*/
struct Resources : Read_quota
{
long prio_levels_log2;
long priority;
Genode::Affinity affinity;
Genode::size_t ram_quota;
Genode::size_t cpu_quota_pc;
bool constrain_phys;
long prio_levels_log2;
long priority;
Affinity affinity;
size_t ram_quota;
size_t cpu_quota_pc;
bool constrain_phys;
Resources(Genode::Xml_node start_node, const char *label,
Resources(Xml_node start_node, const char *label,
long prio_levels,
Genode::Affinity::Space const &affinity_space)
Affinity::Space const &affinity_space,
size_t ram_avail,
Verbose const &verbose)
:
Read_quota(start_node, ram_quota, cpu_quota_pc, constrain_phys),
prio_levels_log2(Genode::log2(prio_levels)),
Read_quota(start_node, ram_quota, cpu_quota_pc,
constrain_phys, ram_avail, verbose),
prio_levels_log2(log2(prio_levels)),
priority(read_priority(start_node, prio_levels)),
affinity(affinity_space,
read_affinity_location(affinity_space, start_node))
@ -466,29 +462,21 @@ class Init::Child : Genode::Child_policy,
}
} _resources;
/*
* Entry point used for serving the parent interface and the
* locally provided ROM sessions for the 'config' and 'binary'
* files.
*/
enum { ENTRYPOINT_STACK_SIZE = 12*1024 };
Genode::Rpc_entrypoint _entrypoint;
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() };
Genode::Parent_service _env_ram_service { _env, Genode::Ram_session::service_name() };
Genode::Parent_service _env_cpu_service { _env, Genode::Cpu_session::service_name() };
Genode::Parent_service _env_pd_service { _env, Genode:: Pd_session::service_name() };
Genode::Parent_service _env_log_service { _env, Genode::Log_session::service_name() };
Genode::Parent_service _env_rom_service { _env, Genode::Rom_session::service_name() };
Genode::Registry<Parent_service> &_parent_services;
Genode::Registry<Routed_service> &_child_services;
Registry<Parent_service> &_parent_services;
Registry<Routed_service> &_child_services;
/**
* Private child configuration
*/
Init::Child_config _config;
Genode::Session_requester _session_requester;
Session_requester _session_requester;
/**
* Policy helpers
@ -498,7 +486,7 @@ class Init::Child : Genode::Child_policy,
Init::Child_policy_redirect_rom_file _configfile_policy;
Init::Child_policy_ram_phys _ram_session_policy;
Genode::Child _child { _env.rm(), _entrypoint, *this };
Genode::Child _child { _env.rm(), _env.ep().rpc_ep(), *this };
/**
* Child_service::Wakeup callback
@ -518,42 +506,40 @@ class Init::Child : Genode::Child_policy,
* config dataspace to local address
* space
*/
Child(Genode::Env &env,
Genode::Xml_node start_node,
Genode::Xml_node default_route_node,
Name_registry &name_registry,
long prio_levels,
Genode::Affinity::Space const &affinity_space,
Genode::Registry<Parent_service> &parent_services,
Genode::Registry<Routed_service> &child_services)
Child(Env &env,
Verbose const &verbose,
Xml_node start_node,
Xml_node default_route_node,
Name_registry &name_registry,
long prio_levels,
Affinity::Space const &affinity_space,
Registry<Parent_service> &parent_services,
Registry<Routed_service> &child_services)
:
_env(env),
_env(env), _verbose(verbose),
_list_element(this),
_start_node(start_node),
_default_route_node(default_route_node),
_name_registry(name_registry),
_name(start_node, name_registry),
_resources(start_node, _name.unique, prio_levels,
affinity_space),
_entrypoint(&_env.pd(), ENTRYPOINT_STACK_SIZE, _name.unique, false,
_resources.affinity.location()),
affinity_space, avail_slack_ram_quota(_env.ram().avail()),
_verbose),
_parent_services(parent_services),
_child_services(child_services),
_config(_env.ram(), _env.rm(), start_node),
_session_requester(_entrypoint, _env.ram(), _env.rm()),
_session_requester(_env.ep().rpc_ep(), _env.ram(), _env.rm()),
_priority_policy(_resources.prio_levels_log2, _resources.priority),
_config_policy("config", _config.dataspace(), &_entrypoint),
_config_policy("config", _config.dataspace(), &_env.ep().rpc_ep()),
_configfile_policy("config", _config.filename()),
_ram_session_policy(_resources.constrain_phys)
{
using namespace Genode;
if (_resources.ram_quota == 0)
Genode::warning("no valid RAM resource for child "
"\"", Genode::Cstring(_name.unique), "\"");
warning("no valid RAM resource for child "
"\"", Cstring(_name.unique), "\"");
if (config_verbose) {
log("child \"", Genode::Cstring(_name.unique), "\"");
if (_verbose.enabled()) {
log("child \"", Cstring(_name.unique), "\"");
log(" RAM quota: ", _resources.ram_quota);
log(" ELF binary: ", Cstring(_name.file));
log(" priority: ", _resources.priority);
@ -567,11 +553,11 @@ class Init::Child : Genode::Child_policy,
for (; ; service_node = service_node.next("service")) {
char name[Genode::Service::Name::capacity()];
char name[Service::Name::capacity()];
service_node.attribute("name").value(name, sizeof(name));
if (config_verbose)
log(" provides service ", Genode::Cstring(name));
if (_verbose.enabled())
log(" provides service ", Cstring(name));
new (_child.heap())
Routed_service(child_services, this->name(),
@ -595,11 +581,6 @@ class Init::Child : Genode::Child_policy,
*/
bool has_name(Child_policy::Name const &str) const { return str == name(); }
/**
* Start execution of child
*/
void start() { _entrypoint.activate(); }
/****************************
** Child-policy interface **
@ -609,20 +590,17 @@ class Init::Child : Genode::Child_policy,
Binary_name binary_name() const override { return _name.file; }
Genode::Ram_session &ref_ram() override { return _env.ram(); }
Genode::Ram_session_capability ref_ram_cap() const override { return _env.ram_session_cap(); }
Ram_session &ref_ram() override { return _env.ram(); }
Ram_session_capability ref_ram_cap() const override { return _env.ram_session_cap(); }
void init(Genode::Ram_session &session, Genode::Ram_session_capability cap) override
void init(Ram_session &session, Ram_session_capability cap) override
{
session.ref_account(Genode::env()->ram_session_cap());
Genode::env()->ram_session()->transfer_quota(cap, _resources.ram_quota);
session.ref_account(_env.ram_session_cap());
_env.ram().transfer_quota(cap, _resources.ram_quota);
}
void init(Genode::Cpu_session &session, Genode::Cpu_session_capability cap) override
void init(Cpu_session &session, Cpu_session_capability cap) override
{
using Genode::Cpu_session;
using Genode::size_t;
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;
@ -638,44 +616,44 @@ class Init::Child : Genode::Child_policy,
_env.cpu().transfer_quota(cap, need_adj);
}
Genode::Id_space<Genode::Parent::Server> &server_id_space() override {
Id_space<Parent::Server> &server_id_space() override {
return _session_requester.id_space(); }
Genode::Service &resolve_session_request(Genode::Service::Name const &service_name,
Genode::Session_state::Args const &args) override
Service &resolve_session_request(Service::Name const &service_name,
Session_state::Args const &args) override
{
/* route environment session requests to the parent */
Genode::Session_label const label(Genode::label_from_args(args.string()));
Session_label const label(label_from_args(args.string()));
if (label == name()) {
if (service_name == Genode::Ram_session::service_name()) return _env_ram_service;
if (service_name == Genode::Cpu_session::service_name()) return _env_cpu_service;
if (service_name == Genode::Pd_session::service_name()) return _env_pd_service;
if (service_name == Genode::Log_session::service_name()) return _env_log_service;
if (service_name == Ram_session::service_name()) return _env_ram_service;
if (service_name == Cpu_session::service_name()) return _env_cpu_service;
if (service_name == Pd_session::service_name()) return _env_pd_service;
if (service_name == Log_session::service_name()) return _env_log_service;
}
/* route initial ROM requests (binary and linker) to the parent */
if (service_name == Genode::Rom_session::service_name()) {
if (service_name == Rom_session::service_name()) {
if (label.last_element() == binary_name()) return _env_rom_service;
if (label.last_element() == linker_name()) return _env_rom_service;
}
Genode::Service *service = nullptr;
Service *service = nullptr;
/* check for "config" ROM request */
if ((service = _config_policy.resolve_session_request(service_name.string(), args.string())))
return *service;
/* check for "session_requests" ROM request */
if (service_name == Genode::Rom_session::service_name()
&& label.last_element() == Genode::Session_requester::rom_name())
if (service_name == Rom_session::service_name()
&& label.last_element() == Session_requester::rom_name())
return _session_requester.service();
try {
Genode::Xml_node route_node = _default_route_node;
Xml_node route_node = _default_route_node;
try {
route_node = _start_node.sub_node("route"); }
catch (...) { }
Genode::Xml_node service_node = route_node.sub_node();
Xml_node service_node = route_node.sub_node();
for (; ; service_node = service_node.next()) {
@ -687,7 +665,7 @@ class Init::Child : Genode::Child_policy,
if (!service_node_args_condition_satisfied(service_node, args, name()))
continue;
Genode::Xml_node target = service_node.sub_node();
Xml_node target = service_node.sub_node();
for (; ; target = target.next()) {
if (target.has_type("parent")) {
@ -698,7 +676,7 @@ class Init::Child : Genode::Child_policy,
if (!service_wildcard) {
warning(name(), ": service lookup for "
"\"", service_name, "\" at parent failed");
throw Genode::Parent::Service_denied();
throw Parent::Service_denied();
}
}
@ -716,9 +694,9 @@ class Init::Child : Genode::Child_policy,
return *service;
if (!service_wildcard) {
Genode::warning(name(), ": lookup to child "
"server \"", server_name, "\" failed");
throw Genode::Parent::Service_denied();
warning(name(), ": lookup to child "
"server \"", server_name, "\" failed");
throw Parent::Service_denied();
}
}
@ -726,7 +704,7 @@ class Init::Child : Genode::Child_policy,
if (is_ambiguous(_child_services, service_name)) {
error(name(), ": ambiguous routes to "
"service \"", service_name, "\"");
throw Genode::Parent::Service_denied();
throw Parent::Service_denied();
}
if ((service = find_service(_child_services, service_name)))
@ -735,7 +713,7 @@ class Init::Child : Genode::Child_policy,
if (!service_wildcard) {
warning(name(), ": lookup for service "
"\"", service_name, "\" failed");
throw Genode::Parent::Service_denied();
throw Parent::Service_denied();
}
}
@ -748,23 +726,21 @@ class Init::Child : Genode::Child_policy,
}
if (!service)
throw Genode::Parent::Service_denied();
throw Parent::Service_denied();
return *service;
}
void filter_session_args(Service::Name const &service,
char *args, Genode::size_t args_len) override
char *args, size_t args_len) override
{
_priority_policy. filter_session_args(service.string(), args, args_len);
_configfile_policy. filter_session_args(service.string(), args, args_len);
_ram_session_policy.filter_session_args(service.string(), args, args_len);
}
Genode::Affinity filter_session_affinity(Genode::Affinity const &session_affinity) override
Affinity filter_session_affinity(Affinity const &session_affinity) override
{
using namespace Genode;
Affinity::Space const &child_space = _resources.affinity.space();
Affinity::Location const &child_location = _resources.affinity.location();
@ -787,7 +763,7 @@ class Init::Child : Genode::Child_policy,
return Affinity(space, location);
}
void announce_service(Genode::Service::Name const &service_name) override
void announce_service(Service::Name const &service_name) override
{
log("child \"", name(), "\" announces service \"", service_name, "\"");
@ -798,33 +774,25 @@ class Init::Child : Genode::Child_policy,
found = true; });
if (!found)
Genode::error(name(), ": illegal announcement of "
"service \"", service_name, "\"");
error(name(), ": illegal announcement of "
"service \"", service_name, "\"");
}
void resource_request(Genode::Parent::Resource_args const &args) override
void resource_request(Parent::Resource_args const &args) override
{
log("child \"", name(), "\" requests resources: ", args.string());
Genode::size_t const requested_ram_quota =
Genode::Arg_string::find_arg(args.string(), "ram_quota")
size_t const requested_ram_quota =
Arg_string::find_arg(args.string(), "ram_quota")
.ulong_value(0);
if (avail_slack_ram_quota() < requested_ram_quota) {
Genode::warning("cannot respond to resource request - out of memory");
if (avail_slack_ram_quota(_env.ram().avail()) < requested_ram_quota) {
warning("cannot respond to resource request - out of memory");
return;
}
/*
* XXX Synchronize quota transfers from/to env()->ram_session()
*
* If multiple children issue concurrent resource requests, the
* value reported by 'avail_slack_ram_quota' may be out of date
* when calling 'transfer_quota'.
*/
Genode::env()->ram_session()->transfer_quota(_child.ram_session_cap(),
requested_ram_quota);
_env.ram().transfer_quota(_child.ram_session_cap(),
requested_ram_quota);
/* wake up child that was starved for resources */
_child.notify_resource_avail();
@ -834,7 +802,7 @@ class Init::Child : Genode::Child_policy,
{
try {
if (_start_node.sub_node("exit").attribute_value("propagate", false)) {
Genode::env()->parent()->exit(exit_value);
_env.parent().exit(exit_value);
return;
}
} catch (...) { }
@ -848,5 +816,4 @@ class Init::Child : Genode::Child_policy,
}
};
#endif /* _INCLUDE__INIT__CHILD_H_ */

View File

@ -17,7 +17,6 @@
/* Genode includes */
#include <base/service.h>
#include <base/child.h>
#include <base/rpc_server.h>
#include <base/session_label.h>
#include <base/attached_ram_dataspace.h>
#include <util/arg_string.h>
@ -34,13 +33,10 @@ namespace Init {
class Child_policy_redirect_rom_file;
class Traditional_child_policy;
using Genode::Attached_ram_dataspace;
using namespace Genode;
using Genode::size_t;
using Genode::Session_label;
using Genode::error;
using Genode::log;
using Genode::Service;
using Genode::Session_state;
using Genode::strcmp;
using Genode::snprintf;
}
@ -63,12 +59,10 @@ class Init::Child_policy_ram_phys
* permits this.
*/
void filter_session_args(const char *service, char *args,
Genode::size_t args_len)
size_t args_len)
{
using namespace Genode;
/* intercept only RAM session requests */
if (Genode::strcmp(service, "RAM"))
if (strcmp(service, "RAM"))
return;
if (_constrain_phys)
@ -91,12 +85,10 @@ class Init::Child_policy_handle_cpu_priorities
Child_policy_handle_cpu_priorities(long prio_levels_log2, long priority)
: _prio_levels_log2(prio_levels_log2), _priority(priority) { }
void filter_session_args(const char *service, char *args, Genode::size_t args_len)
void filter_session_args(const char *service, char *args, size_t args_len)
{
using namespace Genode;
/* intercept only CPU session requests to scale priorities */
if (Genode::strcmp(service, "CPU") || _prio_levels_log2 == 0)
if (strcmp(service, "CPU") || _prio_levels_log2 == 0)
return;
unsigned long priority = Arg_string::find_arg(args, "priority").ulong_value(0);
@ -115,7 +107,7 @@ class Init::Child_policy_handle_cpu_priorities
/* override priority when delegating the session request to the parent */
char value_buf[64];
Genode::snprintf(value_buf, sizeof(value_buf), "0x%lx", priority);
snprintf(value_buf, sizeof(value_buf), "0x%lx", priority);
Arg_string::set_arg(args, args_len, "priority", value_buf);
}
};
@ -125,16 +117,16 @@ class Init::Child_policy_provide_rom_file
{
private:
struct Local_rom_session_component : Genode::Rpc_object<Genode::Rom_session>
struct Local_rom_session_component : Rpc_object<Rom_session>
{
Genode::Rpc_entrypoint &ep;
Genode::Dataspace_capability ds_cap;
Rpc_entrypoint &ep;
Dataspace_capability ds_cap;
/**
* Constructor
*/
Local_rom_session_component(Genode::Rpc_entrypoint &ep,
Genode::Dataspace_capability ds)
Local_rom_session_component(Rpc_entrypoint &ep,
Dataspace_capability ds)
: ep(ep), ds_cap(ds) { ep.manage(this); }
~Local_rom_session_component() { ep.dissolve(this); }
@ -144,16 +136,16 @@ class Init::Child_policy_provide_rom_file
** ROM session interface **
***************************/
Genode::Rom_dataspace_capability dataspace() override {
return Genode::static_cap_cast<Genode::Rom_dataspace>(ds_cap); }
Rom_dataspace_capability dataspace() override {
return static_cap_cast<Rom_dataspace>(ds_cap); }
void sigh(Genode::Signal_context_capability) override { }
void sigh(Signal_context_capability) override { }
} _session;
Genode::Session_label const _module_name;
Session_label const _module_name;
typedef Genode::Local_service<Local_rom_session_component> Service;
typedef Local_service<Local_rom_session_component> Service;
Service::Single_session_factory _session_factory { _session };
Service _service { _session_factory };
@ -163,22 +155,22 @@ class Init::Child_policy_provide_rom_file
/**
* Constructor
*/
Child_policy_provide_rom_file(Genode::Session_label const &module_name,
Genode::Dataspace_capability ds_cap,
Genode::Rpc_entrypoint *ep)
Child_policy_provide_rom_file(Session_label const &module_name,
Dataspace_capability ds_cap,
Rpc_entrypoint *ep)
:
_session(*ep, ds_cap), _module_name(module_name)
{ }
Genode::Service *resolve_session_request(const char *service_name,
Service *resolve_session_request(const char *service_name,
const char *args)
{
/* ignore session requests for non-ROM services */
if (Genode::strcmp(service_name, "ROM")) return 0;
if (strcmp(service_name, "ROM")) return 0;
/* drop out if request refers to another file name */
{
Genode::Session_label const label = Genode::label_from_args(args);
Session_label const label = label_from_args(args);
return label.last_element() == _module_name
? &_service : nullptr;
}
@ -199,14 +191,12 @@ class Init::Child_policy_redirect_rom_file
: _from(from), _to(to) { }
void filter_session_args(const char *service,
char *args, Genode::size_t args_len)
char *args, size_t args_len)
{
using namespace Genode;
if (!_from || !_to) return;
/* ignore session requests for non-ROM services */
if (Genode::strcmp(service, "ROM")) return;
if (strcmp(service, "ROM")) return;
/* drop out if request refers to another module name */
Session_label const label = label_from_args(args);

View File

@ -0,0 +1,37 @@
/*
* \brief Init verbosity
* \author Norman Feske
* \date 2017-01-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 General Public License version 2.
*/
#ifndef _INCLUDE__INIT__VERBOSE_H_
#define _INCLUDE__INIT__VERBOSE_H_
#include <util/noncopyable.h>
#include <util/xml_node.h>
namespace Init { struct Verbose; }
class Init::Verbose : Genode::Noncopyable
{
private:
bool _enabled;
public:
Verbose(Genode::Xml_node config)
: _enabled(config.attribute_value("verbose", false)) { }
bool enabled() const { return _enabled; }
};
#endif /* _INCLUDE__INIT__VERBOSE_H_ */

View File

@ -12,78 +12,65 @@
*/
#include <base/component.h>
#include <base/attached_rom_dataspace.h>
#include <init/child.h>
#include <base/sleep.h>
#include <os/config.h>
namespace Init {
namespace Init { bool config_verbose = false; }
/***************
** Utilities **
***************/
/**
* Read priority-levels declaration from config
*/
inline long read_prio_levels()
{
using namespace Genode;
long prio_levels = 0;
try {
config()->xml_node().attribute("prio_levels").value(&prio_levels); }
catch (...) { }
/**
* 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;
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;
}
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()
{
using namespace Genode;
try {
Xml_node node = config()->xml_node().sub_node("affinity-space");
return Affinity::Space(node.attribute_value<unsigned long>("width", 1),
node.attribute_value<unsigned long>("height", 1));
} catch (...) {
return Affinity::Space(1, 1); }
}
/**
* 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<unsigned long>("width", 1),
node.attribute_value<unsigned long>("height", 1));
} catch (...) {
return Affinity::Space(1, 1); }
}
/**
* Read parent-provided services from config
*/
inline void determine_parent_services(Genode::Registry<Init::Parent_service> *services)
{
using namespace Genode;
/**
* Read parent-provided services from config
*/
inline void determine_parent_services(Registry<Init::Parent_service> &services,
Xml_node config, Allocator &alloc,
bool verbose)
{
if (verbose)
log("parent provides");
if (Init::config_verbose)
log("parent provides");
config.sub_node("parent-provides")
.for_each_sub_node("service", [&] (Xml_node node) {
Xml_node node = config()->xml_node().sub_node("parent-provides").sub_node("service");
for (; ; node = node.next("service")) {
Service::Name name = node.attribute_value("name", Service::Name());
char service_name[Genode::Service::Name::capacity()];
node.attribute("name").value(service_name, sizeof(service_name));
new (env()->heap()) Init::Parent_service(*services, service_name);
if (Init::config_verbose)
log(" service \"", Cstring(service_name), "\"");
if (node.last("service")) break;
new (alloc) Init::Parent_service(services, name);
if (verbose)
log(" service \"", name, "\"");
});
}
}
@ -205,16 +192,6 @@ class Init::Child_registry : public Name_registry, Child_list
_aliases.remove(alias);
}
/**
* Start execution of all children
*/
void start()
{
Genode::List_element<Child> *curr = first();
for (; curr; curr = curr->next())
curr->object()->start();
}
/**
* Return any of the registered children, or 0 if no child exists
*/
@ -264,124 +241,124 @@ class Init::Child_registry : public Name_registry, Child_list
};
void Component::construct(Genode::Env &env)
namespace Init { struct Main; }
struct Init::Main
{
using namespace Init;
using namespace Genode;
Env &_env;
static Registry<Init::Parent_service> parent_services;
static Registry<Routed_service> child_services;
static Child_registry children;
static Cap_connection cap;
Registry<Init::Parent_service> _parent_services;
Registry<Routed_service> _child_services;
Child_registry _children;
/*
* Signal receiver for config changes
*/
Signal_receiver sig_rec;
Signal_context sig_ctx_config;
Signal_context sig_ctx_res_avail;
config()->sigh(sig_rec.manage(&sig_ctx_config));
/* prevent init to block for resource upgrades (never satisfied by core) */
Genode::env()->parent()->resource_avail_sigh(sig_rec.manage(&sig_ctx_res_avail));
Heap _heap { _env.ram(), _env.rm() };
for (;;) {
Attached_rom_dataspace _config { _env, "config" };
config_verbose =
config()->xml_node().attribute_value("verbose", false);
Reconstructible<Verbose> _verbose { _config.xml() };
try { determine_parent_services(&parent_services); }
catch (...) { }
void _handle_resource_avail() { }
Signal_handler<Main> _resource_avail_handler {
_env.ep(), *this, &Main::_handle_resource_avail };
void _handle_config();
Signal_handler<Main> _config_handler {
_env.ep(), *this, &Main::_handle_config };
Main(Env &env) : _env(env)
{
_config.sigh(_config_handler);
/* prevent init to block for resource upgrades (never satisfied by core) */
_env.parent().resource_avail_sigh(_resource_avail_handler);
_handle_config();
}
};
void Init::Main::_handle_config()
{
/* kill all currently running children */
while (_children.any()) {
Init::Child *child = _children.any();
_children.remove(child);
destroy(_heap, child);
}
/* remove all known aliases */
while (_children.any_alias()) {
Init::Alias *alias = _children.any_alias();
_children.remove_alias(alias);
destroy(_heap, alias);
}
/* reset knowledge about parent services */
_parent_services.for_each([&] (Init::Parent_service &service) {
destroy(_heap, &service); });
/* reload config */
try { config()->reload(); } catch (...) { }
_config.update();
_verbose.construct(_config.xml());
try { determine_parent_services(_parent_services, _config.xml(),
_heap, _verbose->enabled()); }
catch (...) { }
/* determine default route for resolving service requests */
Xml_node default_route_node("<empty/>");
try {
default_route_node =
_config.xml().sub_node("default-route"); }
catch (...) { }
/* create aliases */
_config.xml().for_each_sub_node("alias", [&] (Xml_node alias_node) {
/* determine default route for resolving service requests */
Xml_node default_route_node("<empty/>");
try {
default_route_node =
config()->xml_node().sub_node("default-route"); }
catch (...) { }
_children.insert_alias(new (_heap) Alias(alias_node)); }
catch (Alias::Name_is_missing) {
warning("missing 'name' attribute in '<alias>' entry"); }
catch (Alias::Child_is_missing) {
warning("missing 'child' attribute in '<alias>' entry"); }
});
/* create aliases */
config()->xml_node().for_each_sub_node("alias", [&] (Xml_node alias_node) {
/* create children */
try {
_config.xml().for_each_sub_node("start", [&] (Xml_node start_node) {
try {
children.insert_alias(new (Genode::env()->heap()) Alias(alias_node));
_children.insert(new (_heap)
Init::Child(_env, *_verbose, start_node, default_route_node,
_children, read_prio_levels(_config.xml()),
read_affinity_space(_config.xml()),
_parent_services, _child_services));
}
catch (Alias::Name_is_missing) {
warning("missing 'name' attribute in '<alias>' entry"); }
catch (Alias::Child_is_missing) {
warning("missing 'child' attribute in '<alias>' entry"); }
catch (Rom_connection::Rom_connection_failed) {
/*
* The binary does not exist. An error message is printed
* by the Rom_connection constructor.
*/
}
catch (Ram_session::Alloc_failed) {
warning("failed to allocate memory during child construction"); }
catch (Region_map::Attach_failed) {
warning("failed to attach dataspace to local address space "
"during child construction"); }
});
/* create children */
try {
config()->xml_node().for_each_sub_node("start", [&] (Xml_node start_node) {
try {
children.insert(new (Genode::env()->heap())
Init::Child(env, start_node, default_route_node,
children, read_prio_levels(),
read_affinity_space(),
parent_services, child_services));
}
catch (Rom_connection::Rom_connection_failed) {
/*
* The binary does not exist. An error message is printed
* by the Rom_connection constructor.
*/
}
catch (Ram_session::Alloc_failed) {
warning("failed to allocate memory during child construction"); }
catch (Region_map::Attach_failed) {
warning("failed to attach dataspace to local address space "
"during child construction"); }
});
/* start children */
children.start();
}
catch (Xml_node::Nonexistent_sub_node) {
error("no children to start"); }
catch (Xml_node::Invalid_syntax) {
error("no children to start"); }
catch (Init::Child::Child_name_is_not_unique) { }
catch (Init::Child_registry::Alias_name_is_not_unique) { }
/*
* Respond to config changes at runtime
*
* If the config gets updated to a new version, we kill the current
* scenario and start again with the new config.
*/
/* wait for config change */
while (true) {
Signal signal = sig_rec.wait_for_signal();
if (signal.context() == &sig_ctx_config)
break;
warning("unexpected signal received - drop it");
}
/* kill all currently running children */
while (children.any()) {
Init::Child *child = children.any();
children.remove(child);
destroy(Genode::env()->heap(), child);
}
/* remove all known aliases */
while (children.any_alias()) {
Init::Alias *alias = children.any_alias();
children.remove_alias(alias);
destroy(Genode::env()->heap(), alias);
}
/* reset knowledge about parent services */
parent_services.for_each([&] (Init::Parent_service &service) {
destroy(Genode::env()->heap(), &service); });
/* reload config */
try { config()->reload(); } catch (...) { }
}
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) { }
}
void Component::construct(Genode::Env &env) { static Init::Main main(env); }