base: use 'Quota_transfer::Account' for 'Service'

This patch makes use of the new 'Quota_transfer::Account' by the service
types in base/service.h and uses 'Quota_transfer' objects in
base/child.cc and init/server.cc.

Furthermore, it decouples the notion of an 'Async_service' from
'Child_service'. Init's 'Routed_service' is no longer a 'Child_service'
but is based on the new 'Async_service' instead.

With this patch in place, quota transfers do no longer implicitly use
'Ram_session_client' objects. So transfers can in principle originate
from component-local 'Ram_session_component' objects, e.g., as used by
noux. Therefore, this patch removes a strumbling block for turning noux
into a single threaded component in the future.

Issue #2398
This commit is contained in:
Norman Feske
2017-05-08 16:49:00 +02:00
committed by Christian Helmuth
parent 5c43074bc6
commit 3670f7735d
19 changed files with 281 additions and 233 deletions

View File

@ -33,12 +33,13 @@ class Platform::Device_pd_policy
Device_pd_policy(Genode::Rpc_entrypoint &slave_ep,
Genode::Region_map &local_rm,
Genode::Ram_session &ram_ref,
Genode::Ram_session_capability ram_ref_cap,
Genode::Ram_quota ram_quota,
Genode::Session_label const &label)
:
Genode::Slave::Policy(label, "device_pd", *this, slave_ep, local_rm,
ram_ref_cap, ram_quota)
ram_ref, ram_ref_cap, ram_quota)
{ }
};

View File

@ -317,12 +317,13 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
*/
Device_pd(Genode::Region_map &local_rm,
Genode::Rpc_entrypoint &ep,
Genode::Ram_session_guard &guard,
Genode::Ram_session_capability ref_ram,
Genode::Ram_session_guard &ref_ram,
Genode::Ram_session_capability ref_ram_cap,
Genode::Session_label const &label)
try :
_reservation(guard, RAM_QUOTA),
_policy(ep, local_rm, ref_ram, Genode::Ram_quota{RAM_QUOTA}, label),
_reservation(ref_ram, RAM_QUOTA),
_policy(ep, local_rm,
ref_ram, ref_ram_cap, Genode::Ram_quota{RAM_QUOTA}, label),
_child(local_rm, ep, _policy),
_connection(_policy, Genode::Slave::Args())
{ }

View File

