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'.
This commit is contained in:
Norman Feske 2012-04-04 17:07:19 +02:00
parent ba248fe554
commit 9a00ad7ae3
23 changed files with 752 additions and 68 deletions

View File

@ -26,6 +26,8 @@ namespace Genode {
Rom_dataspace_capability dataspace() {
return call<Rpc_dataspace>(); }
void sigh(Signal_context_capability cap) { call<Rpc_sigh>(cap); }
};
}

View File

@ -19,6 +19,7 @@
#include <dataspace/capability.h>
#include <session/session.h>
#include <base/signal.h>
namespace Genode {
@ -38,17 +39,43 @@ namespace Genode {
* \return capability to ROM dataspace
*
* The capability may be invalid.
*
* Consecutive calls of this functions are not guaranteed to return the
* same dataspace as dynamic ROM sessions may update the ROM data
* during the lifetime of the session. When calling the function, the
* server may destroy the old dataspace and replace it with a new one
* containing the updated data. Hence, prior calling this function, the
* client should make sure to detach the previously requested dataspace
* from its local address space.
*/
virtual Rom_dataspace_capability dataspace() = 0;
/**
* Register signal handler to be notified of ROM data changes
*
* The ROM session interface allows for the implementation of ROM
* services that dynamically update the data exported as ROM dataspace
* during the lifetime of the session. This is useful in scenarios
* where this data is generated rather than originating from a static
* file, for example to update a program's configuration at runtime.
*
* By installing a signal handler using the 'sigh()' function, the
* client will receive a notification each time the data changes at the
* server. From the client's perspective, the original data contained
* in the currently used dataspace remains unchanged until the client
* calls 'dataspace()' the next time.
*/
virtual void sigh(Signal_context_capability sigh) = 0;
/*********************
** RPC declaration **
*********************/
GENODE_RPC(Rpc_dataspace, Rom_dataspace_capability, dataspace);
GENODE_RPC(Rpc_sigh, void, sigh, Signal_context_capability);
GENODE_RPC_INTERFACE(Rpc_dataspace);
GENODE_RPC_INTERFACE(Rpc_dataspace, Rpc_sigh);
};
}

View File

@ -66,6 +66,7 @@ namespace Genode {
***************************/
Rom_dataspace_capability dataspace() { return _ds_cap; }
void sigh(Signal_context_capability) { }
};
}

View File

@ -140,15 +140,18 @@ struct Usb_policy : public Genode::Slave_policy
public:
Usb_policy(Genode::Rpc_entrypoint &entrypoint,
Input::Source_registry &input_source_registry,
Block::Driver_registry &block_driver_registry,
Genode::Dataspace_capability config)
Usb_policy(Genode::Rpc_entrypoint &entrypoint,
Input::Source_registry &input_source_registry,
Block::Driver_registry &block_driver_registry,
Genode::Ram_session *ram,
char const *config)
:
Genode::Slave_policy("usb_drv", entrypoint, config),
Genode::Slave_policy("usb_drv", entrypoint, ram),
_input_source_registry(input_source_registry),
_block_driver_registry(block_driver_registry)
{ }
{
configure(config);
}
bool announce_service(const char *service_name,
Genode::Root_capability root,
@ -238,19 +241,12 @@ int main(int argc, char **argv)
static Ps2_policy ps2_policy(ps2_ep, input_source_registry);
static Genode::Slave ps2_slave(ps2_ep, ps2_policy, 512*1024);
/*
* Create config dataspace for USB driver
*/
enum { USB_CONFIG_MAX_LEN = 4096 };
Genode::Attached_ram_dataspace usb_config_ds(Genode::env()->ram_session(),
USB_CONFIG_MAX_LEN);
char const *config = "<config><hid/><storage/></config>";
Genode::strncpy(usb_config_ds.local_addr<char>(), config, USB_CONFIG_MAX_LEN);
/* create USB driver */
char const *config = "<config><hid/><storage/></config>";
static Rpc_entrypoint usb_ep(&cap, STACK_SIZE, "usb_slave");
static Usb_policy usb_policy(usb_ep, input_source_registry,
block_driver_registry, usb_config_ds.cap());
block_driver_registry, env()->ram_session(),
config);
static Genode::Slave usb_slave(usb_ep, usb_policy, 3*1024*1024);
/* create ATAPI driver */

