From 363fd6065d6e1ce8ed104ca68ce5d323d7def0a1 Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Fri, 16 Jan 2015 21:43:20 +0100 Subject: [PATCH] Init: support for aliases for child names Fixes #1373 --- repos/os/src/init/main.cc | 272 ++++++++++++++++++++++++++++---------- 1 file changed, 201 insertions(+), 71 deletions(-) diff --git a/repos/os/src/init/main.cc b/repos/os/src/init/main.cc index 47d87f561..b2a229ed7 100644 --- a/repos/os/src/init/main.cc +++ b/repos/os/src/init/main.cc @@ -92,76 +92,188 @@ inline void determine_parent_services(Genode::Service_registry *services) ** Child registry ** ********************/ +namespace Init { struct Alias; } + + +/** + * Representation of an alias for a child + */ +struct Init::Alias : Genode::List::Element +{ + typedef Genode::String<128> Name; + typedef Genode::String<128> Child; + + Name name; + Child child; + + /** + * Exception types + */ + class Name_is_missing { }; + class Child_is_missing { }; + + /** + * Utility to read a string attribute from an XML node + * + * \param STR string type + * \param EXC exception type raised if attribute is not present + * + * \param node XML node + * \param attr_name name of attribute to read + */ + template + static STR _read_string_attr(Genode::Xml_node node, char const *attr_name) + { + char buf[STR::size()]; + + if (!node.has_attribute(attr_name)) + throw EXC(); + + node.attribute(attr_name).value(buf, sizeof(buf)); + + return STR(buf); + } + + /** + * Constructor + * + * \throw Name_is_missing + * \throw Child_is_missing + */ + Alias(Genode::Xml_node alias) + : + name (_read_string_attr (alias, "name")), + child(_read_string_attr(alias, "child")) + { } +}; + + namespace Init { typedef Genode::List > Child_list; - class Child_registry : public Name_registry, Child_list - { - public: - - /** - * Register child - */ - void insert(Child *child) - { - 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() - { - 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 ** - *****************************/ - - bool is_unique(const char *name) const - { - Genode::List_element const *curr = first(); - for (; curr; curr = curr->next()) - if (curr->object()->has_name(name)) - return false; - - return true; - } - - Genode::Server *lookup_server(const char *name) const - { - Genode::List_element const *curr = first(); - for (; curr; curr = curr->next()) - if (curr->object()->has_name(name)) - return curr->object()->server(); - - return 0; - } - }; + struct Child_registry; } +class Init::Child_registry : public Name_registry, Child_list +{ + private: + + List _aliases; + + public: + + /** + * Exception type + */ + class Alias_name_is_not_unique { }; + + /** + * Register child + */ + void insert(Child *child) + { + Child_list::insert(&child->_list_element); + } + + /** + * Unregister child + */ + void remove(Child *child) + { + Child_list::remove(&child->_list_element); + } + + /** + * Register alias + */ + void insert_alias(Alias *alias) + { + if (!is_unique(alias->name.string())) { + PERR("Alias name %s is not unique", alias->name.string()); + throw Alias_name_is_not_unique(); + } + _aliases.insert(alias); + } + + /** + * Unregister alias + */ + void remove_alias(Alias *alias) + { + _aliases.remove(alias); + } + + /** + * Start execution of all children + */ + 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; + } + + /** + * Return any of the registered aliases, or 0 if no alias exists + */ + Alias *any_alias() + { + return _aliases.first() ? _aliases.first() : 0; + } + + + /***************************** + ** Name-registry interface ** + *****************************/ + + bool is_unique(const char *name) const + { + /* check for name clash with an existing child */ + Genode::List_element const *curr = first(); + for (; curr; curr = curr->next()) + if (curr->object()->has_name(name)) + return false; + + /* check for name clash with an existing alias */ + for (Alias const *a = _aliases.first(); a; a = a->next()) { + if (Alias::Name(name) == a->name) + return false; + } + + return true; + } + + Genode::Server *lookup_server(const char *name) const + { + /* + * Check if an alias with the specified name exists. If so, + * look up the server referred to by the alias. + */ + for (Alias const *a = _aliases.first(); a; a = a->next()) + if (Alias::Name(name) == a->name) + name = a->child.string(); + + /* look up child with the name */ + Genode::List_element const *curr = first(); + for (; curr; curr = curr->next()) + if (curr->object()->has_name(name)) + return curr->object()->server(); + + return 0; + } +}; + + int main(int, char **) { using namespace Init; @@ -202,17 +314,29 @@ int main(int, char **) config()->xml_node().sub_node("default-route"); } catch (...) { } + /* create aliases */ + config()->xml_node().for_each_sub_node("alias", [&] (Xml_node alias_node) { + + try { + children.insert_alias(new (env()->heap()) Alias(alias_node)); + } + catch (Alias::Name_is_missing) { + PWRN("Missing 'name' attribute in '' entry\n"); } + catch (Alias::Child_is_missing) { + PWRN("Missing 'child' attribute in '' entry\n"); } + + }); + /* create children */ try { - Xml_node start_node = config()->xml_node().sub_node("start"); - for (;; start_node = start_node.next("start")) { + config()->xml_node().for_each_sub_node("start", [&] (Xml_node start_node) { try { children.insert(new (env()->heap()) Init::Child(start_node, default_route_node, - &children, read_prio_levels_log2(), - read_affinity_space(), - &parent_services, &child_services, &cap)); + &children, read_prio_levels_log2(), + read_affinity_space(), + &parent_services, &child_services, &cap)); } catch (Rom_connection::Rom_connection_failed) { /* @@ -220,9 +344,7 @@ int main(int, char **) * by the Rom_connection constructor. */ } - - if (start_node.is_last("start")) break; - } + }); /* start children */ children.start(); @@ -232,6 +354,7 @@ int main(int, char **) catch (Xml_node::Invalid_syntax) { PERR("No children to start"); } catch (Init::Child::Child_name_is_not_unique) { } + catch (Init::Child_registry::Alias_name_is_not_unique) { } /* * Respond to config changes at runtime @@ -250,6 +373,13 @@ int main(int, char **) destroy(env()->heap(), child); } + /* remove all known aliases */ + while (children.any_alias()) { + Init::Alias *alias = children.any_alias(); + children.remove_alias(alias); + destroy(env()->heap(), alias); + } + /* reset knowledge about parent services */ parent_services.remove_all();