genode/os/include/init/child_config.h
Norman Feske 9a00ad7ae3 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-05 11:25:26 +02:00

141 lines
3.8 KiB
C++

/*
* \brief Utility for handling child configuration
* \author Norman Feske
* \date 2008-03-22
*/
/*
* Copyright (C) 2008-2012 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__CHILD_CONFIG_H_
#define _INCLUDE__INIT__CHILD_CONFIG_H_
#include <base/env.h>
#include <base/printf.h>
#include <util/xml_node.h>
#include <rom_session/connection.h>
#include <ram_session/client.h>
namespace Init {
class Child_config
{
private:
enum { CONFIGFILE_NAME_LEN = 64 };
char _filename[CONFIGFILE_NAME_LEN];
Genode::Ram_session_capability _ram_session_cap;
Genode::Ram_dataspace_capability _config_ram_ds;
public:
/**
* Constructor
*
* The provided RAM session is used to obtain a dataspace for
* holding the copy of the child's configuration data unless the
* configuration is supplied via a config file. Normally, the
* child's RAM session should be used to account the consumed RAM
* quota to the child.
*/
Child_config(Genode::Ram_session_capability ram_session,
Genode::Xml_node start_node)
: _ram_session_cap(ram_session)
{
using namespace Genode;
/*
* If the start node contains a 'filename' entry, we only keep
* the information about the file name.
*/
_filename[0] = 0;
try {
Xml_node configfile_node = start_node.sub_node("configfile");
configfile_node.attribute("name")
.value(_filename, sizeof(_filename));
return;
} catch (...) { }
/*
* If the start node contains a 'config' entry, we copy this
* entry into a fresh dataspace to be provided to our child.
*/
Ram_session_client rsc(_ram_session_cap);
try {
Xml_node config_node = start_node.sub_node("config");
const char *config = config_node.addr();
Genode::size_t config_size = config_node.size();
if (!config || !config_size) return;
/*
* Allocate RAM dataspace that is big enough to
* hold the configuration and the null termination.
*/
_config_ram_ds = rsc.alloc(config_size + 1);
/*
* Make dataspace locally accessible, copy
* configuration into the dataspace, and append
* a string-terminating zero.
*/
void *addr = env()->rm_session()->attach(_config_ram_ds);
Genode::memcpy(addr, config, config_size);
static_cast<char *>(addr)[config_size] = 0;
env()->rm_session()->detach(addr);
} catch (Rm_session::Attach_failed) {
rsc.free(_config_ram_ds);
return;
} catch (Ram_session::Alloc_failed) {
return;
} catch (Xml_node::Nonexistent_sub_node) { }
}
/**
* Destructor
*/
~Child_config()
{
using namespace Genode;
/*
* The configuration data is either provided as a ROM session
* (holding a complete configfile) or as a RAM dataspace
* holding a copy of the start node's config entry. In the
* latter case, the child's configuration resides in a
* shadow copy kept in '_config_ram_ds'.
*/
if (_config_ram_ds.valid())
Ram_session_client(_ram_session_cap).free(_config_ram_ds);
}
/**
* Return file name if configuration comes from a file
*
* If the configuration is provided inline, the function returns 0.
*/
char const *filename() const {
return _filename[0] != 0 ? _filename : 0; }
/**
* Request dataspace holding the start node's configuration data
*
* This function returns a valid dataspace only when using an
* inline configuration (if 'filename()' returns 0).
*/
Genode::Dataspace_capability dataspace() {
return Genode::Dataspace_capability(_config_ram_ds); }
};
}
#endif /* _INCLUDE__INIT__CHILD_CONFIG_H_ */