@ -31,8 +31,7 @@
namespace Init { class Child; }
class Init::Child : Child_policy, Child_service::Wakeup
class Init::Child : Child_policy, Routed_service::Wakeup
{
public:
@ -170,7 +169,7 @@ class Init::Child : Child_policy, Child_service::Wakeup
void _check_ram_constraints(Ram_quota ram_limit)
{
if (_resources.effective_ram_quota().value == 0)
warning("no valid RAM RESOURCE for child \"", _unique_name, "\"");
warning(name(), ": no valid RAM quota defined");
/*
* If the configured RAM quota exceeds our own quota, we donate
@ -256,10 +255,10 @@ class Init::Child : Child_policy, Child_service::Wakeup
struct Requested_resources
{
Ram_quota const ram;
Requested_resources(Parent::Resource_args const &args)
:
ram(Ram_quota { Arg_string::find_arg(args.string(), "ram_quota")
.ulong_value(0) })
ram (ram_quota_from_args(args.string()))
{ }
};
@ -270,15 +269,18 @@ class Init::Child : Child_policy, Child_service::Wakeup
struct Ram_accessor : Routed_service::Ram_accessor
{
Genode::Child &_child;
Ram_accessor(Genode::Child &child) : _child(child) { }
Ram_session_capability ram() const override {
return _child.ram_session_cap(); }
Ram_session &ram() override { return _child.ram(); }
Ram_session_capability ram_cap() const override { return _child.ram_session_cap(); }
} _ram_accessor { _child };
/**
* Child_service::Wakeup callback
* Async_service::Wakeup callback
*/
void wakeup_child_service() override
void wakeup_async_service() override
{
_session_requester.trigger_update();
}
@ -340,7 +342,8 @@ class Init::Child : Child_policy, Child_service::Wakeup
log(" provides service ", name);
new (_alloc)
Routed_service(_child_services, this->name(), _ram_accessor,
Routed_service(_child_services, this->name(),
_ram_accessor,
_session_requester.id_space(),
_child.session_factory(),
name, *this);

View File

@ -276,11 +276,11 @@ void Init::Main::_handle_config()
_destroy_abandoned_parent_services();
/* initial RAM limit before starting new children */
Ram_quota const avail_ram = _avail_ram();
/* initial RAM and caps limit before starting new children */
Ram_quota const avail_ram = _avail_ram();
/* variable used to track the RAM taken by new started children */
Ram_quota used_ram { 0 };
/* variable used to track the RAM and caps taken by new started children */
Ram_quota used_ram { 0 };
/* create new children */
try {
@ -324,8 +324,8 @@ void Init::Main::_handle_config()
* by the Rom_connection constructor.
*/
}
catch (Allocator::Out_of_memory) {
warning("local memory exhausted during child creation"); }
catch (Out_of_ram) {
warning("memory exhausted during child creation"); }
catch (Ram_session::Alloc_failed) {
warning("failed to allocate memory during child construction"); }
catch (Child::Missing_name_attribute) {

View File

@ -148,13 +148,16 @@ void Init::Server::session_closed(Session_state &session)
{
_report_update_trigger.trigger_report_update();
Parent::Server::Id id { session.id_at_client().value };
_env.parent().session_response(id, Parent::SESSION_CLOSED);
Ram_transfer::Account &service_ram_account = session.service();
Ram_session_client(session.service().ram())
.transfer_quota(_env.ram_session_cap(), session.donated_ram_quota());
service_ram_account.try_transfer(_env.ram_session_cap(),
session.donated_ram_quota());
Parent::Server::Id id { session.id_at_client().value };
session.destroy();
_env.parent().session_response(id, Parent::SESSION_CLOSED);
}
@ -192,13 +195,18 @@ void Init::Server::_handle_create_session_request(Xml_node request,
Session_state &session =
route.service.create_session(route.service.factory(),
_client_id_space, id,
route.label, argbuf, Affinity());
_client_id_space, id, route.label,
argbuf, Affinity());
/* transfer session quota */
try { _env.ram().transfer_quota(route.service.ram(), forward_ram_quota); }
catch (...) {
try {
Ram_transfer::Remote_account env_ram_account(_env.ram(), _env.ram_session_cap());
Ram_transfer ram_transfer(forward_ram_quota, env_ram_account, route.service);
ram_transfer.acknowledge();
}
catch (...) {
/*
* This should never happen unless our parent missed to
* transfor the session quota to us prior issuing the session
@ -227,9 +235,11 @@ void Init::Server::_handle_create_session_request(Xml_node request,
throw Genode::Insufficient_ram_quota();
}
catch (Parent::Service_denied) {
_env.parent().session_response(Parent::Server::Id { id.value }, Parent::INVALID_ARGS); }
_env.parent().session_response(Parent::Server::Id { id.value },
Parent::INVALID_ARGS); }
catch (Genode::Insufficient_ram_quota) {
_env.parent().session_response(Parent::Server::Id { id.value }, Parent::INSUFFICIENT_RAM_QUOTA); }
_env.parent().session_response(Parent::Server::Id { id.value },
Parent::INSUFFICIENT_RAM_QUOTA); }
}
@ -243,7 +253,11 @@ void Init::Server::_handle_upgrade_session_request(Xml_node request,
session.phase = Session_state::UPGRADE_REQUESTED;
try {
_env.ram().transfer_quota(session.service().ram(), ram_quota);
Ram_transfer::Remote_account env_ram_account(_env.ram(), _env.ram_session_cap());
Ram_transfer ram_transfer(ram_quota, env_ram_account, session.service());
ram_transfer.acknowledge();
}
catch (...) {
warning("unable to upgrade session quota (", ram_quota, " bytes) "

View File

@ -59,13 +59,17 @@ class Init::Parent_service : public Genode::Parent_service, public Abandonable
/**
* Init-specific representation of a child service
*/
class Init::Routed_service : public Child_service, public Abandonable
class Init::Routed_service : public Async_service, public Abandonable
{
public:
typedef Child_policy::Name Child_name;
struct Ram_accessor { virtual Ram_session_capability ram() const = 0; };
struct Ram_accessor
{
virtual Ram_session &ram() = 0;
virtual Ram_session_capability ram_cap() const = 0;
};
private:
@ -85,34 +89,41 @@ class Init::Routed_service : public Child_service, public Abandonable
* \param services registry of all services provides by children
* \param child_name child name of server, used for session routing
*
* The other arguments correspond to the arguments of 'Child_service'.
* The other arguments correspond to the arguments of 'Async_service'.
*/
Routed_service(Registry<Routed_service> &services,
Child_name const &child_name,
Ram_accessor &ram_accessor,
Id_space<Parent::Server> &server_id_space,
Session_state::Factory &factory,
Service::Name const &name,
Child_service::Wakeup &wakeup)
Routed_service(Registry<Routed_service> &services,
Child_name const &child_name,
Ram_accessor &ram_accessor,
Id_space<Parent::Server> &server_id_space,
Session_state::Factory &factory,
Service::Name const &name,
Wakeup &wakeup)
:
Child_service(server_id_space, factory, name,
Ram_session_capability(), wakeup),
_child_name(child_name), _ram_accessor(ram_accessor),
Async_service(name, server_id_space, factory, wakeup),
_child_name(child_name),
_ram_accessor(ram_accessor),
_factory(factory), _registry_element(services, *this)
{ }
Child_name const &child_name() const { return _child_name; }
Ram_session_capability ram() const { return _ram_accessor.ram(); }
Session_state::Factory &factory() { return _factory; }
/**
* Return factory for creating/destroying session-state objects
*
* This accessor is solely meant to be used by 'Forwarded_service' to
* allocate session-state objects for sessions requested by init's
* parent.
* Ram_transfer::Account interface
*/
Session_state::Factory &factory() { return _factory; }
void transfer(Ram_session_capability to, Ram_quota amount) override
{
if (to.valid()) _ram_accessor.ram().transfer_quota(to, amount);
}
/**
* Ram_transfer::Account interface
*/
Ram_session_capability cap(Ram_quota) const override
{
return _ram_accessor.ram_cap();
}
};
#endif /* _SRC__INIT__SERVICE_H_ */

View File

@ -36,7 +36,7 @@ struct Test::Policy
Policy(Env &env, Name const &name)
:
Slave::Policy(name, name, *this, env.ep().rpc_ep(), env.rm(),
env.ram_session_cap(), Ram_quota{1024*1024})
env.ram(), env.ram_session_cap(), Ram_quota{1024*1024})
{ }
};

View File

@ -296,7 +296,7 @@ class Test::Parent
:
Slave::Policy(Label("child"), "test-resource_yield",
*this, env.ep().rpc_ep(), env.rm(),
env.ram_session_cap(), Ram_quota{SLAVE_QUOTA}),
env.ram(), env.ram_session_cap(), Ram_quota{SLAVE_QUOTA}),
_parent(parent)
{
configure("<config child=\"yes\" />");