diff --git a/repos/base/include/base/child.h b/repos/base/include/base/child.h index 3f680c86e..ffab7cc50 100644 --- a/repos/base/include/base/child.h +++ b/repos/base/include/base/child.h @@ -447,6 +447,15 @@ class Genode::Child : protected Rpc_object, _child(child), _service(service) { } + /* + * The 'Local_connection' may call 'initial_request' multiple + * times. We use 'initial_request' as a hook to transfer the + * session quota to an async service but we want to transfer + * the session quota only once. The '_first_request' allows + * us to distinguish the first from subsequent calls. + */ + bool _first_request = true; + void initiate_request(Session_state &session) override { session.ready_callback = this; @@ -454,6 +463,23 @@ class Genode::Child : protected Rpc_object, _service.initiate_request(session); + /* + * If the env session is provided by an async service, + * transfer the session resources. + */ + bool const async_service = + session.phase == Session_state::CREATE_REQUESTED; + + if (_first_request && async_service + && _service.name() != Pd_session::service_name()) { + + Ram_quota const ram_quota { CONNECTION::RAM_QUOTA }; + Cap_quota const cap_quota { CONNECTION::CAP_QUOTA }; + _child._policy.ref_pd().transfer_quota(cap(ram_quota), ram_quota); + _child._policy.ref_pd().transfer_quota(cap(cap_quota), cap_quota); + _first_request = false; + } + if (session.phase == Session_state::SERVICE_DENIED) error(_child._policy.name(), ": environment ", CONNECTION::service_name(), " session denied " @@ -585,7 +611,7 @@ class Genode::Child : protected Rpc_object, return _connection.constructed() ? _connection->cap() : Capability(); } - bool alive() const { return _connection.constructed() && _connection->alive(); } + bool closed() const { return !_connection.constructed() || _connection->closed(); } void close() { if (_connection.constructed()) _connection->close(); } }; @@ -689,9 +715,14 @@ class Genode::Child : protected Rpc_object, */ bool env_sessions_closed() const { - if (_linker.constructed() && _linker->alive()) return false; + if (_linker.constructed() && !_linker->closed()) return false; - return !_cpu.alive() && !_log.alive() && !_binary.alive(); + /* + * Note that the state of the CPU session remains unchecked here + * because the eager CPU-session destruction does not work on all + * kernels (search for KERNEL_SUPPORTS_EAGER_CHILD_DESTRUCTION). + */ + return _log.closed() && _binary.closed(); } /** diff --git a/repos/base/include/base/local_connection.h b/repos/base/include/base/local_connection.h index 335d5f236..0a255a951 100644 --- a/repos/base/include/base/local_connection.h +++ b/repos/base/include/base/local_connection.h @@ -175,7 +175,8 @@ class Genode::Local_connection : Local_connection_base service.wakeup(); } - bool alive() const { return _session_state->alive(); } + bool alive() const { return _session_state->alive(); } + bool closed() const { return _session_state->closed(); } using Local_connection_base::close; }; diff --git a/repos/base/include/base/session_state.h b/repos/base/include/base/session_state.h index 6edde1935..fd8e36cf4 100644 --- a/repos/base/include/base/session_state.h +++ b/repos/base/include/base/session_state.h @@ -211,6 +211,26 @@ class Genode::Session_state : public Parent::Client, public Parent::Server return false; } + bool closed() const + { + switch (phase) { + + case SERVICE_DENIED: + case INSUFFICIENT_RAM_QUOTA: + case INSUFFICIENT_CAP_QUOTA: + case CLOSED: + return true; + + case CREATE_REQUESTED: + case AVAILABLE: + case CAP_HANDED_OUT: + case UPGRADE_REQUESTED: + case CLOSE_REQUESTED: + return false; + } + return false; + } + /** * Return client-side label of the session request */