View File

@ -368,6 +368,7 @@ namespace Init {
Init::Child_policy_handle_cpu_priorities _priority_policy;
Init::Child_policy_provide_rom_file _config_policy;
Init::Child_policy_provide_rom_file _binary_policy;
Init::Child_policy_redirect_rom_file _configfile_policy;
public:
@ -396,7 +397,8 @@ namespace Init {
_labeling_policy(_name.unique),
_priority_policy(_resources.prio_levels_log2, _resources.priority),
_config_policy("config", _config.dataspace(), &_entrypoint),
_binary_policy("binary", _binary_rom.dataspace(), &_entrypoint)
_binary_policy("binary", _binary_rom.dataspace(), &_entrypoint),
_configfile_policy("config", _config.filename())
{
using namespace Genode;
@ -545,6 +547,7 @@ namespace Init {
{
_labeling_policy.filter_session_args(service, args, args_len);
_priority_policy.filter_session_args(service, args, args_len);
_configfile_policy.filter_session_args(service, args, args_len);
}
bool announce_service(const char *service_name,

View File

@ -27,10 +27,9 @@ namespace Init {
private:
enum { CONFIGFILE_NAME_LEN = 64 };
char _filename[CONFIGFILE_NAME_LEN];
Genode::Ram_session_capability _ram_session_cap;
Genode::Rom_session_capability _rom_session_cap;
Genode::Rom_dataspace_capability _config_rom_ds;
Genode::Ram_dataspace_capability _config_ram_ds;
public:
@ -38,36 +37,34 @@ namespace Init {
/**
* Constructor
*
* The provided RAM session is used to obtain a dataspace
* for holding the copy of the child's configuration data.
* Normally, the child's RAM session should be used to
* account the consumed RAM quota to the child.
* 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)
Genode::Xml_node start_node)
: _ram_session_cap(ram_session)
{
using namespace Genode;
/*
* If the start node contains a 'filename' entry,
* we obtain the specified file from ROM.
* If the start node contains a 'filename' entry, we only keep
* the information about the file name.
*/
char filename[CONFIGFILE_NAME_LEN];
_filename[0] = 0;
try {
Xml_node configfile_node = start_node.sub_node("configfile");
configfile_node.attribute("name").value(filename, sizeof(filename));
configfile_node.attribute("name")
.value(_filename, sizeof(_filename));
Rom_connection rom(filename);
rom.on_destruction(Rom_connection::KEEP_OPEN);
_rom_session_cap = rom.cap();
_config_rom_ds = rom.dataspace();
return;
} catch (...) { }
/*
* If the start node contains a 'config' entry,
* we copy this entry into a fresh dataspace to
* be provided to our child.
* 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 {
@ -111,23 +108,32 @@ namespace Init {
using namespace Genode;
/*
* The configuration data is either provided as a
* ROM dataspace (holding a complete configfile) or
* as a RAM dataspace holding a copy of the start
* node's config entry.
* 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 (_rom_session_cap.valid())
env()->parent()->close(_rom_session_cap);
else
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 _rom_session_cap.valid() ? Genode::Dataspace_capability(_config_rom_ds)
: Genode::Dataspace_capability(_config_ram_ds); }
return Genode::Dataspace_capability(_config_ram_ds); }
};
}

View File

@ -123,6 +123,8 @@ namespace Init {
Genode::Rom_dataspace_capability dataspace() {
return Genode::static_cap_cast<Genode::Rom_dataspace>(ds_cap); }
void sigh(Genode::Signal_context_capability) { }
} _local_rom_session;
Genode::Rpc_entrypoint *_ep;
@ -194,6 +196,39 @@ namespace Init {
};
class Child_policy_redirect_rom_file
{
private:
char const *_from;
char const *_to;
public:
Child_policy_redirect_rom_file(const char *from, const char *to)
: _from(from), _to(to) { }
void filter_session_args(const char *service,
char *args, Genode::size_t args_len)
{
if (!_from || !_to) return;
/* ignore session requests for non-ROM services */
if (Genode::strcmp(service, "ROM")) return;
/* drop out if request refers to another file name */
enum { FILENAME_MAX_LEN = 32 };
char buf[FILENAME_MAX_LEN];
Genode::Arg_string::find_arg(args, "filename").string(buf, sizeof(buf), "");
if (Genode::strcmp(_from, buf) != 0) return;
/* replace filename argument */
Genode::snprintf(buf, sizeof(buf), "\"%s\"", _to);
Genode::Arg_string::set_arg(args, args_len, "filename", buf);
}
};
class Traditional_child_policy : public Genode::Child_policy,
public Genode::Client
{

View File

@ -0,0 +1,163 @@
/*
* \brief Child policy helper for supplying dynamic ROM modules
* \author Norman Feske
* \date 2012-04-04
*/
/*
* Copyright (C) 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__OS__CHILD_POLICY_DYNAMIC_ROM_H_
#define _INCLUDE__OS__CHILD_POLICY_DYNAMIC_ROM_H_
#include <ram_session/ram_session.h>
#include <rom_session/rom_session.h>
#include <base/rpc_server.h>
#include <os/attached_ram_dataspace.h>
namespace Genode {
class Child_policy_dynamic_rom_file : public Rpc_object<Rom_session>,
public Service
{
private:
Ram_session *_ram;
/*
* We keep two dataspaces around. The foreground ('_fg') dataspace
* is the one we present to the client. While the foreground
* dataspace is in use, we perform all modifications of the data
* in the background dataspace (which is invisible to the client).
* Once the client calls 'dataspace()', we promote the old
* background dataspace to the new foreground and thereby hand out
* the former background dataspace.
*/
Attached_ram_dataspace _fg;
Attached_ram_dataspace _bg;
bool _bg_has_pending_data;
Signal_context_capability _sigh_cap;
Rpc_entrypoint &_ep;
Rom_session_capability _rom_session_cap;
enum { FILENAME_MAX_LEN = 32 };
char _filename[FILENAME_MAX_LEN];
public:
/**
* Constructor
*
* \param ram RAM session used to allocate the backing store
* for buffering ROM module data
*
* If 'ram' is 0, the child policy is ineffective.
*/
Child_policy_dynamic_rom_file(const char *filename,
Rpc_entrypoint &ep,
Ram_session *ram)
:
Service("ROM"),
_ram(ram),
_fg(0, 0), _bg(0, 0),
_bg_has_pending_data(false),
_ep(ep),
_rom_session_cap(_ep.manage(this))
{
strncpy(_filename, filename, sizeof(_filename));
}
/**
* Destructor
*/
~Child_policy_dynamic_rom_file() { _ep.dissolve(this); }
/**
* Load new content into ROM module
*
* \throw Ram_session::Alloc_failed
* \throw Rm_session::Attach_failed
*/
void load(void const *data, size_t data_len)
{
if (!_ram) {
PERR("Error: No backing store for loading ROM data");
return;
}
/* let background buffer grow if needed */
if (_bg.size() < data_len)
_bg.realloc(_ram, data_len);
memcpy(_bg.local_addr<void>(), data, data_len);
_bg_has_pending_data = true;
if (_sigh_cap.valid())
Signal_transmitter(_sigh_cap).submit();
}
/***************************
** ROM session interface **
***************************/
Rom_dataspace_capability dataspace()
{
if (!_fg.size() && !_bg_has_pending_data) {
PERR("Error: no data loaded");
return Rom_dataspace_capability();
}
/*
* Keep foreground if no background exists. Otherwise, use
* old background as new foreground.
*/
if (_bg_has_pending_data) {
_fg.swap(_bg);
_bg_has_pending_data = false;
}
Dataspace_capability ds_cap = _fg.cap();
return static_cap_cast<Rom_dataspace>(ds_cap);
}
void sigh(Signal_context_capability cap) { _sigh_cap = cap; }
/***********************
** Service interface **
***********************/
Session_capability session(const char *) { return _rom_session_cap; }
void upgrade(Session_capability, const char *) { }
void close(Session_capability) { }
/*********************
** Policy function **
*********************/
Service *resolve_session_request(const char *service_name,
const char *args)
{
if (!_ram) return 0;
/* ignore session requests for non-ROM services */
if (strcmp(service_name, "ROM")) return 0;
/* drop out if request refers to another file name */
char buf[FILENAME_MAX_LEN];
Arg_string::find_arg(args, "filename").string(buf, sizeof(buf), "");
return !strcmp(buf, _filename) ? this : 0;
}
};
}
#endif /* _INCLUDE__OS__CHILD_POLICY_DYNAMIC_ROM_H_ */

View File

@ -47,6 +47,36 @@ namespace Genode {
{ }
Xml_node xml_node() { return _config_xml; }
/**
* Register signal handler for tracking config modifications
*/
void sigh(Signal_context_capability cap) { _config_rom.sigh(cap); }
/**
* Reload configuration
*
* \throw Invalid if the new configuration has an invalid syntax
*
* This function is meant to be called as response to a signal
* received by the signal handler as registered via 'sigh()'.
*/
void reload()
{
try {
/* re-acquire dataspace from ROM session */
env()->rm_session()->detach(_config_xml.addr());
_config_ds = _config_rom.dataspace();
/* re-initialize XML node with new config data */
_config_xml = Xml_node(env()->rm_session()->attach(_config_ds),
Genode::Dataspace_client(_config_ds).size());
} catch (Genode::Xml_node::Invalid_syntax) {
PERR("Config file has invalid syntax");
throw Invalid();
}
}
};
/**

View File

@ -22,6 +22,7 @@
#include <ram_session/connection.h>
#include <cpu_session/connection.h>
#include <rm_session/connection.h>
#include <os/child_policy_dynamic_rom.h>
namespace Genode {
@ -44,14 +45,13 @@ namespace Genode {
private:
char const *_label;
Genode::Service_registry _parent_services;
Genode::Rpc_entrypoint &_entrypoint;
Genode::Rom_connection _binary_rom;
Init::Child_policy_enforce_labeling _labeling_policy;
Init::Child_policy_provide_rom_file _binary_policy;
Init::Child_policy_provide_rom_file _config_policy;
char const *_label;
Genode::Service_registry _parent_services;
Genode::Rpc_entrypoint &_entrypoint;
Genode::Rom_connection _binary_rom;
Init::Child_policy_enforce_labeling _labeling_policy;
Init::Child_policy_provide_rom_file _binary_policy;
Genode::Child_policy_dynamic_rom_file _config_policy;
bool _service_permitted(const char *service_name)
{
@ -67,25 +67,36 @@ namespace Genode {
/**
* Slave-policy constructor
*
* \param label name of the program to start
* \param entrypoint entrypoint used to provide local services
* such as the config ROM service
* \param config dataspace containing the child config
* \param label name of the program to start
* \param entrypoint entrypoint used to provide local services
* such as the config ROM service
* \param ram RAM session used for buffering config data
*
* If 'ram' is set to 0, no configuration can be supplied to the
* slave.
*/
Slave_policy(const char *label,
Genode::Rpc_entrypoint &entrypoint,
Genode::Dataspace_capability config = Genode::Dataspace_capability())
Slave_policy(const char *label,
Genode::Rpc_entrypoint &entrypoint,
Genode::Ram_session *ram = 0)
:
_label(label),
_entrypoint(entrypoint),
_binary_rom(_label, _label),
_labeling_policy(_label),
_binary_policy("binary", _binary_rom.dataspace(), &_entrypoint),
_config_policy("config", config, &_entrypoint)
_config_policy("config", _entrypoint, ram)
{ }
Genode::Dataspace_capability binary() { return _binary_rom.dataspace(); }
/**
* Assign new configuration to slave
*/
void configure(char const *config)
{
_config_policy.load(config, Genode::strlen(config) + 1);
}
/****************************
** Child_policy interface **

50
os/run/dynamic_config.run Normal file
View File

@ -0,0 +1,50 @@
build "core init test/dynamic_config"
create_boot_directory
install_config {
<config>
<parent-provides>
<service name="ROM"/>
<service name="RAM"/>
<service name="CPU"/>
<service name="RM"/>
<service name="CAP"/>
<service name="PD"/>
<service name="IRQ"/>
<service name="IO_PORT"/>
<service name="SIGNAL"/>
<service name="LOG"/>
</parent-provides>
<default-route>
<any-service> <parent/> <any-child/> </any-service>
</default-route>
<start name="timer">
<resource name="RAM" quantum="1M"/>
<provides><service name="Timer"/></provides>
</start>
<start name="test-dynamic_config_server">
<resource name="RAM" quantum="1M"/>
<provides> <service name="ROM" /> </provides>
</start>
<start name="test-dynamic_config">
<resource name="RAM" quantum="1M"/>
<configfile name="config.dynamic" />
<route>
<service name="ROM">
<if-arg key="filename" value="config.dynamic" />
<child name="test-dynamic_config_server"/>
</service>
<any-service> <parent /> </any-service>
</route>
</start>
</config>
}
build_boot_image "core init timer test-dynamic_config test-dynamic_config_server"
append qemu_args "-nographic -m 64"
run_genode_until {obtained counter value 11 from config.*} 100
puts "Test succeeded"

View File

@ -0,0 +1,38 @@
build "core init test/dynamic_config"
create_boot_directory
install_config {
<config>
<parent-provides>
<service name="ROM"/>
<service name="RAM"/>
<service name="CPU"/>
<service name="RM"/>
<service name="CAP"/>
<service name="PD"/>
<service name="IRQ"/>
<service name="IO_PORT"/>
<service name="SIGNAL"/>
<service name="LOG"/>
</parent-provides>
<default-route>
<any-service> <parent/> <any-child/> </any-service>
</default-route>
<start name="timer">
<resource name="RAM" quantum="1M"/>
<provides><service name="Timer"/></provides>
</start>
<start name="test-dynamic_config_master">
<resource name="RAM" quantum="2M"/>
</start>
</config>
}
build_boot_image "core init timer test-dynamic_config test-dynamic_config_master"
append qemu_args "-nographic -m 64"
run_genode_until {obtained counter value 11 from config.*} 100
puts "Test succeeded"

View File

@ -186,11 +186,12 @@ namespace Iso {
File *_file;
public:
Rom_dataspace_capability dataspace() {
return static_cap_cast<Rom_dataspace>(_file->rm()->dataspace()); }
public:
void sigh(Signal_context_capability) { }
Rom_component(char *path, Signal_receiver *receiver,
Backing_store *backing_store)
@ -205,10 +206,6 @@ namespace Iso {
File::cache()->insert(_file);
}
~Rom_component()
{}
};
@ -274,7 +271,7 @@ namespace Iso {
try {
return new (md_alloc())
Rom_component(_path, Pager::pager()->signal_receiver(),
_backing_store);
_backing_store);
}
catch (Io_error) { throw Root::Unavailable(); }
catch (Non_data_disc) { throw Root::Unavailable(); }

View File

@ -55,6 +55,8 @@ class Rom_session_component : public Genode::Rpc_object<Genode::Rom_session>
***************************/
Genode::Rom_dataspace_capability dataspace() { return _ds_cap; }
void sigh(Genode::Signal_context_capability) { }
};
#endif /* _ROM_SESSION_COMPONENT_H_ */

View File

@ -67,6 +67,8 @@ class Rom_session_component : public Genode::Rpc_object<Genode::Rom_session>
Genode::Rom_dataspace_capability dataspace() {
return _rom.dataspace(); }
void sigh(Genode::Signal_context_capability) { }
};
class Rom_root : public Genode::Root_component<Rom_session_component>

View File

@ -156,6 +156,8 @@ class Rom_session_component : public Genode::Rpc_object<Genode::Rom_session>
Genode::Dataspace_capability ds = _file_ds;
return Genode::static_cap_cast<Genode::Rom_dataspace>(ds);
}
void sigh(Genode::Signal_context_capability) { }
};

