From 7d9f68493ac324baf055248983f5a4e478a94ef6 Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Sun, 19 Feb 2017 21:40:52 +0100 Subject: [PATCH] base: support for multi-staged child startup This patch enhances the 'Child' and 'Child_policy' with the ability to separate the different steps of bootstrapping children. If the 'Child_policy::initiate_env_sessions()' returns false, the child's environment sessions remain unrouted at construction time. This way, child objects for many children can be initialized to a state that allows the children to represent services for other children. Therefore, session routing can be applied before any child executes. At this stage, the environment RAM sessions of all children can be created. Note that this step still has the limitation that RAM sessions are generally expected to be provided by either the parent or a local service. Once all children are equipped with RAM, they can in principle receive session-quota donations. Hence, all other environment sessions can now be arbitrarily routed and initiated. Once the environment of a child is complete, the child's process and initial thread is created. --- repos/base/include/base/child.h | 65 +++++++++++++++++++++++++------ repos/base/include/base/service.h | 5 +-- repos/base/lib/symbols/ld | 2 + repos/base/src/lib/base/child.cc | 38 +++++++++++++----- 4 files changed, 85 insertions(+), 25 deletions(-) diff --git a/repos/base/include/base/child.h b/repos/base/include/base/child.h index b6dab9deb1..c445a5ff6d 100644 --- a/repos/base/include/base/child.h +++ b/repos/base/include/base/child.h @@ -200,6 +200,16 @@ struct Genode::Child_policy */ virtual size_t session_alloc_batch_size() const { return 16; } + /** + * Return true to create the environment sessions at child construction + * + * By returning 'false', it is possible to create 'Child' objects without + * routing of their environment sessions at construction time. Once the + * routing information is available, the child's environment sessions + * must be manually initiated by calling 'Child::initiate_env_sessions()'. + */ + virtual bool initiate_env_sessions() const { return true; } + /** * Return region map for the child's address space * @@ -413,12 +423,14 @@ class Genode::Child : protected Rpc_object, template struct Env_connection { + Child &_child; + + Id_space::Id const _client_id; + typedef String<64> Label; Args const _args; - Child_policy::Route _route; - /* * The 'Env_service' monitors session responses in order to attempt * to 'Child::_try_construct_env_dependent_members()' on the @@ -456,10 +468,11 @@ class Genode::Child : protected Rpc_object, } void wakeup() override { _service.wakeup(); } + }; - } _env_service; + Constructible _env_service; - Local_connection _connection; + Constructible > _connection; /** * Construct session arguments with the child policy applied @@ -485,18 +498,34 @@ class Genode::Child : protected Rpc_object, Env_connection(Child &child, Id_space::Id id, Label const &label = Label()) : - _args(_construct_args(child._policy, label)), - _route(child._resolve_session_request(child._policy, _service_name(), - _args.string())), - _env_service(child, _route.service), - _connection(_env_service, child._id_space, id, _args, - child._policy.filter_session_affinity(Affinity())) + _child(child), _client_id(id), + _args(_construct_args(child._policy, label)) { } + /** + * Initiate routing and creation of the environment session + */ + void initiate() + { + /* don't attempt to initiate env session twice */ + if (_connection.constructed()) + return; + + Child_policy::Route const route = + _child._resolve_session_request(_child._policy, + _service_name(), + _args.string()); + + _env_service.construct(_child, route.service); + _connection.construct(*_env_service, _child._id_space, _client_id, + _args, _child._policy.filter_session_affinity(Affinity())); + } + typedef typename CONNECTION::Session_type SESSION; - SESSION &session() { return _connection.session(); } - Capability cap() const { return _connection.cap(); } + SESSION &session() { return _connection->session(); } + + Capability cap() const { return _connection->cap(); } }; Env_connection _ram { *this, Env::ram(), _policy.name() }; @@ -569,6 +598,18 @@ class Genode::Child : protected Rpc_object, */ bool active() const { return _process.constructed(); } + /** + * Initialize the child's RAM session + */ + void initiate_env_ram_session(); + + /** + * Trigger the routing and creation of the child's environment session + * + * See the description of 'Child_policy::initiate_env_sessions'. + */ + void initiate_env_sessions(); + /** * RAM quota unconditionally consumed by the child's environment */ diff --git a/repos/base/include/base/service.h b/repos/base/include/base/service.h index 200df961ae..b9e8adfa7a 100644 --- a/repos/base/include/base/service.h +++ b/repos/base/include/base/service.h @@ -108,10 +108,7 @@ class Genode::Service : Noncopyable /** * Return the RAM session to be used for trading resources */ - Ram_session_capability ram() const - { - return _ram; - } + virtual Ram_session_capability ram() const { return _ram; } }; diff --git a/repos/base/lib/symbols/ld b/repos/base/lib/symbols/ld index 420cd84430..29c11b2d8c 100644 --- a/repos/base/lib/symbols/ld +++ b/repos/base/lib/symbols/ld @@ -230,6 +230,8 @@ _ZN6Genode5Child16resource_requestERKNS_6StringILm160EEE T _ZN6Genode5Child16session_responseENS_8Id_spaceINS_6Parent6ServerEE2IdENS2_16Session_responseE T _ZN6Genode5Child19deliver_session_capENS_8Id_spaceINS_6Parent6ServerEE2IdENS_10CapabilityINS_7SessionEEE T _ZN6Genode5Child19resource_avail_sighENS_10CapabilityINS_14Signal_contextEEE T +_ZN6Genode5Child21initiate_env_sessionsEv T +_ZN6Genode5Child24initiate_env_ram_sessionEv T _ZN6Genode5Child4exitEi T _ZN6Genode5Child5closeENS_8Id_spaceINS_6Parent6ClientEE2IdE T _ZN6Genode5Child5yieldERKNS_6StringILm160EEE T diff --git a/repos/base/src/lib/base/child.cc b/repos/base/src/lib/base/child.cc index d9351af9c0..5fc0a83f46 100644 --- a/repos/base/src/lib/base/child.cc +++ b/repos/base/src/lib/base/child.cc @@ -712,6 +712,31 @@ void Child::_discard_env_session(Id_space::Id id) } +void Child::initiate_env_ram_session() { _ram.initiate(); } + + +void Child::initiate_env_sessions() +{ + _pd .initiate(); + _cpu .initiate(); + _log .initiate(); + _binary.initiate(); + + /* + * Issue environment-session request for obtaining the linker binary. We + * accept this request to fail. In this case, the child creation may still + * succeed if the binary is statically linked. + */ + try { + _linker.construct(*this, Parent::Env::linker(), _policy.linker_name()); + _linker->initiate(); + } + catch (Parent::Service_denied) { } + + _try_construct_env_dependent_members(); +} + + Child::Child(Region_map &local_rm, Rpc_entrypoint &entrypoint, Child_policy &policy) @@ -719,15 +744,10 @@ Child::Child(Region_map &local_rm, _policy(policy), _local_rm(local_rm), _entrypoint(entrypoint), _parent_cap(_entrypoint.manage(this)) { - /* - * Issue environment-session request for obtaining the linker binary. We - * accept this request to fail. In this case, the child creation may still - * succeed if the binary is statically linked. - */ - try { _linker.construct(*this, Parent::Env::linker(), _policy.linker_name()); } - catch (Parent::Service_denied) { } - - _try_construct_env_dependent_members(); + if (_policy.initiate_env_sessions()) { + initiate_env_ram_session(); + initiate_env_sessions(); + } }