mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-18 10:46:25 +00:00
base: introduce Env::try_session
The new 'Env::try_session' method mirrors the existing 'Env::session' without implicitly handling exceptions of the types 'Out_of_ram', 'Out_of_caps', 'Insufficient_ram_quota', and 'Insufficient_cap_quota'. It enables runtime environments like init to reflect those exceptions to their children instead of paying the costs of implicit session-quota upgrades out of the own pocket. By changing the 'Parent_service' to use 'try_session', this patch fixes a resource-exhaustion problem of init in Sculpt OS that occurred when the GPU multiplexer created a large batch of IO_MEM sessions, with each session requiring a second attempt with the session quota upgraded by 4 KiB. Issue #3767
This commit is contained in:
parent
d5d7915b4d
commit
6f1d3862cd
@ -68,6 +68,16 @@ struct Genode::Env : Interface
|
||||
*/
|
||||
virtual Id_space<Parent::Client> &id_space() = 0;
|
||||
|
||||
/**
|
||||
* Create session with quota upgrades as needed
|
||||
*
|
||||
* \throw Service_denied
|
||||
*
|
||||
* In contrast to 'try_session', this method implicitly handles
|
||||
* 'Insufficient_ram_quota' and 'Insufficient_cap_quota' by successively
|
||||
* increasing the session quota. On the occurrence of an 'Out_of_ram'
|
||||
* or 'Out_of_caps' exception, a resource request is issued to the parent.
|
||||
*/
|
||||
virtual Session_capability session(Parent::Service_name const &,
|
||||
Parent::Client::Id,
|
||||
Parent::Session_args const &,
|
||||
@ -82,10 +92,6 @@ struct Genode::Env : Interface
|
||||
* \param affinity preferred CPU affinity for the session
|
||||
*
|
||||
* \throw Service_denied
|
||||
* \throw Insufficient_cap_quota
|
||||
* \throw Insufficient_ram_quota
|
||||
* \throw Out_of_caps
|
||||
* \throw Out_of_ram
|
||||
*
|
||||
* See the documentation of 'Parent::session'.
|
||||
*
|
||||
@ -161,6 +167,20 @@ struct Genode::Env : Interface
|
||||
* \noapi
|
||||
*/
|
||||
virtual void reinit_main_thread(Capability<Region_map> &stack_area_rm) = 0;
|
||||
|
||||
/**
|
||||
* Attempt the creation of a session
|
||||
*
|
||||
* \throw Service_denied
|
||||
* \throw Insufficient_cap_quota
|
||||
* \throw Insufficient_ram_quota
|
||||
* \throw Out_of_caps
|
||||
* \throw Out_of_ram
|
||||
*/
|
||||
virtual Session_capability try_session(Parent::Service_name const &,
|
||||
Parent::Client::Id,
|
||||
Parent::Session_args const &,
|
||||
Affinity const &) = 0;
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__BASE__ENV_H_ */
|
||||
|
@ -27,6 +27,7 @@ namespace Genode {
|
||||
class Service;
|
||||
template <typename> class Session_factory;
|
||||
template <typename> class Local_service;
|
||||
class Try_parent_service;
|
||||
class Parent_service;
|
||||
class Async_service;
|
||||
class Child_service;
|
||||
@ -230,9 +231,14 @@ class Genode::Local_service : public Service
|
||||
|
||||
|
||||
/**
|
||||
* Representation of a service provided by our parent
|
||||
* Representation of a strictly accounted service provided by our parent
|
||||
*
|
||||
* The 'Try_parent_service' reflects the local depletion of RAM or cap quotas
|
||||
* during 'initiate_request' via 'Out_of_ram' or 'Out_of_caps' exceptions.
|
||||
* This is appropriate in situations that demand strict accounting of resource
|
||||
* use per child, e.g., child components hosted by the init component.
|
||||
*/
|
||||
class Genode::Parent_service : public Service
|
||||
class Genode::Try_parent_service : public Service
|
||||
{
|
||||
private:
|
||||
|
||||
@ -240,12 +246,13 @@ class Genode::Parent_service : public Service
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Parent_service(Env &env, Service::Name const &name)
|
||||
Try_parent_service(Env &env, Service::Name const &name)
|
||||
: Service(name), _env(env) { }
|
||||
|
||||
/*
|
||||
* \throw Out_of_ram
|
||||
* \throw Out_of_caps
|
||||
*/
|
||||
void initiate_request(Session_state &session) override
|
||||
{
|
||||
switch (session.phase) {
|
||||
@ -256,32 +263,35 @@ class Genode::Parent_service : public Service
|
||||
_env.id_space());
|
||||
try {
|
||||
|
||||
session.cap = _env.session(name().string(),
|
||||
session.id_at_parent->id(),
|
||||
Session_state::Server_args(session).string(),
|
||||
session.affinity());
|
||||
session.cap = _env.try_session(name().string(),
|
||||
session.id_at_parent->id(),
|
||||
Session_state::Server_args(session).string(),
|
||||
session.affinity());
|
||||
|
||||
session.phase = Session_state::AVAILABLE;
|
||||
}
|
||||
catch (Out_of_ram) {
|
||||
session.id_at_parent.destruct();
|
||||
session.phase = Session_state::SERVICE_DENIED; }
|
||||
|
||||
session.phase = Session_state::CLOSED;
|
||||
throw;
|
||||
}
|
||||
catch (Out_of_caps) {
|
||||
session.id_at_parent.destruct();
|
||||
session.phase = Session_state::SERVICE_DENIED; }
|
||||
|
||||
session.phase = Session_state::CLOSED;
|
||||
throw;
|
||||
}
|
||||
catch (Insufficient_ram_quota) {
|
||||
session.id_at_parent.destruct();
|
||||
session.phase = Session_state::INSUFFICIENT_RAM_QUOTA; }
|
||||
|
||||
session.phase = Session_state::INSUFFICIENT_RAM_QUOTA;
|
||||
}
|
||||
catch (Insufficient_cap_quota) {
|
||||
session.id_at_parent.destruct();
|
||||
session.phase = Session_state::INSUFFICIENT_CAP_QUOTA; }
|
||||
|
||||
session.phase = Session_state::INSUFFICIENT_CAP_QUOTA;
|
||||
}
|
||||
catch (Service_denied) {
|
||||
session.id_at_parent.destruct();
|
||||
session.phase = Session_state::SERVICE_DENIED; }
|
||||
session.phase = Session_state::SERVICE_DENIED;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
@ -326,6 +336,50 @@ class Genode::Parent_service : public Service
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Representation of a service provided by our parent
|
||||
*
|
||||
* In contrast to 'Try_parent_service', the 'Parent_service' handles the
|
||||
* exhaution of the local RAM or cap quotas by issuing resource requests.
|
||||
* This is useful in situations where the parent is unconditionally willing
|
||||
* to satisfy the resource needs of its children.
|
||||
*/
|
||||
class Genode::Parent_service : public Try_parent_service
|
||||
{
|
||||
private:
|
||||
|
||||
Env &_env;
|
||||
|
||||
public:
|
||||
|
||||
Parent_service(Env &env, Service::Name const &name)
|
||||
: Try_parent_service(env, name), _env(env) { }
|
||||
|
||||
void initiate_request(Session_state &session) override
|
||||
{
|
||||
for (unsigned i = 0; i < 10; i++) {
|
||||
|
||||
try {
|
||||
Try_parent_service::initiate_request(session);
|
||||
return;
|
||||
}
|
||||
catch (Out_of_ram) {
|
||||
Ram_quota ram_quota { ram_quota_from_args(session.args().string()) };
|
||||
Parent::Resource_args args(String<64>("ram_quota=", ram_quota));
|
||||
_env.parent().resource_request(args);
|
||||
}
|
||||
catch (Out_of_caps) {
|
||||
Cap_quota cap_quota { cap_quota_from_args(session.args().string()) };
|
||||
Parent::Resource_args args(String<64>("cap_quota=", cap_quota));
|
||||
_env.parent().resource_request(args);
|
||||
}
|
||||
}
|
||||
|
||||
error("parent-session request repeatedly failed");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Representation of a service that asynchronously responds to session request
|
||||
*/
|
||||
|
@ -116,10 +116,10 @@ namespace {
|
||||
_session_blockade->block();
|
||||
}
|
||||
|
||||
Session_capability session(Parent::Service_name const &name,
|
||||
Parent::Client::Id id,
|
||||
Parent::Session_args const &args,
|
||||
Affinity const &affinity) override
|
||||
Session_capability try_session(Parent::Service_name const &name,
|
||||
Parent::Client::Id id,
|
||||
Parent::Session_args const &args,
|
||||
Affinity const &affinity) override
|
||||
{
|
||||
if (!args.valid_string()) {
|
||||
warning(name.string(), " session denied because of truncated arguments");
|
||||
@ -128,6 +128,20 @@ namespace {
|
||||
|
||||
Mutex::Guard guard(_mutex);
|
||||
|
||||
Session_capability cap = _parent.session(id, name, args, affinity);
|
||||
|
||||
if (cap.valid())
|
||||
return cap;
|
||||
|
||||
_block_for_session();
|
||||
return _parent.session_cap(id);
|
||||
}
|
||||
|
||||
Session_capability session(Parent::Service_name const &name,
|
||||
Parent::Client::Id id,
|
||||
Parent::Session_args const &args,
|
||||
Affinity const &affinity) override
|
||||
{
|
||||
/*
|
||||
* Since we account for the backing store for session meta data on
|
||||
* the route between client and server, the session quota provided
|
||||
@ -154,14 +168,7 @@ namespace {
|
||||
Arg_string::set_arg(argbuf, sizeof(argbuf), "cap_quota",
|
||||
String<32>(cap_quota).string());
|
||||
|
||||
Session_capability cap =
|
||||
_parent.session(id, name, Parent::Session_args(argbuf), affinity);
|
||||
|
||||
if (cap.valid())
|
||||
return cap;
|
||||
|
||||
_block_for_session();
|
||||
return _parent.session_cap(id);
|
||||
return try_session(name, id, Parent::Session_args(argbuf), affinity);
|
||||
}
|
||||
|
||||
catch (Insufficient_ram_quota) {
|
||||
|
@ -54,10 +54,22 @@ struct Qt_launchpad_namespace::Local_env : Genode::Env
|
||||
Parent::Client::Id id,
|
||||
Parent::Session_args const &session_args,
|
||||
Affinity const &affinity) override
|
||||
{ return genode_env.session(service_name, id, session_args, affinity); }
|
||||
{
|
||||
return genode_env.session(service_name, id, session_args, affinity);
|
||||
}
|
||||
|
||||
Session_capability try_session(Parent::Service_name const &service_name,
|
||||
Parent::Client::Id id,
|
||||
Parent::Session_args const &session_args,
|
||||
Affinity const &affinity) override
|
||||
{
|
||||
return genode_env.try_session(service_name, id, session_args, affinity);
|
||||
}
|
||||
|
||||
void upgrade(Parent::Client::Id id, Parent::Upgrade_args const &args) override
|
||||
{ return genode_env.upgrade(id, args); }
|
||||
{
|
||||
return genode_env.upgrade(id, args);
|
||||
}
|
||||
|
||||
void close(Parent::Client::Id id) override { return genode_env.close(id); }
|
||||
|
||||
@ -72,6 +84,7 @@ struct Qt_launchpad_namespace::Local_env : Genode::Env
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void Libc::Component::construct(Libc::Env &env)
|
||||
{
|
||||
Libc::with_libc([&] {
|
||||
|
@ -114,6 +114,12 @@ class Libc::Env_implementation : public Libc::Env, public Config_accessor
|
||||
Affinity const &aff) override {
|
||||
return _env.session(name, id, args, aff); }
|
||||
|
||||
Session_capability try_session(Parent::Service_name const &name,
|
||||
Parent::Client::Id id,
|
||||
Parent::Session_args const &args,
|
||||
Affinity const &aff) override {
|
||||
return _env.try_session(name, id, args, aff); }
|
||||
|
||||
void upgrade(Parent::Client::Id id,
|
||||
Parent::Upgrade_args const &args) override {
|
||||
return _env.upgrade(id, args); }
|
||||
|
@ -40,7 +40,7 @@ class Sandbox::Abandonable : Interface
|
||||
};
|
||||
|
||||
|
||||
class Sandbox::Parent_service : public Genode::Parent_service, public Abandonable
|
||||
class Sandbox::Parent_service : public Genode::Try_parent_service, public Abandonable
|
||||
{
|
||||
private:
|
||||
|
||||
@ -51,7 +51,7 @@ class Sandbox::Parent_service : public Genode::Parent_service, public Abandonabl
|
||||
Parent_service(Registry<Parent_service> ®istry, Env &env,
|
||||
Service::Name const &name)
|
||||
:
|
||||
Genode::Parent_service(env, name), _reg_elem(registry, *this)
|
||||
Genode::Try_parent_service(env, name), _reg_elem(registry, *this)
|
||||
{ }
|
||||
};
|
||||
|
||||
|
@ -78,10 +78,22 @@ class Gdb_monitor::App_child : public Child_policy,
|
||||
Parent::Client::Id id,
|
||||
Parent::Session_args const &session_args,
|
||||
Affinity const &affinity) override
|
||||
{ return genode_env.session(service_name, id, session_args, affinity); }
|
||||
{
|
||||
return genode_env.session(service_name, id, session_args, affinity);
|
||||
}
|
||||
|
||||
Session_capability try_session(Parent::Service_name const &service_name,
|
||||
Parent::Client::Id id,
|
||||
Parent::Session_args const &session_args,
|
||||
Affinity const &affinity) override
|
||||
{
|
||||
return genode_env.session(service_name, id, session_args, affinity);
|
||||
}
|
||||
|
||||
void upgrade(Parent::Client::Id id, Parent::Upgrade_args const &args) override
|
||||
{ return genode_env.upgrade(id, args); }
|
||||
{
|
||||
return genode_env.upgrade(id, args);
|
||||
}
|
||||
|
||||
void close(Parent::Client::Id id) override { return genode_env.close(id); }
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user