base: fix quota transfer to async env services

Whenever an environment session was provided by an asynchronous service,
e.g., the depot_rom of the sculpt scenario, the session quota was not
transferred to the server at session-creation time. This resulted in a
slow depletion of the server's quota over time. This patch ensures that
the delivery of session quota is consistent with the information
reported to the server as session argument.
This commit is contained in:
Norman Feske 2018-06-07 17:24:00 +02:00 committed by Christian Helmuth
parent 578bec11ac
commit 81613afa03
3 changed files with 56 additions and 4 deletions

View File

@ -447,6 +447,15 @@ class Genode::Child : protected Rpc_object<Parent>,
_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<Parent>,
_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<Parent>,
return _connection.constructed() ? _connection->cap()
: Capability<SESSION>(); }
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<Parent>,
*/
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();
}
/**

View File

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

View File

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