2011-12-22 15:19:25 +00:00
|
|
|
/*
|
|
|
|
* \brief Representation used for children of the init process
|
|
|
|
* \author Norman Feske
|
|
|
|
* \date 2010-05-04
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2012-01-03 14:35:05 +00:00
|
|
|
* Copyright (C) 2010-2012 Genode Labs GmbH
|
2011-12-22 15:19:25 +00: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 */
|
|
|
|
#include <ram_session/connection.h>
|
|
|
|
#include <cpu_session/connection.h>
|
|
|
|
#include <cap_session/connection.h>
|
|
|
|
#include <base/printf.h>
|
|
|
|
#include <base/child.h>
|
|
|
|
|
|
|
|
/* init includes */
|
|
|
|
#include <init/child_config.h>
|
|
|
|
#include <init/child_policy.h>
|
|
|
|
|
|
|
|
namespace Init {
|
|
|
|
|
|
|
|
extern bool config_verbose;
|
|
|
|
|
|
|
|
|
|
|
|
/***************
|
|
|
|
** Utilities **
|
|
|
|
***************/
|
|
|
|
|
|
|
|
inline long read_priority(Genode::Xml_node start_node)
|
|
|
|
{
|
|
|
|
long priority = Genode::Cpu_session::DEFAULT_PRIORITY;
|
|
|
|
try { start_node.attribute("priority").value(&priority); }
|
|
|
|
catch (...) { }
|
|
|
|
|
|
|
|
/*
|
|
|
|
* All priority declarations in the config file are
|
|
|
|
* negative because child priorities can never be higher
|
|
|
|
* than parent priorities. To simplify priority
|
|
|
|
* calculations, we use inverted values. Lower values
|
|
|
|
* correspond to higher priorities.
|
|
|
|
*/
|
|
|
|
return -priority;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
inline Genode::size_t read_ram_quota(Genode::Xml_node start_node)
|
|
|
|
{
|
|
|
|
Genode::Number_of_bytes ram_quota = 0;
|
|
|
|
try {
|
|
|
|
Genode::Xml_node rsc = start_node.sub_node("resource");
|
|
|
|
for (;; rsc = rsc.next("resource")) {
|
|
|
|
|
|
|
|
try {
|
|
|
|
if (rsc.attribute("name").has_value("RAM")) {
|
|
|
|
rsc.attribute("quantum").value(&ram_quota);
|
|
|
|
}
|
|
|
|
} catch (...) { }
|
|
|
|
}
|
|
|
|
} catch (...) { }
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the configured quota exceeds our own quota, we donate
|
|
|
|
* all remaining quota to the child but we need to count in
|
|
|
|
* our allocation of the child meta data from the heap.
|
|
|
|
* Hence, we preserve some of our own quota.
|
|
|
|
*/
|
|
|
|
if (ram_quota > Genode::env()->ram_session()->avail() - 128*1024) {
|
|
|
|
ram_quota = Genode::env()->ram_session()->avail() - 128*1024;
|
|
|
|
if (config_verbose)
|
|
|
|
Genode::printf("Warning: Specified quota exceeds available quota.\n"
|
|
|
|
" Proceeding with a quota of %zd bytes.\n",
|
|
|
|
(Genode::size_t)ram_quota);
|
|
|
|
}
|
|
|
|
return ram_quota;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return true if service XML node matches the specified service name
|
|
|
|
*/
|
|
|
|
inline bool service_node_matches(Genode::Xml_node service_node, const char *service_name)
|
|
|
|
{
|
|
|
|
if (service_node.has_type("any-service"))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return service_node.has_type("service")
|
|
|
|
&& service_node.attribute("name").has_value(service_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if arguments satisfy the condition specified for the route
|
|
|
|
*/
|
|
|
|
inline bool service_node_args_condition_satisfied(Genode::Xml_node service_node,
|
|
|
|
const char *args)
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
Genode::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];
|
|
|
|
if_arg.attribute("key").value(key, sizeof(key));
|
|
|
|
if_arg.attribute("value").value(value, sizeof(value));
|
|
|
|
|
|
|
|
char arg_value[VALUE_MAX_LEN];
|
|
|
|
Genode::Arg_string::find_arg(args, key).string(arg_value, sizeof(arg_value), "");
|
|
|
|
return Genode::strcmp(value, arg_value) == 0;
|
|
|
|
} catch (...) { }
|
|
|
|
|
|
|
|
/* if no if-arg node exists, the condition is met */
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Init-specific representation of a child service
|
|
|
|
*
|
|
|
|
* For init, we introduce this 'Service' variant that distinguishes two
|
|
|
|
* phases, declared and announced. A 'Routed_service' object is created
|
|
|
|
* when a '<provides>' declaration is found in init's configuration.
|
|
|
|
* At that time, however, no children including the server do yet exist.
|
|
|
|
* If, at this stage, a client tries to open a session to this service,
|
|
|
|
* the client get enqueued in a list of applicants and blocked. When
|
|
|
|
* the server officially announces its service and passes over the root
|
|
|
|
* capability, the 'Routed_service' enters the announced stage and any
|
|
|
|
* applicants get unblocked.
|
|
|
|
*/
|
|
|
|
class Routed_service : public Genode::Service
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
|
|
|
|
Genode::Root_capability _root;
|
|
|
|
bool _announced;
|
|
|
|
Genode::Server *_server;
|
|
|
|
|
|
|
|
struct Applicant : public Genode::Cancelable_lock,
|
|
|
|
public Genode::List<Applicant>::Element
|
|
|
|
{
|
|
|
|
Applicant() : Cancelable_lock(Genode::Lock::LOCKED) { }
|
|
|
|
};
|
|
|
|
|
|
|
|
Genode::Lock _applicants_lock;
|
|
|
|
Genode::List<Applicant> _applicants;
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor
|
|
|
|
*
|
|
|
|
* \param name name of service
|
|
|
|
* \param server server providing the service
|
|
|
|
*/
|
|
|
|
Routed_service(const char *name,
|
|
|
|
Genode::Server *server)
|
|
|
|
: Service(name), _announced(false), _server(server) { }
|
|
|
|
|
|
|
|
Genode::Server *server() const { return _server; }
|
|
|
|
|
|
|
|
void announce(Genode::Root_capability root)
|
|
|
|
{
|
|
|
|
Genode::Lock::Guard guard(_applicants_lock);
|
|
|
|
|
|
|
|
_root = root;
|
|
|
|
_announced = true;
|
|
|
|
|
|
|
|
/* wake up aspiring clients */
|
|
|
|
for (Applicant *a; (a = _applicants.first()); ) {
|
|
|
|
_applicants.remove(a);
|
|
|
|
a->unlock();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Genode::Session_capability session(const char *args)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* This function is called from the context of the client's
|
|
|
|
* activation thread. If the service is not yet announced,
|
|
|
|
* we let the client block.
|
|
|
|
*/
|
|
|
|
_applicants_lock.lock();
|
|
|
|
if (!_announced) {
|
|
|
|
Applicant myself;
|
|
|
|
_applicants.insert(&myself);
|
|
|
|
_applicants_lock.unlock();
|
|
|
|
myself.lock();
|
|
|
|
} else
|
|
|
|
_applicants_lock.unlock();
|
|
|
|
|
|
|
|
Genode::Session_capability cap;
|
|
|
|
try { cap = Genode::Root_client(_root).session(args); }
|
|
|
|
catch (Genode::Root::Invalid_args) { throw Invalid_args(); }
|
|
|
|
catch (Genode::Root::Unavailable) { throw Unavailable(); }
|
|
|
|
catch (Genode::Root::Quota_exceeded) { throw Quota_exceeded(); }
|
|
|
|
|
|
|
|
if (!cap.valid())
|
|
|
|
throw Unavailable();
|
|
|
|
|
|
|
|
return cap;
|
|
|
|
}
|
|
|
|
|
|
|
|
void upgrade(Genode::Session_capability sc, const char *args)
|
|
|
|
{
|
|
|
|
Genode::Root_client(_root).upgrade(sc, args);
|
|
|
|
}
|
|
|
|
|
|
|
|
void close(Genode::Session_capability sc)
|
|
|
|
{
|
|
|
|
Genode::Root_client(_root).close(sc);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Interface for name database
|
|
|
|
*/
|
|
|
|
struct Name_registry
|
|
|
|
{
|
|
|
|
virtual ~Name_registry() { }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if specified name is unique
|
|
|
|
*
|
|
|
|
* \return false if name already exists
|
|
|
|
*/
|
|
|
|
virtual bool is_unique(const char *name) const = 0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Find server with specified name
|
|
|
|
*/
|
|
|
|
virtual Genode::Server *lookup_server(const char *name) const = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class Child_registry;
|
|
|
|
|
|
|
|
|
|
|
|
class Child : Genode::Child_policy
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
|
|
|
|
friend class Child_registry;
|
|
|
|
|
|
|
|
Genode::List_element<Child> _list_element;
|
|
|
|
|
|
|
|
Genode::Xml_node _start_node;
|
|
|
|
|
|
|
|
Genode::Xml_node _default_route_node;
|
|
|
|
|
|
|
|
Name_registry *_name_registry;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Unique child name and file name of ELF binary
|
|
|
|
*/
|
|
|
|
struct Name
|
|
|
|
{
|
|
|
|
enum { MAX_NAME_LEN = 64 };
|
|
|
|
char file[MAX_NAME_LEN];
|
|
|
|
char unique[MAX_NAME_LEN];
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor
|
|
|
|
*
|
|
|
|
* Obtains file name and unique process name from XML node
|
|
|
|
*
|
|
|
|
* \param start_node XML start node
|
|
|
|
* \param registry registry tracking unique names
|
|
|
|
*/
|
|
|
|
Name(Genode::Xml_node start_node, Name_registry const *registry) {
|
|
|
|
try {
|
|
|
|
start_node.attribute("name").value(unique, sizeof(unique)); }
|
|
|
|
catch (Genode::Xml_node::Nonexistent_attribute) {
|
|
|
|
PWRN("Missing 'name' attribute in '<start>' entry.\n");
|
|
|
|
throw; }
|
|
|
|
|
|
|
|
/* check for a name confict with the other children */
|
|
|
|
if (!registry->is_unique(unique)) {
|
|
|
|
PERR("Child name \"%s\" is not unique", unique);
|
|
|
|
class Child_name_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));
|
|
|
|
|
|
|
|
/* check for a binary declaration */
|
|
|
|
try {
|
|
|
|
Genode::Xml_node binary = start_node.sub_node("binary");
|
|
|
|
binary.attribute("name").value(file, sizeof(file));
|
|
|
|
} catch (...) { }
|
|
|
|
}
|
|
|
|
} _name;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Resources assigned to the child
|
|
|
|
*/
|
|
|
|
struct Resources
|
|
|
|
{
|
|
|
|
long prio_levels_log2;
|
|
|
|
long priority;
|
|
|
|
Genode::size_t ram_quota;
|
|
|
|
Genode::Ram_connection ram;
|
|
|
|
Genode::Cpu_connection cpu;
|
|
|
|
Genode::Rm_connection rm;
|
|
|
|
|
|
|
|
Resources(Genode::Xml_node start_node, const char *label,
|
|
|
|
long prio_levels_log2)
|
|
|
|
:
|
|
|
|
prio_levels_log2(prio_levels_log2),
|
|
|
|
priority(read_priority(start_node)),
|
|
|
|
ram_quota(read_ram_quota(start_node)),
|
|
|
|
ram(label),
|
|
|
|
cpu(label, priority*(Genode::Cpu_session::PRIORITY_LIMIT >> prio_levels_log2))
|
|
|
|
{
|
|
|
|
/* deduce session costs from usable ram quota */
|
|
|
|
Genode::size_t session_donations = Genode::Rm_connection::RAM_QUOTA +
|
|
|
|
Genode::Cpu_connection::RAM_QUOTA +
|
|
|
|
Genode::Ram_connection::RAM_QUOTA;
|
|
|
|
|
|
|
|
if (ram_quota > session_donations)
|
|
|
|
ram_quota -= session_donations;
|
|
|
|
else ram_quota = 0;
|
|
|
|
|
|
|
|
ram.ref_account(Genode::env()->ram_session_cap());
|
|
|
|
Genode::env()->ram_session()->transfer_quota(ram.cap(), ram_quota);
|
|
|
|
}
|
|
|
|
} _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;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* ELF binary
|
|
|
|
*/
|
|
|
|
Genode::Rom_connection _binary_rom;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Private child configuration
|
|
|
|
*/
|
|
|
|
Init::Child_config _config;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Each child of init can act as a server
|
|
|
|
*/
|
|
|
|
Genode::Server _server;
|
|
|
|
|
|
|
|
Genode::Child _child;
|
|
|
|
|
|
|
|
Genode::Service_registry *_parent_services;
|
|
|
|
Genode::Service_registry *_child_services;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Policy helpers
|
|
|
|
*/
|
|
|
|
Init::Child_policy_enforce_labeling _labeling_policy;
|
|
|
|
Init::Child_policy_handle_cpu_priorities _priority_policy;
|
|
|
|
Init::Child_policy_provide_rom_file _config_policy;
|
|
|
|
Init::Child_policy_provide_rom_file _binary_policy;
|
Support for dynamic ROM sessions, fix #170
This patch introduces support for ROM sessions that update their
provided data during the lifetime of the session. The 'Rom_session'
interface had been extended with the new 'release()' and 'sigh()'
functions, which are needed to support the new protocol. All ROM
services have been updated to the new interface.
Furthermore, the patch changes the child policy of init
with regard to the handling of configuration files. The 'Init::Child'
used to always provide the ROM dataspace with the child's config file
via a locally implemented ROM service. However, for dynamic ROM
sessions, we need to establish a session to the real supplier of the ROM
data. This is achieved by using a new 'Child_policy_redirect_rom_file'
policy to handle the 'configfile' rather than handling the 'configfile'
case entirely within 'Child_config'.
To see the new facility in action, the new 'os/run/dynamic_config.run'
script provides a simple scenario. The config file of the test program
is provided by a service, which generates and updates the config data
at regular intervals.
In addition, new support has been added to let slaves use dynamic
reconfiguration. By using the new 'Child_policy_dynamic_rom_file', the
configuration of a slave can be changed dynamically at runtime via the
new 'configure()' function.
The config is provided as plain null-terminated string (instead of a
dataspace capability) because we need to buffer the config data anyway.
So there is no benefit of using a dataspace. For buffering configuration
data, a 'Ram_session' must be supplied. If no 'Ram_session' is specified
at construction time of a 'Slave_policy', no config is supplied to the
slave (which is still a common case).
An example for dynamically reconfiguring a slave is provided by
'os/run/dynamic_config_slave.run'.
2012-04-04 15:07:19 +00:00
|
|
|
Init::Child_policy_redirect_rom_file _configfile_policy;
|
2011-12-22 15:19:25 +00:00
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
Child(Genode::Xml_node start_node,
|
|
|
|
Genode::Xml_node default_route_node,
|
|
|
|
Name_registry *name_registry,
|
|
|
|
long prio_levels_log2,
|
|
|
|
Genode::Service_registry *parent_services,
|
|
|
|
Genode::Service_registry *child_services,
|
|
|
|
Genode::Cap_session *cap_session)
|
|
|
|
:
|
|
|
|
_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_log2),
|
|
|
|
_entrypoint(cap_session, ENTRYPOINT_STACK_SIZE, _name.unique, false),
|
|
|
|
_binary_rom(_name.file, _name.unique),
|
|
|
|
_config(_resources.ram.cap(), start_node),
|
|
|
|
_server(_resources.ram.cap()),
|
|
|
|
_child(_binary_rom.dataspace(), _resources.ram.cap(),
|
|
|
|
_resources.cpu.cap(), _resources.rm.cap(), &_entrypoint, this),
|
|
|
|
_parent_services(parent_services),
|
|
|
|
_child_services(child_services),
|
|
|
|
_labeling_policy(_name.unique),
|
|
|
|
_priority_policy(_resources.prio_levels_log2, _resources.priority),
|
|
|
|
_config_policy("config", _config.dataspace(), &_entrypoint),
|
Support for dynamic ROM sessions, fix #170
This patch introduces support for ROM sessions that update their
provided data during the lifetime of the session. The 'Rom_session'
interface had been extended with the new 'release()' and 'sigh()'
functions, which are needed to support the new protocol. All ROM
services have been updated to the new interface.
Furthermore, the patch changes the child policy of init
with regard to the handling of configuration files. The 'Init::Child'
used to always provide the ROM dataspace with the child's config file
via a locally implemented ROM service. However, for dynamic ROM
sessions, we need to establish a session to the real supplier of the ROM
data. This is achieved by using a new 'Child_policy_redirect_rom_file'
policy to handle the 'configfile' rather than handling the 'configfile'
case entirely within 'Child_config'.
To see the new facility in action, the new 'os/run/dynamic_config.run'
script provides a simple scenario. The config file of the test program
is provided by a service, which generates and updates the config data
at regular intervals.
In addition, new support has been added to let slaves use dynamic
reconfiguration. By using the new 'Child_policy_dynamic_rom_file', the
configuration of a slave can be changed dynamically at runtime via the
new 'configure()' function.
The config is provided as plain null-terminated string (instead of a
dataspace capability) because we need to buffer the config data anyway.
So there is no benefit of using a dataspace. For buffering configuration
data, a 'Ram_session' must be supplied. If no 'Ram_session' is specified
at construction time of a 'Slave_policy', no config is supplied to the
slave (which is still a common case).
An example for dynamically reconfiguring a slave is provided by
'os/run/dynamic_config_slave.run'.
2012-04-04 15:07:19 +00:00
|
|
|
_binary_policy("binary", _binary_rom.dataspace(), &_entrypoint),
|
|
|
|
_configfile_policy("config", _config.filename())
|
2011-12-22 15:19:25 +00:00
|
|
|
{
|
|
|
|
using namespace Genode;
|
|
|
|
|
|
|
|
if (_resources.ram_quota == 0)
|
|
|
|
PWRN("no valid RAM resource for child \"%s\"", _name.unique);
|
|
|
|
|
|
|
|
if (config_verbose) {
|
|
|
|
Genode::printf("child \"%s\"\n", _name.unique);
|
|
|
|
Genode::printf(" RAM quota: %zd\n", _resources.ram_quota);
|
|
|
|
Genode::printf(" ELF binary: %s\n", _name.file);
|
|
|
|
Genode::printf(" priority: %ld\n", _resources.priority);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Determine services provided by the child
|
|
|
|
*/
|
|
|
|
try {
|
|
|
|
Xml_node service_node = start_node.sub_node("provides").sub_node("service");
|
|
|
|
|
|
|
|
for (; ; service_node = service_node.next("service")) {
|
|
|
|
|
|
|
|
char name[Genode::Service::MAX_NAME_LEN];
|
|
|
|
service_node.attribute("name").value(name, sizeof(name));
|
|
|
|
|
|
|
|
if (config_verbose)
|
|
|
|
Genode::printf(" provides service %s\n", name);
|
|
|
|
|
|
|
|
child_services->insert(new (_child.heap())
|
|
|
|
Routed_service(name, &_server));
|
|
|
|
|
|
|
|
}
|
|
|
|
} catch (Xml_node::Nonexistent_sub_node) { }
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual ~Child() { }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return true if the child has the specified name
|
|
|
|
*/
|
|
|
|
bool has_name(const char *n) const { return !Genode::strcmp(name(), n); }
|
|
|
|
|
|
|
|
Genode::Server *server() { return &_server; }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Start execution of child
|
|
|
|
*/
|
|
|
|
void start() { _entrypoint.activate(); }
|
|
|
|
|
|
|
|
|
|
|
|
/****************************
|
|
|
|
** Child-policy interface **
|
|
|
|
****************************/
|
|
|
|
|
|
|
|
const char *name() const { return _name.unique; }
|
|
|
|
|
|
|
|
Genode::Service *resolve_session_request(const char *service_name,
|
|
|
|
const char *args)
|
|
|
|
{
|
|
|
|
Genode::Service *service = 0;
|
|
|
|
|
|
|
|
/* check for config file request */
|
|
|
|
if ((service = _config_policy.resolve_session_request(service_name, args)))
|
|
|
|
return service;
|
|
|
|
|
|
|
|
/* check for binary file request */
|
|
|
|
if ((service = _binary_policy.resolve_session_request(service_name, args)))
|
|
|
|
return service;
|
|
|
|
|
|
|
|
try {
|
|
|
|
Genode::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();
|
|
|
|
|
|
|
|
for (; ; service_node = service_node.next()) {
|
|
|
|
|
|
|
|
bool service_wildcard = service_node.has_type("any-service");
|
|
|
|
|
|
|
|
if (!service_node_matches(service_node, service_name))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!service_node_args_condition_satisfied(service_node, args))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
Genode::Xml_node target = service_node.sub_node();
|
|
|
|
for (; ; target = target.next()) {
|
|
|
|
|
|
|
|
if (target.has_type("parent")) {
|
|
|
|
service = _parent_services->find(service_name);
|
|
|
|
if (service)
|
|
|
|
return service;
|
|
|
|
|
|
|
|
if (!service_wildcard) {
|
|
|
|
PWRN("%s: service lookup for \"%s\" at parent failed", name(), service_name);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (target.has_type("child")) {
|
|
|
|
char server_name[Name::MAX_NAME_LEN];
|
|
|
|
server_name[0] = 0;
|
|
|
|
target.attribute("name").value(server_name, sizeof(server_name));
|
|
|
|
|
|
|
|
Genode::Server *server = _name_registry->lookup_server(server_name);
|
|
|
|
if (!server)
|
|
|
|
PWRN("%s: invalid route to non-existing server \"%s\"", name(), server_name);
|
|
|
|
|
|
|
|
service = _child_services->find(service_name, server);
|
|
|
|
if (service)
|
|
|
|
return service;
|
|
|
|
|
|
|
|
if (!service_wildcard) {
|
|
|
|
PWRN("%s: lookup to child service \"%s\" failed", name(), service_name);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (target.has_type("any-child")) {
|
|
|
|
if (_child_services->is_ambiguous(service_name)) {
|
|
|
|
PERR("%s: ambiguous routes to service \"%s\"", name(), service_name);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
service = _child_services->find(service_name);
|
|
|
|
if (service)
|
|
|
|
return service;
|
|
|
|
|
|
|
|
if (!service_wildcard) {
|
|
|
|
PWRN("%s: lookup for service \"%s\" failed", name(), service_name);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (target.is_last())
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (...) {
|
|
|
|
PWRN("%s: no route to service \"%s\"", name(), service_name);
|
|
|
|
}
|
|
|
|
return service;
|
|
|
|
}
|
|
|
|
|
|
|
|
void filter_session_args(const char *service,
|
|
|
|
char *args, Genode::size_t args_len)
|
|
|
|
{
|
|
|
|
_labeling_policy.filter_session_args(service, args, args_len);
|
|
|
|
_priority_policy.filter_session_args(service, args, args_len);
|
Support for dynamic ROM sessions, fix #170
This patch introduces support for ROM sessions that update their
provided data during the lifetime of the session. The 'Rom_session'
interface had been extended with the new 'release()' and 'sigh()'
functions, which are needed to support the new protocol. All ROM
services have been updated to the new interface.
Furthermore, the patch changes the child policy of init
with regard to the handling of configuration files. The 'Init::Child'
used to always provide the ROM dataspace with the child's config file
via a locally implemented ROM service. However, for dynamic ROM
sessions, we need to establish a session to the real supplier of the ROM
data. This is achieved by using a new 'Child_policy_redirect_rom_file'
policy to handle the 'configfile' rather than handling the 'configfile'
case entirely within 'Child_config'.
To see the new facility in action, the new 'os/run/dynamic_config.run'
script provides a simple scenario. The config file of the test program
is provided by a service, which generates and updates the config data
at regular intervals.
In addition, new support has been added to let slaves use dynamic
reconfiguration. By using the new 'Child_policy_dynamic_rom_file', the
configuration of a slave can be changed dynamically at runtime via the
new 'configure()' function.
The config is provided as plain null-terminated string (instead of a
dataspace capability) because we need to buffer the config data anyway.
So there is no benefit of using a dataspace. For buffering configuration
data, a 'Ram_session' must be supplied. If no 'Ram_session' is specified
at construction time of a 'Slave_policy', no config is supplied to the
slave (which is still a common case).
An example for dynamically reconfiguring a slave is provided by
'os/run/dynamic_config_slave.run'.
2012-04-04 15:07:19 +00:00
|
|
|
_configfile_policy.filter_session_args(service, args, args_len);
|
2011-12-22 15:19:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool announce_service(const char *service_name,
|
|
|
|
Genode::Root_capability root,
|
2012-04-11 16:24:37 +00:00
|
|
|
Genode::Allocator *alloc,
|
|
|
|
Genode::Server *server)
|
2011-12-22 15:19:25 +00:00
|
|
|
{
|
|
|
|
if (config_verbose)
|
|
|
|
Genode::printf("child \"%s\" announces service \"%s\"\n",
|
|
|
|
name(), service_name);
|
|
|
|
|
|
|
|
Genode::Service *s = _child_services->find(service_name, &_server);
|
|
|
|
Routed_service *rs = dynamic_cast<Routed_service *>(s);
|
|
|
|
if (!s || !rs) {
|
|
|
|
PERR("%s: illegal announcement of service \"%s\"", name(), service_name);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
rs->announce(root);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* _INCLUDE__INIT__CHILD_H_ */
|