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) { } };