Init: handle reconfiguration

With this change, init becomes able to respond to config changes by
restarting the scenario with the new config. To make this feature useful
in practice, init must not fail under any circumstances. Even on
conditions that were considered as fatal previously and led to the abort
of init (such as ambiguous names of the children or misconfiguration in
general), init must stay alive and responsive to config changes.
This commit is contained in:
Norman Feske 2013-01-14 12:13:05 +01:00
parent fe734272bc
commit fcca4f3466
5 changed files with 106 additions and 40 deletions

View File

@ -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();
}

View File

@ -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: <unified>"
@ -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
}

View File

@ -35,6 +35,7 @@ install_config {
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
<service name="SIGNAL"/>
</parent-provides>
<default-route>
<any-service> <parent/> <any-child/> </any-service>

View File

@ -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<Child> *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("<empty/>");
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("<empty/>");
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;
}

View File

@ -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