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

@ -445,7 +445,7 @@ class Genode::Child : protected Rpc_object<Parent>,
Env_service(Child &child, Service &service) Env_service(Child &child, Service &service)
: :
Genode::Service(CONNECTION::service_name(), service.ram()), Genode::Service(CONNECTION::service_name()),
_child(child), _service(service) _child(child), _service(service)
{ } { }
@ -469,6 +469,23 @@ class Genode::Child : protected Rpc_object<Parent>,
_child._try_construct_env_dependent_members(); _child._try_construct_env_dependent_members();
} }
/**
* Service (Ram_transfer::Account) interface
*/
void transfer(Ram_session_capability to, Ram_quota amount) override
{
Ram_transfer::Account &from = _service;
from.transfer(to, amount);
}
/**
* Service (Ram_transfer::Account) interface
*/
Ram_session_capability cap(Ram_quota) const override
{
Ram_transfer::Account &to = _service;
return to.cap(Ram_quota());
}
void wakeup() override { _service.wakeup(); } void wakeup() override { _service.wakeup(); }
bool operator == (Service const &other) const override bool operator == (Service const &other) const override

View File

@ -20,6 +20,7 @@
#include <base/session_state.h> #include <base/session_state.h>
#include <base/log.h> #include <base/log.h>
#include <base/registry.h> #include <base/registry.h>
#include <base/quota_transfer.h>
namespace Genode { namespace Genode {
@ -27,11 +28,12 @@ namespace Genode {
template <typename> class Session_factory; template <typename> class Session_factory;
template <typename> class Local_service; template <typename> class Local_service;
class Parent_service; class Parent_service;
class Async_service;
class Child_service; class Child_service;
} }
class Genode::Service : Noncopyable class Genode::Service : public Ram_transfer::Account
{ {
public: public:
@ -39,8 +41,7 @@ class Genode::Service : Noncopyable
private: private:
Name const _name; Name const _name;
Ram_session_capability const _ram;
protected: protected:
@ -64,10 +65,8 @@ class Genode::Service : Noncopyable
* Constructor * Constructor
* *
* \param name service name * \param name service name
* \param ram RAM session to receive/withdraw session quota
*/ */
Service(Name const &name, Ram_session_capability ram) Service(Name const &name) : _name(name) { }
: _name(name), _ram(ram) { }
virtual ~Service() { } virtual ~Service() { }
@ -104,11 +103,6 @@ class Genode::Service : Noncopyable
*/ */
virtual void wakeup() { } virtual void wakeup() { }
/**
* Return the RAM session to be used for trading resources
*/
virtual Ram_session_capability ram() const { return _ram; }
virtual bool operator == (Service const &other) const { return this == &other; } virtual bool operator == (Service const &other) const { return this == &other; }
}; };
@ -181,10 +175,7 @@ class Genode::Local_service : public Service
* Constructor * Constructor
*/ */
Local_service(Factory &factory) Local_service(Factory &factory)
: : Service(SESSION::service_name()), _factory(factory) { }
Service(SESSION::service_name(), Ram_session_capability()),
_factory(factory)
{ }
void initiate_request(Session_state &session) override void initiate_request(Session_state &session) override
{ {
@ -235,6 +226,7 @@ class Genode::Local_service : public Service
break; break;
} }
} }
}; };
@ -257,7 +249,7 @@ class Genode::Parent_service : public Service
* Constructor * Constructor
*/ */
Parent_service(Env &env, Service::Name const &name) Parent_service(Env &env, Service::Name const &name)
: Service(name, Ram_session_capability()), _env(env) { } : Service(name), _env(env) { }
/** /**
* Constructor * Constructor
@ -265,7 +257,7 @@ class Genode::Parent_service : public Service
* \deprecated * \deprecated
*/ */
Parent_service(Service::Name const &name) Parent_service(Service::Name const &name)
: Service(name, Ram_session_capability()), _env(_env_deprecated()) { } : Service(name), _env(_env_deprecated()) { }
void initiate_request(Session_state &session) override void initiate_request(Session_state &session) override
{ {
@ -284,6 +276,9 @@ class Genode::Parent_service : public Service
session.phase = Session_state::AVAILABLE; session.phase = Session_state::AVAILABLE;
} }
catch (Out_of_ram) {
session.id_at_parent.destruct();
session.phase = Session_state::INVALID_ARGS; }
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; }
@ -304,7 +299,7 @@ class Genode::Parent_service : public Service
try { try {
_env.upgrade(session.id_at_parent->id(), args.string()); } _env.upgrade(session.id_at_parent->id(), args.string()); }
catch (Out_of_ram) { catch (Out_of_ram) {
warning("quota exceeded while upgrading parent session"); } warning("RAM quota exceeded while upgrading parent session"); }
session.confirm_ram_upgrade(); session.confirm_ram_upgrade();
session.phase = Session_state::CAP_HANDED_OUT; session.phase = Session_state::CAP_HANDED_OUT;
@ -332,13 +327,13 @@ class Genode::Parent_service : public Service
/** /**
* Representation of a service that is implemented in a child * Representation of a service that asynchronously responds to session request
*/ */
class Genode::Child_service : public Service class Genode::Async_service : public Service
{ {
public: public:
struct Wakeup { virtual void wakeup_child_service() = 0; }; struct Wakeup { virtual void wakeup_async_service() = 0; };
private: private:
@ -360,24 +355,20 @@ class Genode::Child_service : public Service
public: public:
/** /**
* Constructor * Constructor
* *
* \param factory server-side session-state factory * \param factory server-side session-state factory
* \param name name of service * \param name name of service
* \param ram recipient of session quota
* \param wakeup callback to be notified on the arrival of new * \param wakeup callback to be notified on the arrival of new
* session requests * session requests
*
*/ */
Child_service(Id_space<Parent::Server> &server_id_space, Async_service(Service::Name const &name,
Id_space<Parent::Server> &server_id_space,
Session_state::Factory &factory, Session_state::Factory &factory,
Service::Name const &name,
Ram_session_capability ram,
Wakeup &wakeup) Wakeup &wakeup)
: :
Service(name, ram), Service(name),
_server_id_space(server_id_space), _server_id_space(server_id_space),
_server_factory(factory), _wakeup(wakeup) _server_factory(factory), _wakeup(wakeup)
{ } { }
@ -395,7 +386,46 @@ class Genode::Child_service : public Service
return &_server_id_space == &id_space; return &_server_id_space == &id_space;
} }
void wakeup() override { _wakeup.wakeup_child_service(); } void wakeup() override { _wakeup.wakeup_async_service(); }
};
/**
* Representation of a service that is implemented in a child
*/
class Genode::Child_service : public Async_service
{
private:
Ram_session_client _ram;
public:
/**
* Constructor
*/
Child_service(Service::Name const &name,
Id_space<Parent::Server> &server_id_space,
Session_state::Factory &factory,
Wakeup &wakeup,
Ram_session_capability ram)
:
Async_service(name, server_id_space, factory, wakeup),
_ram(ram)
{ }
/**
* Ram_transfer::Account interface
*/
void transfer(Ram_session_capability to, Ram_quota amount) override
{
if (to.valid()) _ram.transfer_quota(to, amount);
}
/**
* Ram_transfer::Account interface
*/
Ram_session_capability cap(Ram_quota) const override { return _ram; }
}; };
#endif /* _INCLUDE__BASE__SERVICE_H_ */ #endif /* _INCLUDE__BASE__SERVICE_H_ */

