diff --git a/os/include/init/child.h b/os/include/init/child.h index 36e6c99299..05321e25ac 100644 --- a/os/include/init/child.h +++ b/os/include/init/child.h @@ -295,6 +295,13 @@ namespace Init { class Child : Genode::Child_policy { + public: + + /** + * Exception type + */ + class Child_name_is_not_unique { }; + private: friend class Child_registry; @@ -334,7 +341,6 @@ namespace Init { /* check for a name confict with the other children */ if (!registry->is_unique(unique)) { PERR("Child name \"%s\" is not unique", unique); - class Child_name_is_not_unique { }; throw Child_name_is_not_unique(); } diff --git a/os/run/ldso.run b/os/run/ldso.run index 472137ea9c..6dbf4b38ff 100644 --- a/os/run/ldso.run +++ b/os/run/ldso.run @@ -29,7 +29,7 @@ append qemu_args "-nographic -m 64" run_genode_until "child exited with exit value 0.*\n" 10 # pay only attention to the output of init and its children -grep_output {^\[init} +grep_output {^\[init } unify_output {environ: [a-f0-9]+} "environ: " @@ -54,6 +54,5 @@ compare_output_to { [init -> test-ldso] Libc test: abs(-10): 10 [init -> test-ldso] ================ [init -> test-ldso] - [init] virtual void Genode::Child_policy::exit(int): child exited with exit value 0 } diff --git a/os/run/tar_rom.run b/os/run/tar_rom.run index 795ad87b9c..c2543f707a 100644 --- a/os/run/tar_rom.run +++ b/os/run/tar_rom.run @@ -35,6 +35,7 @@ install_config { + diff --git a/os/src/init/main.cc b/os/src/init/main.cc index 80686039da..d780379c6c 100644 --- a/os/src/init/main.cc +++ b/os/src/init/main.cc @@ -89,15 +89,32 @@ namespace Init { Child_list::insert(&child->_list_element); } + /** + * Unregister child + */ + void remove(Child *child) + { + Child_list::remove(&child->_list_element); + } + /** * Start execution of all children */ - void start() { + void start() + { Genode::List_element *curr = first(); for (; curr; curr = curr->next()) curr->object()->start(); } + /** + * Return any of the registered children, or 0 if no child exists + */ + Child *any() + { + return first() ? first()->object() : 0; + } + /***************************** ** Name-registry interface ** @@ -129,54 +146,97 @@ namespace Init { int main(int, char **) { using namespace Init; - - try { - config_verbose = - Genode::config()->xml_node().attribute("verbose").has_value("yes"); } - catch (...) { } + using namespace Genode; /* look for dynamic linker */ try { - static Genode::Rom_connection rom("ld.lib.so"); - Genode::Process::dynamic_linker(rom.dataspace()); + static Rom_connection rom("ld.lib.so"); + Process::dynamic_linker(rom.dataspace()); } catch (...) { } - static Genode::Service_registry parent_services; - static Genode::Service_registry child_services; - static Child_registry children; - static Genode::Cap_connection cap; + static Service_registry parent_services; + static Service_registry child_services; + static Child_registry children; + static Cap_connection cap; - try { determine_parent_services(&parent_services); } - catch (...) { } + /* + * Signal receiver for config changes + */ + Signal_receiver sig_rec; + Signal_context sig_ctx; + config()->sigh(sig_rec.manage(&sig_ctx)); - /* determine default route for resolving service requests */ - Genode::Xml_node default_route_node(""); - try { - default_route_node = - Genode::config()->xml_node().sub_node("default-route"); } - catch (...) { } + for (;;) { - /* create children */ - try { - Genode::Xml_node start_node = Genode::config()->xml_node().sub_node("start"); - for (;; start_node = start_node.next("start")) { + try { + config_verbose = + config()->xml_node().attribute("verbose").has_value("yes"); } + catch (...) { } - children.insert(new (Genode::env()->heap()) - Child(start_node, default_route_node, &children, - read_prio_levels_log2(), - &parent_services, &child_services, &cap)); + try { determine_parent_services(&parent_services); } + catch (...) { } - if (start_node.is_last("start")) break; + /* determine default route for resolving service requests */ + Xml_node default_route_node(""); + try { + default_route_node = + config()->xml_node().sub_node("default-route"); } + catch (...) { } + + /* create children */ + try { + Xml_node start_node = config()->xml_node().sub_node("start"); + for (;; start_node = start_node.next("start")) { + + try { + children.insert(new (env()->heap()) + Init::Child(start_node, default_route_node, + &children, read_prio_levels_log2(), + &parent_services, &child_services, &cap)); + } + catch (Rom_connection::Rom_connection_failed) { + /* + * The binary does not exist. An error message is printed + * by the Rom_connection constructor. + */ + } + + if (start_node.is_last("start")) break; + } + + /* start children */ + children.start(); } - } - catch (Genode::Xml_node::Nonexistent_sub_node) { - PERR("No children to start"); + catch (Xml_node::Nonexistent_sub_node) { + PERR("No children to start"); } + catch (Config::Invalid) { + PERR("No valid config found"); } + catch (Init::Child::Child_name_is_not_unique) { } + + /* + * Respond to config changes at runtime + * + * If the config gets updated to a new version, we kill the current + * scenario and start again with the new config. + */ + + /* wait for config change */ + sig_rec.wait_for_signal(); + + /* kill all currently running children */ + while (children.any()) { + Init::Child *child = children.any(); + children.remove(child); + destroy(env()->heap(), child); + } + + /* reset knowledge about parent services */ + parent_services.remove_all(); + + /* reload config */ + config()->reload(); } - /* start children */ - children.start(); - - Genode::sleep_forever(); return 0; } diff --git a/os/src/init/target.mk b/os/src/init/target.mk index aabae562c4..5c92ec3494 100644 --- a/os/src/init/target.mk +++ b/os/src/init/target.mk @@ -1,3 +1,3 @@ TARGET = init SRC_CC = main.cc -LIBS = env cxx server child init_pd_args +LIBS = env cxx server child init_pd_args signal