View File

@ -0,0 +1,62 @@
/*
* \brief Test for changing configuration at runtime
* \author Norman Feske
* \date 2012-04-04
*/
/*
* Copyright (C) 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.
*/
/* Genode includes */
#include <os/config.h>
void parse_config()
{
try {
long counter = 1;
Genode::config()->xml_node().sub_node("counter").value(&counter);
Genode::printf("obtained counter value %ld from config\n", counter);
} catch (...) {
PERR("Error while parsing the configuration");
}
}
int main(int, char **)
{
parse_config();
struct Signal_dispatcher : public Genode::Signal_context
{
void dispatch()
{
try {
Genode::config()->reload();
parse_config();
} catch (Genode::Config::Invalid) {
PERR("Error: reloading config failed");
}
}
} signal_dispatcher;
static Genode::Signal_receiver sig_rec;
/* register signal handler for config changes */
Genode::config()->sigh(sig_rec.manage(&signal_dispatcher));
for (;;) {
/* wait for config change */
Genode::Signal signal = sig_rec.wait_for_signal();
for (int i = 0; i < signal.num(); i++)
static_cast<Signal_dispatcher *>(signal.context())->dispatch();
}
return 0;
}

View File

@ -0,0 +1,68 @@
/*
* \brief Test for changing the configuration of a slave at runtime
* \author Norman Feske
* \date 2012-04-04
*/
/*
* Copyright (C) 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.
*/
/* Genode includes */
#include <os/config.h>
#include <os/slave.h>
#include <timer_session/connection.h>
#include <cap_session/connection.h>
struct Test_slave_policy : Genode::Slave_policy
{
const char **_permitted_services() const
{
static const char *permitted_services[] = {
"RM", "LOG", "SIGNAL", 0 };
return permitted_services;
};
Test_slave_policy(char const *name, Genode::Rpc_entrypoint &ep)
: Genode::Slave_policy(name, ep, Genode::env()->ram_session())
{ }
};
int main(int, char **)
{
using namespace Genode;
enum { STACK_SIZE = 2*4096 };
static Cap_connection cap;
static Rpc_entrypoint ep(&cap, STACK_SIZE, "slave_ep");
static Test_slave_policy slave_policy("test-dynamic_config", ep);
/* define initial config for slave */
slave_policy.configure("<config><counter>-1</counter></config>");
static Genode::Slave slave(ep, slave_policy, 512*1024);
/* update slave config at regular intervals */
int counter = 0;
for (;;) {
static Timer::Connection timer;
timer.msleep(250);
/* re-generate configuration */
char buf[100];
Genode::snprintf(buf, sizeof(buf),
"<config><counter>%d</counter></config>",
counter++);
slave_policy.configure(buf);
}
return 0;
}

