mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-18 18:56:29 +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;
|
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 &,
|
virtual Session_capability session(Parent::Service_name const &,
|
||||||
Parent::Client::Id,
|
Parent::Client::Id,
|
||||||
Parent::Session_args const &,
|
Parent::Session_args const &,
|
||||||
@ -82,10 +92,6 @@ struct Genode::Env : Interface
|
|||||||
* \param affinity preferred CPU affinity for the session
|
* \param affinity preferred CPU affinity for the session
|
||||||
*
|
*
|
||||||
* \throw Service_denied
|
* \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'.
|
* See the documentation of 'Parent::session'.
|
||||||
*
|
*
|
||||||
@ -161,6 +167,20 @@ struct Genode::Env : Interface
|
|||||||
* \noapi
|
* \noapi
|
||||||
*/
|
*/
|
||||||
virtual void reinit_main_thread(Capability<Region_map> &stack_area_rm) = 0;
|
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_ */
|
#endif /* _INCLUDE__BASE__ENV_H_ */
|
||||||
|
@ -27,6 +27,7 @@ namespace Genode {
|
|||||||
class Service;
|
class Service;
|
||||||
template <typename> class Session_factory;
|
template <typename> class Session_factory;
|
||||||
template <typename> class Local_service;
|
template <typename> class Local_service;
|
||||||
|
class Try_parent_service;
|
||||||
class Parent_service;
|
class Parent_service;
|
||||||
class Async_service;
|
class Async_service;
|
||||||
class Child_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:
|
private:
|
||||||
|
|
||||||
@ -240,12 +246,13 @@ class Genode::Parent_service : public Service
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
Try_parent_service(Env &env, Service::Name const &name)
|
||||||
* Constructor
|
|
||||||
*/
|
|
||||||
Parent_service(Env &env, Service::Name const &name)
|
|
||||||
: Service(name), _env(env) { }
|
: Service(name), _env(env) { }
|
||||||
|
|
||||||
|
/*
|
||||||
|
* \throw Out_of_ram
|
||||||
|
* \throw Out_of_caps
|
||||||
|
*/
|
||||||
void initiate_request(Session_state &session) override
|
void initiate_request(Session_state &session) override
|
||||||
{
|
{
|
||||||
switch (session.phase) {
|
switch (session.phase) {
|
||||||
@ -256,7 +263,7 @@ class Genode::Parent_service : public Service
|
|||||||
_env.id_space());
|
_env.id_space());
|
||||||
try {
|
try {
|
||||||
|
|
||||||
session.cap = _env.session(name().string(),
|
session.cap = _env.try_session(name().string(),
|
||||||
session.id_at_parent->id(),
|
session.id_at_parent->id(),
|
||||||
Session_state::Server_args(session).string(),
|
Session_state::Server_args(session).string(),
|
||||||
session.affinity());
|
session.affinity());
|
||||||
@ -265,23 +272,26 @@ class Genode::Parent_service : public Service
|
|||||||
}
|
}
|
||||||
catch (Out_of_ram) {
|
catch (Out_of_ram) {
|
||||||
session.id_at_parent.destruct();
|
session.id_at_parent.destruct();
|
||||||
session.phase = Session_state::SERVICE_DENIED; }
|
session.phase = Session_state::CLOSED;
|
||||||
|
throw;
|
||||||
|
}
|
||||||
catch (Out_of_caps) {
|
catch (Out_of_caps) {
|
||||||
session.id_at_parent.destruct();
|
session.id_at_parent.destruct();
|
||||||
session.phase = Session_state::SERVICE_DENIED; }
|
session.phase = Session_state::CLOSED;
|
||||||
|
throw;
|
||||||
|
}
|
||||||
catch (Insufficient_ram_quota) {
|
catch (Insufficient_ram_quota) {
|
||||||
session.id_at_parent.destruct();
|
session.id_at_parent.destruct();
|
||||||
session.phase = Session_state::INSUFFICIENT_RAM_QUOTA; }
|
session.phase = Session_state::INSUFFICIENT_RAM_QUOTA;
|
||||||
|
}
|
||||||
catch (Insufficient_cap_quota) {
|
catch (Insufficient_cap_quota) {
|
||||||
session.id_at_parent.destruct();
|
session.id_at_parent.destruct();
|
||||||
session.phase = Session_state::INSUFFICIENT_CAP_QUOTA; }
|
session.phase = Session_state::INSUFFICIENT_CAP_QUOTA;
|
||||||
|
}
|
||||||
catch (Service_denied) {
|
catch (Service_denied) {
|
||||||
session.id_at_parent.destruct();
|
session.id_at_parent.destruct();
|
||||||
session.phase = Session_state::SERVICE_DENIED; }
|
session.phase = Session_state::SERVICE_DENIED;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
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
|
* Representation of a service that asynchronously responds to session request
|
||||||
*/
|
*/
|
||||||
|
@ -116,7 +116,7 @@ namespace {
|
|||||||
_session_blockade->block();
|
_session_blockade->block();
|
||||||
}
|
}
|
||||||
|
|
||||||
Session_capability session(Parent::Service_name const &name,
|
Session_capability try_session(Parent::Service_name const &name,
|
||||||
Parent::Client::Id id,
|
Parent::Client::Id id,
|
||||||
Parent::Session_args const &args,
|
Parent::Session_args const &args,
|
||||||
Affinity const &affinity) override
|
Affinity const &affinity) override
|
||||||
@ -128,6 +128,20 @@ namespace {
|
|||||||
|
|
||||||
Mutex::Guard guard(_mutex);
|
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
|
* Since we account for the backing store for session meta data on
|
||||||
* the route between client and server, the session quota provided
|
* the route between client and server, the session quota provided
|
||||||
@ -154,14 +168,7 @@ namespace {
|
|||||||
Arg_string::set_arg(argbuf, sizeof(argbuf), "cap_quota",
|
Arg_string::set_arg(argbuf, sizeof(argbuf), "cap_quota",
|
||||||
String<32>(cap_quota).string());
|
String<32>(cap_quota).string());
|
||||||
|
|
||||||
Session_capability cap =
|
return try_session(name, id, Parent::Session_args(argbuf), affinity);
|
||||||
_parent.session(id, name, Parent::Session_args(argbuf), affinity);
|
|
||||||
|
|
||||||
if (cap.valid())
|
|
||||||
return cap;
|
|
||||||
|
|
||||||
_block_for_session();
|
|
||||||
return _parent.session_cap(id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (Insufficient_ram_quota) {
|
catch (Insufficient_ram_quota) {
|
||||||
|
@ -54,10 +54,22 @@ struct Qt_launchpad_namespace::Local_env : Genode::Env
|
|||||||
Parent::Client::Id id,
|
Parent::Client::Id id,
|
||||||
Parent::Session_args const &session_args,
|
Parent::Session_args const &session_args,
|
||||||
Affinity const &affinity) override
|
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
|
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); }
|
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)
|
void Libc::Component::construct(Libc::Env &env)
|
||||||
{
|
{
|
||||||
Libc::with_libc([&] {
|
Libc::with_libc([&] {
|
||||||
|
@ -114,6 +114,12 @@ class Libc::Env_implementation : public Libc::Env, public Config_accessor
|
|||||||
Affinity const &aff) override {
|
Affinity const &aff) override {
|
||||||
return _env.session(name, id, args, aff); }
|
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,
|
void upgrade(Parent::Client::Id id,
|
||||||
Parent::Upgrade_args const &args) override {
|
Parent::Upgrade_args const &args) override {
|
||||||
return _env.upgrade(id, args); }
|
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:
|
private:
|
||||||
|
|
||||||
@ -51,7 +51,7 @@ class Sandbox::Parent_service : public Genode::Parent_service, public Abandonabl
|
|||||||
Parent_service(Registry<Parent_service> ®istry, Env &env,
|
Parent_service(Registry<Parent_service> ®istry, Env &env,
|
||||||
Service::Name const &name)
|
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::Client::Id id,
|
||||||
Parent::Session_args const &session_args,
|
Parent::Session_args const &session_args,
|
||||||
Affinity const &affinity) override
|
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
|
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); }
|
void close(Parent::Client::Id id) override { return genode_env.close(id); }
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user