View File

@ -12,84 +12,11 @@
*/ */
#include <base/child.h> #include <base/child.h>
#include <base/quota_transfer.h>
using namespace Genode; using namespace Genode;
/***************
** Utilities **
***************/
namespace {
/**
* Guard for transferring quota donation
*
* This class is used to provide transactional semantics of quota
* transfers. Establishing a new session involves several steps, in
* particular subsequent quota transfers. If one intermediate step
* fails, we need to revert all quota transfers that already took
* place. When instantated at a local scope, a 'Transfer' object guards
* a quota transfer. If the scope is left without prior an explicit
* acknowledgement of the transfer (for example via an exception), the
* destructor the 'Transfer' object reverts the transfer in flight.
*/
class Transfer {
bool _ack;
Ram_quota _quantum;
Ram_session_capability _from;
Ram_session_capability _to;
public:
class Quota_exceeded : Exception { };
/**
* Constructor
*
* \param quantim number of bytes to transfer
* \param from donator RAM session
* \param to receiver RAM session
*
* \throw Quota_exceeded
*/
Transfer(Ram_quota quantum,
Ram_session_capability from,
Ram_session_capability to)
: _ack(false), _quantum(quantum), _from(from), _to(to)
{
if (!_from.valid() || !_to.valid())
return;
try { Ram_session_client(_from).transfer_quota(_to, quantum); }
catch (...) {
warning("not enough quota for a donation of ", quantum, " bytes");
throw Quota_exceeded();
}
}
/**
* Destructor
*
* The destructor will be called when leaving the scope of the
* 'session' function. If the scope is left because of an error
* (e.g., an exception), the donation will be reverted.
*/
~Transfer()
{
if (!_ack && _from.valid() && _to.valid())
Ram_session_client(_to).transfer_quota(_from, _quantum);
}
/**
* Acknowledge quota donation
*/
void acknowledge() { _ack = true; }
};
}
/*********** /***********
** Child ** ** Child **
***********/ ***********/
@ -270,12 +197,14 @@ Session_capability Child::session(Parent::Client::Id id,
session.closed_callback = this; session.closed_callback = this;
try { try {
Ram_transfer::Remote_account ref_ram_account { _policy.ref_ram(), _policy.ref_ram_cap() };
Ram_transfer::Remote_account ram_account { ram(), ram_session_cap() };
/* transfer the quota donation from the child's account to ourself */ /* transfer the quota donation from the child's account to ourself */
Transfer donation_from_child(ram_quota, _ram.cap(), _policy.ref_ram_cap()); Ram_transfer ram_donation_from_child(ram_quota, ram_account, ref_ram_account);
/* transfer session quota from ourself to the service provider */ /* transfer session quota from ourself to the service provider */
Transfer donation_to_service(forward_ram_quota, _policy.ref_ram_cap(), Ram_transfer ram_donation_to_service(forward_ram_quota, ref_ram_account, service);
service.ram());
/* try to dispatch session request synchronously */ /* try to dispatch session request synchronously */
service.initiate_request(session); service.initiate_request(session);
@ -291,13 +220,13 @@ Session_capability Child::session(Parent::Client::Id id,
} }
/* finish transaction */ /* finish transaction */
donation_from_child.acknowledge(); ram_donation_from_child.acknowledge();
donation_to_service.acknowledge(); ram_donation_to_service.acknowledge();
} }
catch (Transfer::Quota_exceeded) { /*
/* * Release session meta data if one of the quota transfers went wrong.
* Release session meta data if one of the quota transfers went wrong. */
*/ catch (Ram_transfer::Quota_exceeded) {
session.destroy(); session.destroy();
throw Out_of_ram(); throw Out_of_ram();
} }
@ -386,12 +315,14 @@ Parent::Upgrade_result Child::upgrade(Client::Id id, Parent::Upgrade_args const
Arg_string::find_arg(args.string(), "ram_quota").ulong_value(0) }; Arg_string::find_arg(args.string(), "ram_quota").ulong_value(0) };
try { try {
Ram_transfer::Remote_account ref_ram_account { _policy.ref_ram(), _policy.ref_ram_cap() };
Ram_transfer::Remote_account ram_account { ram(), ram_session_cap() };
/* transfer quota from client to ourself */ /* transfer quota from client to ourself */
Transfer donation_from_child(ram_quota, _ram.cap(), _policy.ref_ram_cap()); Ram_transfer ram_donation_from_child(ram_quota, ram_account, ref_ram_account);
/* transfer session quota from ourself to the service provider */ /* transfer session quota from ourself to the service provider */
Transfer donation_to_service(ram_quota, _policy.ref_ram_cap(), Ram_transfer ram_donation_to_service(ram_quota, ref_ram_account, session.service());
session.service().ram());
session.increase_donated_quota(ram_quota); session.increase_donated_quota(ram_quota);
session.phase = Session_state::UPGRADE_REQUESTED; session.phase = Session_state::UPGRADE_REQUESTED;
@ -399,11 +330,11 @@ Parent::Upgrade_result Child::upgrade(Client::Id id, Parent::Upgrade_args const
session.service().initiate_request(session); session.service().initiate_request(session);
/* finish transaction */ /* finish transaction */
donation_from_child.acknowledge(); ram_donation_from_child.acknowledge();
donation_to_service.acknowledge(); ram_donation_to_service.acknowledge();
} }
catch (Transfer::Quota_exceeded) { catch (Ram_transfer::Quota_exceeded) {
warning(_policy.name(), ": upgrade of ", session.service().name(), " failed"); warning(_policy.name(), ": RAM upgrade of ", session.service().name(), " failed");
throw Out_of_ram(); throw Out_of_ram();
} }
@ -422,10 +353,14 @@ Parent::Upgrade_result Child::upgrade(Client::Id id, Parent::Upgrade_args const
void Child::_revert_quota_and_destroy(Session_state &session) void Child::_revert_quota_and_destroy(Session_state &session)
{ {
Ram_transfer::Remote_account ref_ram_account(_policy.ref_ram(), _policy.ref_ram_cap());
Ram_transfer::Account &service_ram_account = session.service();
Ram_transfer::Remote_account child_ram_account(ram(), ram_session_cap());
try { try {
/* transfer session quota from the service to ourself */ /* transfer session quota from the service to ourself */
Transfer donation_from_service(session.donated_ram_quota(), Ram_transfer ram_donation_from_service(session.donated_ram_quota(),
session.service().ram(), _policy.ref_ram_cap()); service_ram_account, ref_ram_account);
/* /*
* Transfer session quota from ourself to the client (our child). In * Transfer session quota from ourself to the client (our child). In
@ -433,15 +368,19 @@ void Child::_revert_quota_and_destroy(Session_state &session)
* quota that we preserved for locally storing the session meta data * quota that we preserved for locally storing the session meta data
* ('session_costs'). * ('session_costs').
*/ */
Transfer donation_to_client(Ram_quota{session.donated_ram_quota().value + Ram_quota const returned_ram { session.donated_ram_quota().value +
_session_factory.session_costs()}, _session_factory.session_costs() };
_policy.ref_ram_cap(), ram_session_cap());
Ram_transfer ram_donation_to_client(returned_ram,
ref_ram_account, child_ram_account);
/* finish transaction */ /* finish transaction */
donation_from_service.acknowledge(); ram_donation_from_service.acknowledge();
donation_to_client.acknowledge(); ram_donation_to_client.acknowledge();
} }
catch (Transfer::Quota_exceeded) { catch (Ram_transfer::Quota_exceeded) {
warning(_policy.name(), ": could not revert session quota (", session, ")"); } warning(_policy.name(), ": could not revert session RAM quota (", session, ")"); }
catch (Cap_transfer::Quota_exceeded) {
warning(_policy.name(), ": could not revert session cap quota (", session, ")"); }
session.destroy(); session.destroy();
_policy.session_state_changed(); _policy.session_state_changed();

View File

@ -34,7 +34,7 @@ class Launchpad;
class Launchpad_child : public Genode::Child_policy, class Launchpad_child : public Genode::Child_policy,
public Genode::List<Launchpad_child>::Element, public Genode::List<Launchpad_child>::Element,
public Genode::Child_service::Wakeup public Genode::Async_service::Wakeup
{ {
public: public:
@ -75,7 +75,7 @@ class Launchpad_child : public Genode::Child_policy,
/** /**
* Child_service::Wakeup callback * Child_service::Wakeup callback
*/ */
void wakeup_child_service() override void wakeup_async_service() override
{ {
_session_requester.trigger_update(); _session_requester.trigger_update();
} }
@ -133,8 +133,7 @@ class Launchpad_child : public Genode::Child_policy,
Binary_name binary_name() const override { return _elf_name; } Binary_name binary_name() const override { return _elf_name; }
Genode::Ram_session &ref_ram() override { return _ref_ram; } Genode::Ram_session &ref_ram() override { return _ref_ram; }
Genode::Ram_session_capability ref_ram_cap() const override { return _ref_ram_cap; } Genode::Ram_session_capability ref_ram_cap() const override { return _ref_ram_cap; }
void init(Genode::Ram_session &session, void init(Genode::Ram_session &session,
@ -198,9 +197,10 @@ class Launchpad_child : public Genode::Child_policy,
} }
new (_alloc) new (_alloc)
Child_service(_child_services, _session_requester.id_space(), Child_service(_child_services, service_name,
_child.session_factory(), service_name, _session_requester.id_space(),
_child.ram_session_cap(), *this); _child.session_factory(), *this,
_child.ram_session_cap());
} }
}; };

View File

@ -50,10 +50,12 @@ class Report_rom_slave : public Genode::Noncopyable
Policy(Genode::Rpc_entrypoint &ep, Policy(Genode::Rpc_entrypoint &ep,
Genode::Region_map &rm, Genode::Region_map &rm,
Genode::Ram_session_capability ram, Genode::Ram_session &ref_ram,
Genode::Ram_session_capability ref_ram_cap,
const char *config) const char *config)
: :
Genode::Slave::Policy(_name(), _name(), *this, ep, rm, ram, _quota()) Genode::Slave::Policy(_name(), _name(), *this, ep, rm,
ref_ram, ref_ram_cap, _quota())
{ {
if (config) if (config)
configure(config); configure(config);
@ -76,11 +78,12 @@ class Report_rom_slave : public Genode::Noncopyable
*/ */
Report_rom_slave(Genode::Pd_session &pd, Report_rom_slave(Genode::Pd_session &pd,
Genode::Region_map &rm, Genode::Region_map &rm,
Genode::Ram_session_capability ram, Genode::Ram_session &ram,
Genode::Ram_session_capability ram_cap,
char const *config) char const *config)
: :
_ep(&pd, _ep_stack_size, "report_rom"), _ep(&pd, _ep_stack_size, "report_rom"),
_policy(_ep, rm, ram, config), _policy(_ep, rm, ram, ram_cap, config),
_child(rm, _ep, _policy) _child(rm, _ep, _policy)
{ } { }

View File

@ -196,10 +196,12 @@ class Launcher::Fading_dialog : private Input_event_handler
_fader_slave_ep(&env.pd(), _fader_slave_ep_stack_size, "nit_fader"), _fader_slave_ep(&env.pd(), _fader_slave_ep_stack_size, "nit_fader"),
_nitpicker_connection(env, "menu"), _nitpicker_connection(env, "menu"),
_nitpicker_session(env, _nitpicker_connection, env.ep(), _fader_slave_ep, *this), _nitpicker_session(env, _nitpicker_connection, env.ep(), _fader_slave_ep, *this),
_nit_fader_slave(_fader_slave_ep, env.rm(), env.ram_session_cap(), _nit_fader_slave(_fader_slave_ep, env.rm(),
env.ram(), env.ram_session_cap(),
_nitpicker_service), _nitpicker_service),
_nit_fader_connection(env.rm(), _nit_fader_slave.policy(), Slave::Args("label=menu")), _nit_fader_connection(env.rm(), _nit_fader_slave.policy(), Slave::Args("label=menu")),
_menu_view_slave(env.pd(), env.rm(), env.ram_session_cap(), _menu_view_slave(env.pd(), env.rm(),
env.ram(), env.ram_session_cap(),
_nit_fader_connection, _nit_fader_connection,
_dialog_rom, _hover_report, initial_position) _dialog_rom, _hover_report, initial_position)
{ {

View File

@ -43,7 +43,8 @@ struct Launcher::Main
"</config>"; "</config>";
Report_rom_slave _report_rom_slave { Report_rom_slave _report_rom_slave {
_env.pd(), _env.rm(), _env.ram_session_cap(), _report_rom_config }; _env.pd(), _env.rm(), _env.ram(), _env.ram_session_cap(),
_report_rom_config };
/** /**
* Nitpicker session used to perform session-control operations on the * Nitpicker session used to perform session-control operations on the

View File

@ -80,13 +80,15 @@ class Launcher::Menu_view_slave
Policy(Genode::Rpc_entrypoint &ep, Policy(Genode::Rpc_entrypoint &ep,
Genode::Region_map &rm, Genode::Region_map &rm,
Genode::Ram_session_capability ram, Genode::Ram_session &ref_ram,
Genode::Ram_session_capability ref_ram_cap,
Capability<Nitpicker::Session> nitpicker_session, Capability<Nitpicker::Session> nitpicker_session,
Capability<Rom_session> dialog_rom_session, Capability<Rom_session> dialog_rom_session,
Capability<Report::Session> hover_report_session, Capability<Report::Session> hover_report_session,
Position position) Position position)
: :
Genode::Slave::Policy(_name(), _name(), *this, ep, rm, ram, _quota()), Genode::Slave::Policy(_name(), _name(), *this, ep, rm,
ref_ram, ref_ram_cap, _quota()),
_nitpicker(rm, nitpicker_session), _nitpicker(rm, nitpicker_session),
_dialog_rom(dialog_rom_session), _dialog_rom(dialog_rom_session),
_hover_report(hover_report_session), _hover_report(hover_report_session),
@ -127,14 +129,16 @@ class Launcher::Menu_view_slave
*/ */
Menu_view_slave(Genode::Pd_session &pd, Menu_view_slave(Genode::Pd_session &pd,
Genode::Region_map &rm, Genode::Region_map &rm,
Genode::Ram_session_capability ram, Genode::Ram_session &ref_ram,
Genode::Ram_session_capability ref_ram_cap,
Capability<Nitpicker::Session> nitpicker_session, Capability<Nitpicker::Session> nitpicker_session,
Capability<Rom_session> dialog_rom_session, Capability<Rom_session> dialog_rom_session,
Capability<Report::Session> hover_report_session, Capability<Report::Session> hover_report_session,
Position initial_position) Position initial_position)
: :
_ep(&pd, _ep_stack_size, "nit_fader"), _ep(&pd, _ep_stack_size, "nit_fader"),
_policy(_ep, rm, ram, nitpicker_session, dialog_rom_session, _policy(_ep, rm, ref_ram, ref_ram_cap,
nitpicker_session, dialog_rom_session,
hover_report_session, initial_position), hover_report_session, initial_position),
_child(rm, _ep, _policy) _child(rm, _ep, _policy)
{ } { }

View File

@ -52,10 +52,12 @@ class Launcher::Nit_fader_slave
Policy(Rpc_entrypoint &ep, Policy(Rpc_entrypoint &ep,
Region_map &rm, Region_map &rm,
Ram_session_capability ram, Ram_session &ref_ram,
Ram_session_capability ref_ram_cap,
Genode::Service &nitpicker_service) Genode::Service &nitpicker_service)
: :
Genode::Slave::Policy(_name(), _name(), *this, ep, rm, ram, _quota()), Genode::Slave::Policy(_name(), _name(), *this, ep, rm,
ref_ram, ref_ram_cap, _quota()),
_nitpicker_service(nitpicker_service) _nitpicker_service(nitpicker_service)
{ {
visible(false); visible(false);
@ -87,16 +89,17 @@ class Launcher::Nit_fader_slave
/** /**
* Constructor * Constructor
* *
* \param ep entrypoint used for nitpicker child thread * \param ep entrypoint used for nitpicker child thread
* \param ram RAM session used to allocate the configuration * \param ref_ram RAM session used to allocate the configuration
* dataspace * dataspace and child memory
*/ */
Nit_fader_slave(Rpc_entrypoint &ep, Nit_fader_slave(Rpc_entrypoint &ep,
Genode::Region_map &rm, Genode::Region_map &rm,
Ram_session_capability ram, Ram_session &ref_ram,
Ram_session_capability ref_ram_cap,
Genode::Service &nitpicker_service) Genode::Service &nitpicker_service)
: :
_policy(ep, rm, ram, nitpicker_service), _policy(ep, rm, ref_ram, ref_ram_cap, nitpicker_service),
_child(rm, ep, _policy) _child(rm, ep, _policy)
{ {
visible(false); visible(false);

View File

@ -78,7 +78,7 @@ class Genode::Child_policy_dynamic_rom_file : public Rpc_object<Rom_session>,
Rpc_entrypoint &ep, Rpc_entrypoint &ep,
Ram_session *ram) Ram_session *ram)
: :
Service("ROM", Ram_session_capability()), Service("ROM"),
_ram(ram), _rm(rm), _ram(ram), _rm(rm),
_fg(*_ram, _rm, 0), _bg(*_ram, _rm, 0), _fg(*_ram, _rm, 0), _bg(*_ram, _rm, 0),
_bg_has_pending_data(false), _bg_has_pending_data(false),
@ -101,7 +101,7 @@ class Genode::Child_policy_dynamic_rom_file : public Rpc_object<Rom_session>,
Rpc_entrypoint &ep, Rpc_entrypoint &ep,
Ram_session *ram) __attribute__((deprecated)) Ram_session *ram) __attribute__((deprecated))
: :
Service("ROM", Ram_session_capability()), Service("ROM"),
_ram(ram), _rm(*env_deprecated()->rm_session()), _ram(ram), _rm(*env_deprecated()->rm_session()),
_fg(*_ram, _rm, 0), _bg(*_ram, _rm, 0), _fg(*_ram, _rm, 0), _bg(*_ram, _rm, 0),
_bg_has_pending_data(false), _bg_has_pending_data(false),

View File

@ -54,7 +54,8 @@ class Genode::Slave::Policy : public Child_policy
Label const _label; Label const _label;
Binary_name const _binary_name; Binary_name const _binary_name;
Ram_session_client _ram; Ram_session &_ref_ram;
Ram_session_capability _ref_ram_cap;
Genode::Parent_service _binary_service; Genode::Parent_service _binary_service;
Ram_quota const _ram_quota; Ram_quota const _ram_quota;
Parent_services &_parent_services; Parent_services &_parent_services;
@ -77,19 +78,22 @@ class Genode::Slave::Policy : public Child_policy
* \throw Ram_session::Alloc_failed by 'Child_policy_dynamic_rom_file' * \throw Ram_session::Alloc_failed by 'Child_policy_dynamic_rom_file'
* \throw Rm_session::Attach_failed by 'Child_policy_dynamic_rom_file' * \throw Rm_session::Attach_failed by 'Child_policy_dynamic_rom_file'
*/ */
Policy(Label const &label, Policy(Label const &label,
Name const &binary_name, Name const &binary_name,
Parent_services &parent_services, Parent_services &parent_services,
Rpc_entrypoint &ep, Rpc_entrypoint &ep,
Region_map &rm, Region_map &rm,
Ram_session_capability ram_cap, Ram_session &ref_ram,
Ram_quota ram_quota) Ram_session_capability ref_ram_cap,
Ram_quota ram_quota)
: :
_label(label), _binary_name(binary_name), _ram(ram_cap), _label(label), _binary_name(binary_name),
_ref_ram(ref_ram), _ref_ram_cap(ref_ram_cap),
_binary_service(Rom_session::service_name()), _binary_service(Rom_session::service_name()),
_ram_quota(ram_quota), _parent_services(parent_services), _ep(ep), _ram_quota(ram_quota),
_config_policy(rm, "config", _ep, &_ram), _parent_services(parent_services), _ep(ep),
_session_requester(ep, _ram, rm) _config_policy(rm, "config", _ep, &_ref_ram),
_session_requester(ep, _ref_ram, rm)
{ {
configure("<config/>"); configure("<config/>");
} }
@ -123,13 +127,13 @@ class Genode::Slave::Policy : public Child_policy
Binary_name binary_name() const override { return _binary_name; } Binary_name binary_name() const override { return _binary_name; }
Ram_session &ref_ram() override { return _ram; } Ram_session &ref_ram() override { return _ref_ram; }
Ram_session_capability ref_ram_cap() const override { return _ram; } Ram_session_capability ref_ram_cap() const override { return _ref_ram_cap; }
void init(Ram_session &session, Ram_session_capability cap) override void init(Ram_session &session, Ram_session_capability cap) override
{ {
session.ref_account(_ram); session.ref_account(_ref_ram_cap);
_ram.transfer_quota(cap, _ram_quota); _ref_ram.transfer_quota(cap, _ram_quota);
} }
Service &resolve_session_request(Service::Name const &service_name, Service &resolve_session_request(Service::Name const &service_name,
@ -178,15 +182,13 @@ class Genode::Slave::Connection_base
struct Service : Genode::Service, Session_state::Ready_callback, struct Service : Genode::Service, Session_state::Ready_callback,
Session_state::Closed_callback Session_state::Closed_callback
{ {
Id_space<Parent::Server> &_id_space; Policy &_policy;
Lock _lock { Lock::LOCKED };
Lock _lock { Lock::LOCKED }; bool _alive = false;
bool _alive = false;
Service(Policy &policy) Service(Policy &policy)
: :
Genode::Service(CONNECTION::service_name(), policy.ref_ram_cap()), Genode::Service(CONNECTION::service_name()), _policy(policy)
_id_space(policy.server_id_space())
{ } { }
void initiate_request(Session_state &session) override void initiate_request(Session_state &session) override
@ -196,7 +198,8 @@ class Genode::Slave::Connection_base
case Session_state::CREATE_REQUESTED: case Session_state::CREATE_REQUESTED:
if (!session.id_at_server.constructed()) if (!session.id_at_server.constructed())
session.id_at_server.construct(session, _id_space); session.id_at_server.construct(session,
_policy.server_id_space());
session.ready_callback = this; session.ready_callback = this;
session.async_client_notify = true; session.async_client_notify = true;
@ -237,6 +240,22 @@ class Genode::Slave::Connection_base
*/ */
void session_closed(Session_state &s) override { _lock.unlock(); } void session_closed(Session_state &s) override { _lock.unlock(); }
/**
* Service ('Ram_transfer::Account') interface
*/
void transfer(Ram_session_capability to, Ram_quota amount) override
{
if (to.valid()) _policy.ref_ram().transfer_quota(to, amount);
}
/**
* Service ('Ram_transfer::Account') interface
*/
Ram_session_capability cap(Ram_quota) const override
{
return _policy.ref_ram_cap();
}
} _service; } _service;
Local_connection<CONNECTION> _connection; Local_connection<CONNECTION> _connection;

View File

@ -33,12 +33,13 @@ class Platform::Device_pd_policy
Device_pd_policy(Genode::Rpc_entrypoint &slave_ep, Device_pd_policy(Genode::Rpc_entrypoint &slave_ep,
Genode::Region_map &local_rm, Genode::Region_map &local_rm,
Genode::Ram_session &ram_ref,
Genode::Ram_session_capability ram_ref_cap, Genode::Ram_session_capability ram_ref_cap,
Genode::Ram_quota ram_quota, Genode::Ram_quota ram_quota,
Genode::Session_label const &label) Genode::Session_label const &label)
: :
Genode::Slave::Policy(label, "device_pd", *this, slave_ep, local_rm, 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, Device_pd(Genode::Region_map &local_rm,
Genode::Rpc_entrypoint &ep, Genode::Rpc_entrypoint &ep,
Genode::Ram_session_guard &guard, Genode::Ram_session_guard &ref_ram,
Genode::Ram_session_capability ref_ram, Genode::Ram_session_capability ref_ram_cap,
Genode::Session_label const &label) Genode::Session_label const &label)
try : try :
_reservation(guard, RAM_QUOTA), _reservation(ref_ram, RAM_QUOTA),
_policy(ep, local_rm, ref_ram, Genode::Ram_quota{RAM_QUOTA}, label), _policy(ep, local_rm,
ref_ram, ref_ram_cap, Genode::Ram_quota{RAM_QUOTA}, label),
_child(local_rm, ep, _policy), _child(local_rm, ep, _policy),
_connection(_policy, Genode::Slave::Args()) _connection(_policy, Genode::Slave::Args())
{ } { }

View File

@ -31,8 +31,7 @@
namespace Init { class Child; } namespace Init { class Child; }
class Init::Child : Child_policy, Routed_service::Wakeup
class Init::Child : Child_policy, Child_service::Wakeup
{ {
public: public:
@ -170,7 +169,7 @@ class Init::Child : Child_policy, Child_service::Wakeup
void _check_ram_constraints(Ram_quota ram_limit) void _check_ram_constraints(Ram_quota ram_limit)
{ {
if (_resources.effective_ram_quota().value == 0) 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 * 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 struct Requested_resources
{ {
Ram_quota const ram; Ram_quota const ram;
Requested_resources(Parent::Resource_args const &args) Requested_resources(Parent::Resource_args const &args)
: :
ram(Ram_quota { Arg_string::find_arg(args.string(), "ram_quota") ram (ram_quota_from_args(args.string()))
.ulong_value(0) })
{ } { }
}; };
@ -270,15 +269,18 @@ class Init::Child : Child_policy, Child_service::Wakeup
struct Ram_accessor : Routed_service::Ram_accessor struct Ram_accessor : Routed_service::Ram_accessor
{ {
Genode::Child &_child; Genode::Child &_child;
Ram_accessor(Genode::Child &child) : _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 }; } _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(); _session_requester.trigger_update();
} }
@ -340,7 +342,8 @@ class Init::Child : Child_policy, Child_service::Wakeup
log(" provides service ", name); log(" provides service ", name);
new (_alloc) new (_alloc)
Routed_service(_child_services, this->name(), _ram_accessor, Routed_service(_child_services, this->name(),
_ram_accessor,
_session_requester.id_space(), _session_requester.id_space(),
_child.session_factory(), _child.session_factory(),
name, *this); name, *this);

View File

@ -276,11 +276,11 @@ void Init::Main::_handle_config()
_destroy_abandoned_parent_services(); _destroy_abandoned_parent_services();
/* initial RAM limit before starting new children */ /* initial RAM and caps limit before starting new children */
Ram_quota const avail_ram = _avail_ram(); Ram_quota const avail_ram = _avail_ram();
/* variable used to track the RAM taken by new started children */ /* variable used to track the RAM and caps taken by new started children */
Ram_quota used_ram { 0 }; Ram_quota used_ram { 0 };
/* create new children */ /* create new children */
try { try {
@ -324,8 +324,8 @@ void Init::Main::_handle_config()
* by the Rom_connection constructor. * by the Rom_connection constructor.
*/ */
} }
catch (Allocator::Out_of_memory) { catch (Out_of_ram) {
warning("local memory exhausted during child creation"); } warning("memory exhausted during child creation"); }
catch (Ram_session::Alloc_failed) { catch (Ram_session::Alloc_failed) {
warning("failed to allocate memory during child construction"); } warning("failed to allocate memory during child construction"); }
catch (Child::Missing_name_attribute) { 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(); _report_update_trigger.trigger_report_update();
Parent::Server::Id id { session.id_at_client().value }; Ram_transfer::Account &service_ram_account = session.service();
_env.parent().session_response(id, Parent::SESSION_CLOSED);
Ram_session_client(session.service().ram()) service_ram_account.try_transfer(_env.ram_session_cap(),
.transfer_quota(_env.ram_session_cap(), session.donated_ram_quota()); session.donated_ram_quota());
Parent::Server::Id id { session.id_at_client().value };
session.destroy(); 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 = Session_state &session =
route.service.create_session(route.service.factory(), route.service.create_session(route.service.factory(),
_client_id_space, id, _client_id_space, id, route.label,
route.label, argbuf, Affinity()); argbuf, Affinity());
/* transfer session quota */ /* transfer session quota */
try { _env.ram().transfer_quota(route.service.ram(), forward_ram_quota); } try {
catch (...) { 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 * This should never happen unless our parent missed to
* transfor the session quota to us prior issuing the session * 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(); throw Genode::Insufficient_ram_quota();
} }
catch (Parent::Service_denied) { 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) { 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; session.phase = Session_state::UPGRADE_REQUESTED;
try { 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 (...) { catch (...) {
warning("unable to upgrade session quota (", ram_quota, " bytes) " 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 * 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: public:
typedef Child_policy::Name Child_name; 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: private:
@ -85,34 +89,41 @@ class Init::Routed_service : public Child_service, public Abandonable
* \param services registry of all services provides by children * \param services registry of all services provides by children
* \param child_name child name of server, used for session routing * \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, Routed_service(Registry<Routed_service> &services,
Child_name const &child_name, Child_name const &child_name,
Ram_accessor &ram_accessor, Ram_accessor &ram_accessor,
Id_space<Parent::Server> &server_id_space, Id_space<Parent::Server> &server_id_space,
Session_state::Factory &factory, Session_state::Factory &factory,
Service::Name const &name, Service::Name const &name,
Child_service::Wakeup &wakeup) Wakeup &wakeup)
: :
Child_service(server_id_space, factory, name, Async_service(name, server_id_space, factory, wakeup),
Ram_session_capability(), wakeup), _child_name(child_name),
_child_name(child_name), _ram_accessor(ram_accessor), _ram_accessor(ram_accessor),
_factory(factory), _registry_element(services, *this) _factory(factory), _registry_element(services, *this)
{ } { }
Child_name const &child_name() const { return _child_name; } 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 * Ram_transfer::Account interface
*
* This accessor is solely meant to be used by 'Forwarded_service' to
* allocate session-state objects for sessions requested by init's
* parent.
*/ */
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_ */ #endif /* _SRC__INIT__SERVICE_H_ */

View File

@ -36,7 +36,7 @@ struct Test::Policy
Policy(Env &env, Name const &name) Policy(Env &env, Name const &name)
: :
Slave::Policy(name, name, *this, env.ep().rpc_ep(), env.rm(), 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", Slave::Policy(Label("child"), "test-resource_yield",
*this, env.ep().rpc_ep(), env.rm(), *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) _parent(parent)
{ {
configure("<config child=\"yes\" />"); configure("<config child=\"yes\" />");