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.
This commit is contained in:
Norman Feske 2017-02-19 21:40:52 +01:00 committed by Christian Helmuth
parent 9cba459958
commit 7d9f68493a
4 changed files with 85 additions and 25 deletions

View File

@ -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<Parent>,
template <typename CONNECTION>
struct Env_connection
{
Child &_child;
Id_space<Parent::Client>::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<Parent>,
}
void wakeup() override { _service.wakeup(); }
};
} _env_service;
Constructible<Env_service> _env_service;
Local_connection<CONNECTION> _connection;
Constructible<Local_connection<CONNECTION> > _connection;
/**
* Construct session arguments with the child policy applied
@ -485,18 +498,34 @@ class Genode::Child : protected Rpc_object<Parent>,
Env_connection(Child &child, Id_space<Parent::Client>::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<SESSION> cap() const { return _connection.cap(); }
SESSION &session() { return _connection->session(); }
Capability<SESSION> cap() const { return _connection->cap(); }
};
Env_connection<Ram_connection> _ram { *this, Env::ram(), _policy.name() };
@ -569,6 +598,18 @@ class Genode::Child : protected Rpc_object<Parent>,
*/
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
*/

View File

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

View File

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

View File

@ -712,6 +712,31 @@ void Child::_discard_env_session(Id_space<Parent::Client>::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();
}
}