From 9a00ad7ae3ac8e4fd4867555db7671df34aac882 Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Wed, 4 Apr 2012 17:07:19 +0200 Subject: [PATCH] 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'. --- base/include/rom_session/client.h | 2 + base/include/rom_session/rom_session.h | 29 ++- base/src/core/include/rom_session_component.h | 1 + gems/src/server/d3m/main.cc | 28 ++- os/include/init/child.h | 5 +- os/include/init/child_config.h | 60 +++--- os/include/init/child_policy.h | 35 ++++ os/include/os/child_policy_dynamic_rom.h | 163 ++++++++++++++++ os/include/os/config.h | 30 +++ os/include/os/slave.h | 43 +++-- os/run/dynamic_config.run | 50 +++++ os/run/dynamic_config_slave.run | 38 ++++ os/src/server/iso9660/main.cc | 11 +- os/src/server/loader/rom_session_component.h | 2 + os/src/server/rom_prefetcher/main.cc | 2 + os/src/server/tar_rom/main.cc | 2 + os/src/test/dynamic_config/main.cc | 62 ++++++ os/src/test/dynamic_config/master/main.cc | 68 +++++++ os/src/test/dynamic_config/master/target.mk | 3 + os/src/test/dynamic_config/server/main.cc | 176 ++++++++++++++++++ os/src/test/dynamic_config/server/target.mk | 3 + os/src/test/dynamic_config/target.mk | 3 + ports/src/app/gdb_monitor/rom.h | 4 + 23 files changed, 752 insertions(+), 68 deletions(-) create mode 100644 os/include/os/child_policy_dynamic_rom.h create mode 100644 os/run/dynamic_config.run create mode 100644 os/run/dynamic_config_slave.run create mode 100644 os/src/test/dynamic_config/main.cc create mode 100644 os/src/test/dynamic_config/master/main.cc create mode 100644 os/src/test/dynamic_config/master/target.mk create mode 100644 os/src/test/dynamic_config/server/main.cc create mode 100644 os/src/test/dynamic_config/server/target.mk create mode 100644 os/src/test/dynamic_config/target.mk diff --git a/base/include/rom_session/client.h b/base/include/rom_session/client.h index ffd6c6c74..421392e9d 100644 --- a/base/include/rom_session/client.h +++ b/base/include/rom_session/client.h @@ -26,6 +26,8 @@ namespace Genode { Rom_dataspace_capability dataspace() { return call(); } + + void sigh(Signal_context_capability cap) { call(cap); } }; } diff --git a/base/include/rom_session/rom_session.h b/base/include/rom_session/rom_session.h index 43e156254..a651965f0 100644 --- a/base/include/rom_session/rom_session.h +++ b/base/include/rom_session/rom_session.h @@ -19,6 +19,7 @@ #include #include +#include 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); }; } diff --git a/base/src/core/include/rom_session_component.h b/base/src/core/include/rom_session_component.h index 859c675ab..3757ec14b 100644 --- a/base/src/core/include/rom_session_component.h +++ b/base/src/core/include/rom_session_component.h @@ -66,6 +66,7 @@ namespace Genode { ***************************/ Rom_dataspace_capability dataspace() { return _ds_cap; } + void sigh(Signal_context_capability) { } }; } diff --git a/gems/src/server/d3m/main.cc b/gems/src/server/d3m/main.cc index a5c6c1b4c..374044724 100644 --- a/gems/src/server/d3m/main.cc +++ b/gems/src/server/d3m/main.cc @@ -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 = ""; - Genode::strncpy(usb_config_ds.local_addr(), config, USB_CONFIG_MAX_LEN); - /* create USB driver */ + char const *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 */ diff --git a/os/include/init/child.h b/os/include/init/child.h index 23f6bdcb2..3ee786a8e 100644 --- a/os/include/init/child.h +++ b/os/include/init/child.h @@ -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, diff --git a/os/include/init/child_config.h b/os/include/init/child_config.h index 7a0a4b615..7f5c554fe 100644 --- a/os/include/init/child_config.h +++ b/os/include/init/child_config.h @@ -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); } }; } diff --git a/os/include/init/child_policy.h b/os/include/init/child_policy.h index 8b8917b3d..d37ac6624 100644 --- a/os/include/init/child_policy.h +++ b/os/include/init/child_policy.h @@ -123,6 +123,8 @@ namespace Init { Genode::Rom_dataspace_capability dataspace() { return Genode::static_cap_cast(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 { diff --git a/os/include/os/child_policy_dynamic_rom.h b/os/include/os/child_policy_dynamic_rom.h new file mode 100644 index 000000000..b98c60cc9 --- /dev/null +++ b/os/include/os/child_policy_dynamic_rom.h @@ -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 +#include +#include +#include + +namespace Genode { + + class Child_policy_dynamic_rom_file : public Rpc_object, + 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(), 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(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_ */ diff --git a/os/include/os/config.h b/os/include/os/config.h index 603c25174..b60da0ca3 100644 --- a/os/include/os/config.h +++ b/os/include/os/config.h @@ -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(); + } + } }; /** diff --git a/os/include/os/slave.h b/os/include/os/slave.h index 0616230dc..080ed3793 100644 --- a/os/include/os/slave.h +++ b/os/include/os/slave.h @@ -22,6 +22,7 @@ #include #include #include +#include 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 ** diff --git a/os/run/dynamic_config.run b/os/run/dynamic_config.run new file mode 100644 index 000000000..1786f00a8 --- /dev/null +++ b/os/run/dynamic_config.run @@ -0,0 +1,50 @@ +build "core init test/dynamic_config" + +create_boot_directory + +install_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" diff --git a/os/run/dynamic_config_slave.run b/os/run/dynamic_config_slave.run new file mode 100644 index 000000000..f2fcba330 --- /dev/null +++ b/os/run/dynamic_config_slave.run @@ -0,0 +1,38 @@ +build "core init test/dynamic_config" + +create_boot_directory + +install_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" diff --git a/os/src/server/iso9660/main.cc b/os/src/server/iso9660/main.cc index 3234910dd..909c3d05b 100644 --- a/os/src/server/iso9660/main.cc +++ b/os/src/server/iso9660/main.cc @@ -186,11 +186,12 @@ namespace Iso { File *_file; + public: + Rom_dataspace_capability dataspace() { return static_cap_cast(_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(); } diff --git a/os/src/server/loader/rom_session_component.h b/os/src/server/loader/rom_session_component.h index e6b8920d7..cf1ddf067 100644 --- a/os/src/server/loader/rom_session_component.h +++ b/os/src/server/loader/rom_session_component.h @@ -55,6 +55,8 @@ class Rom_session_component : public Genode::Rpc_object ***************************/ Genode::Rom_dataspace_capability dataspace() { return _ds_cap; } + + void sigh(Genode::Signal_context_capability) { } }; #endif /* _ROM_SESSION_COMPONENT_H_ */ diff --git a/os/src/server/rom_prefetcher/main.cc b/os/src/server/rom_prefetcher/main.cc index 7e336bd62..875ba4d1f 100644 --- a/os/src/server/rom_prefetcher/main.cc +++ b/os/src/server/rom_prefetcher/main.cc @@ -67,6 +67,8 @@ class Rom_session_component : public Genode::Rpc_object Genode::Rom_dataspace_capability dataspace() { return _rom.dataspace(); } + + void sigh(Genode::Signal_context_capability) { } }; class Rom_root : public Genode::Root_component diff --git a/os/src/server/tar_rom/main.cc b/os/src/server/tar_rom/main.cc index 034146a51..712c80947 100755 --- a/os/src/server/tar_rom/main.cc +++ b/os/src/server/tar_rom/main.cc @@ -156,6 +156,8 @@ class Rom_session_component : public Genode::Rpc_object Genode::Dataspace_capability ds = _file_ds; return Genode::static_cap_cast(ds); } + + void sigh(Genode::Signal_context_capability) { } }; diff --git a/os/src/test/dynamic_config/main.cc b/os/src/test/dynamic_config/main.cc new file mode 100644 index 000000000..5d0422ae5 --- /dev/null +++ b/os/src/test/dynamic_config/main.cc @@ -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 + + +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.context())->dispatch(); + } + return 0; +} diff --git a/os/src/test/dynamic_config/master/main.cc b/os/src/test/dynamic_config/master/main.cc new file mode 100644 index 000000000..fd031a011 --- /dev/null +++ b/os/src/test/dynamic_config/master/main.cc @@ -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 +#include +#include +#include + + +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("-1"); + + 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), + "%d", + counter++); + + slave_policy.configure(buf); + } + return 0; +} diff --git a/os/src/test/dynamic_config/master/target.mk b/os/src/test/dynamic_config/master/target.mk new file mode 100644 index 000000000..32f1efa66 --- /dev/null +++ b/os/src/test/dynamic_config/master/target.mk @@ -0,0 +1,3 @@ +TARGET = test-dynamic_config_master +SRC_CC = main.cc +LIBS = env signal server process diff --git a/os/src/test/dynamic_config/server/main.cc b/os/src/test/dynamic_config/server/main.cc new file mode 100644 index 000000000..dc48ea300 --- /dev/null +++ b/os/src/test/dynamic_config/server/main.cc @@ -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 +#include +#include +#include +#include +#include +#include + +/** + * Root interface that hands out a statically created session + */ +template +class Static_root : public Genode::Rpc_object > +{ + private: + + typedef Genode::Capability 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 +{ + 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(), 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(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_root(ep.manage(&rom_session)); + + rom_session.configure("-1"); + + /* 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), + "%d", + counter++); + + rom_session.configure(buf); + } + return 0; +}; diff --git a/os/src/test/dynamic_config/server/target.mk b/os/src/test/dynamic_config/server/target.mk new file mode 100644 index 000000000..9b18b9f3a --- /dev/null +++ b/os/src/test/dynamic_config/server/target.mk @@ -0,0 +1,3 @@ +TARGET = test-dynamic_config_server +SRC_CC = main.cc +LIBS = env signal server diff --git a/os/src/test/dynamic_config/target.mk b/os/src/test/dynamic_config/target.mk new file mode 100644 index 000000000..b1f183673 --- /dev/null +++ b/os/src/test/dynamic_config/target.mk @@ -0,0 +1,3 @@ +TARGET = test-dynamic_config +SRC_CC = main.cc +LIBS = env signal diff --git a/ports/src/app/gdb_monitor/rom.h b/ports/src/app/gdb_monitor/rom.h index 9400251d0..90c37029a 100644 --- a/ports/src/app/gdb_monitor/rom.h +++ b/ports/src/app/gdb_monitor/rom.h @@ -72,6 +72,10 @@ namespace Gdb_monitor { return static_cap_cast( static_cap_cast(_clone_cap)); } + + void release() { } + + void sigh(Genode::Signal_context_capability) { } };