Permalink
Browse files

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'.
  • Loading branch information...
nfeske committed Apr 4, 2012
1 parent ba248fe commit 9a00ad7ae3ac8e4fd4867555db7671df34aac882
@@ -26,6 +26,8 @@ namespace Genode {
Rom_dataspace_capability dataspace() {
return call<Rpc_dataspace>(); }
+
+ void sigh(Signal_context_capability cap) { call<Rpc_sigh>(cap); }
};
}
@@ -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);
};
}
@@ -66,6 +66,7 @@ namespace Genode {
***************************/
Rom_dataspace_capability dataspace() { return _ds_cap; }
+ void sigh(Signal_context_capability) { }
};
}
@@ -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
@@ -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,
@@ -27,47 +27,44 @@ 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:
/**
* 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); }
};
}
@@ -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
{
Oops, something went wrong.

0 comments on commit 9a00ad7

Please sign in to comment.