View File

@ -0,0 +1,3 @@
TARGET = test-dynamic_config_master
SRC_CC = main.cc
LIBS = env signal server process

View File

@ -0,0 +1,176 @@
/*
* \brief Test for changing configuration at runtime (server-side)
* \author Norman Feske
* \date 2012-04-04
*
* This program provides a generated config file as ROM service. After
* opening a ROM session, the data gets repeatedly updated.
*/
/*
* Copyright (C) 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.
*/
/* Genode includes */
#include <base/rpc_server.h>
#include <base/signal.h>
#include <root/root.h>
#include <os/attached_ram_dataspace.h>
#include <timer_session/connection.h>
#include <rom_session/rom_session.h>
#include <cap_session/connection.h>
/**
* Root interface that hands out a statically created session
*/
template <typename SESSION_TYPE>
class Static_root : public Genode::Rpc_object<Genode::Typed_root<SESSION_TYPE> >
{
private:
typedef Genode::Capability<SESSION_TYPE> Session_capability;
Session_capability _session;
public:
/**
* Constructor
*
* \param session session to be provided to the client
*/
Static_root(Session_capability session) : _session(session) { }
/********************
** Root interface **
********************/
Genode::Session_capability session(Genode::Root::Session_args const &)
{
return _session;
}
void upgrade(Genode::Session_capability, Genode::Root::Upgrade_args const &) { }
void close(Genode::Session_capability) { }
};
/*
* The implementation of this class follows the lines of
* 'os/include/os/child_policy_dynamic_rom.h'.
*/
class Rom_session_component : public Genode::Rpc_object<Genode::Rom_session>
{
private:
Genode::Attached_ram_dataspace _fg;
Genode::Attached_ram_dataspace _bg;
bool _bg_has_pending_data;
Genode::Lock _lock;
Genode::Signal_context_capability _sigh;
public:
/**
* Constructor
*/
Rom_session_component()
: _fg(0, 0), _bg(0, 0), _bg_has_pending_data(false) { }
/**
* Update the config file
*/
void configure(char const *data)
{
Genode::Lock::Guard guard(_lock);
Genode::size_t const data_len = Genode::strlen(data) + 1;
/* let background buffer grow if needed */
if (_bg.size() < data_len)
_bg.realloc(Genode::env()->ram_session(), data_len);
Genode::strncpy(_bg.local_addr<char>(), data, data_len);
_bg_has_pending_data = true;
/* inform client about the changed data */
if (_sigh.valid())
Genode::Signal_transmitter(_sigh).submit();
}
/***************************
** ROM session interface **
***************************/
Genode::Rom_dataspace_capability dataspace()
{
Genode::Lock::Guard guard(_lock);
if (!_fg.size() && !_bg_has_pending_data) {
PERR("Error: no data loaded");
return Genode::Rom_dataspace_capability();
}
/*
* Keep foreground if no background exists. Otherwise, use old
* background as new foreground.
*/
if (_bg_has_pending_data) {
_fg.swap(_bg);
_bg_has_pending_data = false;
}
Genode::Dataspace_capability ds_cap = _fg.cap();
return Genode::static_cap_cast<Genode::Rom_dataspace>(ds_cap);
}
void sigh(Genode::Signal_context_capability sigh_cap)
{
Genode::Lock::Guard guard(_lock);
_sigh = sigh_cap;
}
};
int main(int argc, char **argv)
{
using namespace Genode;
/* connection to capability service needed to create capabilities */
static Cap_connection cap;
enum { STACK_SIZE = 8*1024 };
static Rpc_entrypoint ep(&cap, STACK_SIZE, "rom_ep");
static Rom_session_component rom_session;
static Static_root<Rom_session> rom_root(ep.manage(&rom_session));
rom_session.configure("<config><counter>-1</counter></config>");
/* announce server */
env()->parent()->announce(ep.manage(&rom_root));
int counter = 0;
for (;;) {
static Timer::Connection timer;
timer.msleep(250);
/* re-generate configuration */
char buf[100];
Genode::snprintf(buf, sizeof(buf),
"<config><counter>%d</counter></config>",
counter++);
rom_session.configure(buf);
}
return 0;
};

View File

@ -0,0 +1,3 @@
TARGET = test-dynamic_config_server
SRC_CC = main.cc
LIBS = env signal server

View File

@ -0,0 +1,3 @@
TARGET = test-dynamic_config
SRC_CC = main.cc
LIBS = env signal

View File

@ -72,6 +72,10 @@ namespace Gdb_monitor {
return static_cap_cast<Rom_dataspace>(
static_cap_cast<Dataspace>(_clone_cap));
}
void release() { }
void sigh(Genode::Signal_context_capability) { }
};