mirror of
https://github.com/genodelabs/genode.git
synced 2025-06-18 23:28:29 +00:00
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:
committed by
Christian Helmuth
parent
5c43074bc6
commit
3670f7735d
@ -445,7 +445,7 @@ class Genode::Child : protected Rpc_object<Parent>,
|
||||
|
||||
Env_service(Child &child, Service &service)
|
||||
:
|
||||
Genode::Service(CONNECTION::service_name(), service.ram()),
|
||||
Genode::Service(CONNECTION::service_name()),
|
||||
_child(child), _service(service)
|
||||
{ }
|
||||
|
||||
@ -469,6 +469,23 @@ class Genode::Child : protected Rpc_object<Parent>,
|
||||
_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(); }
|
||||
|
||||
bool operator == (Service const &other) const override
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <base/session_state.h>
|
||||
#include <base/log.h>
|
||||
#include <base/registry.h>
|
||||
#include <base/quota_transfer.h>
|
||||
|
||||
namespace Genode {
|
||||
|
||||
@ -27,11 +28,12 @@ namespace Genode {
|
||||
template <typename> class Session_factory;
|
||||
template <typename> class Local_service;
|
||||
class Parent_service;
|
||||
class Async_service;
|
||||
class Child_service;
|
||||
}
|
||||
|
||||
|
||||
class Genode::Service : Noncopyable
|
||||
class Genode::Service : public Ram_transfer::Account
|
||||
{
|
||||
public:
|
||||
|
||||
@ -39,8 +41,7 @@ class Genode::Service : Noncopyable
|
||||
|
||||
private:
|
||||
|
||||
Name const _name;
|
||||
Ram_session_capability const _ram;
|
||||
Name const _name;
|
||||
|
||||
protected:
|
||||
|
||||
@ -64,10 +65,8 @@ class Genode::Service : Noncopyable
|
||||
* Constructor
|
||||
*
|
||||
* \param name service name
|
||||
* \param ram RAM session to receive/withdraw session quota
|
||||
*/
|
||||
Service(Name const &name, Ram_session_capability ram)
|
||||
: _name(name), _ram(ram) { }
|
||||
Service(Name const &name) : _name(name) { }
|
||||
|
||||
virtual ~Service() { }
|
||||
|
||||
@ -104,11 +103,6 @@ class Genode::Service : Noncopyable
|
||||
*/
|
||||
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; }
|
||||
};
|
||||
|
||||
@ -181,10 +175,7 @@ class Genode::Local_service : public Service
|
||||
* Constructor
|
||||
*/
|
||||
Local_service(Factory &factory)
|
||||
:
|
||||
Service(SESSION::service_name(), Ram_session_capability()),
|
||||
_factory(factory)
|
||||
{ }
|
||||
: Service(SESSION::service_name()), _factory(factory) { }
|
||||
|
||||
void initiate_request(Session_state &session) override
|
||||
{
|
||||
@ -235,6 +226,7 @@ class Genode::Local_service : public Service
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
@ -257,7 +249,7 @@ class Genode::Parent_service : public Service
|
||||
* Constructor
|
||||
*/
|
||||
Parent_service(Env &env, Service::Name const &name)
|
||||
: Service(name, Ram_session_capability()), _env(env) { }
|
||||
: Service(name), _env(env) { }
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@ -265,7 +257,7 @@ class Genode::Parent_service : public Service
|
||||
* \deprecated
|
||||
*/
|
||||
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
|
||||
{
|
||||
@ -284,6 +276,9 @@ class Genode::Parent_service : public Service
|
||||
|
||||
session.phase = Session_state::AVAILABLE;
|
||||
}
|
||||
catch (Out_of_ram) {
|
||||
session.id_at_parent.destruct();
|
||||
session.phase = Session_state::INVALID_ARGS; }
|
||||
catch (Insufficient_ram_quota) {
|
||||
session.id_at_parent.destruct();
|
||||
session.phase = Session_state::INSUFFICIENT_RAM_QUOTA; }
|
||||
@ -304,7 +299,7 @@ class Genode::Parent_service : public Service
|
||||
try {
|
||||
_env.upgrade(session.id_at_parent->id(), args.string()); }
|
||||
catch (Out_of_ram) {
|
||||
warning("quota exceeded while upgrading parent session"); }
|
||||
warning("RAM quota exceeded while upgrading parent session"); }
|
||||
|
||||
session.confirm_ram_upgrade();
|
||||
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:
|
||||
|
||||
struct Wakeup { virtual void wakeup_child_service() = 0; };
|
||||
struct Wakeup { virtual void wakeup_async_service() = 0; };
|
||||
|
||||
private:
|
||||
|
||||
@ -360,24 +355,20 @@ class Genode::Child_service : public Service
|
||||
|
||||
public:
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param factory server-side session-state factory
|
||||
* \param name name of service
|
||||
* \param ram recipient of session quota
|
||||
* \param wakeup callback to be notified on the arrival of new
|
||||
* 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,
|
||||
Service::Name const &name,
|
||||
Ram_session_capability ram,
|
||||
Wakeup &wakeup)
|
||||
:
|
||||
Service(name, ram),
|
||||
Service(name),
|
||||
_server_id_space(server_id_space),
|
||||
_server_factory(factory), _wakeup(wakeup)
|
||||
{ }
|
||||
@ -395,7 +386,46 @@ class Genode::Child_service : public Service
|
||||
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_ */
|
||||
|
@ -12,84 +12,11 @@
|
||||
*/
|
||||
|
||||
#include <base/child.h>
|
||||
#include <base/quota_transfer.h>
|
||||
|
||||
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 **
|
||||
***********/
|
||||
@ -270,12 +197,14 @@ Session_capability Child::session(Parent::Client::Id id,
|
||||
session.closed_callback = this;
|
||||
|
||||
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 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 donation_to_service(forward_ram_quota, _policy.ref_ram_cap(),
|
||||
service.ram());
|
||||
Ram_transfer ram_donation_to_service(forward_ram_quota, ref_ram_account, service);
|
||||
|
||||
/* try to dispatch session request synchronously */
|
||||
service.initiate_request(session);
|
||||
@ -291,13 +220,13 @@ Session_capability Child::session(Parent::Client::Id id,
|
||||
}
|
||||
|
||||
/* finish transaction */
|
||||
donation_from_child.acknowledge();
|
||||
donation_to_service.acknowledge();
|
||||
ram_donation_from_child.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();
|
||||
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) };
|
||||
|
||||
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 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 donation_to_service(ram_quota, _policy.ref_ram_cap(),
|
||||
session.service().ram());
|
||||
Ram_transfer ram_donation_to_service(ram_quota, ref_ram_account, session.service());
|
||||
|
||||
session.increase_donated_quota(ram_quota);
|
||||
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);
|
||||
|
||||
/* finish transaction */
|
||||
donation_from_child.acknowledge();
|
||||
donation_to_service.acknowledge();
|
||||
ram_donation_from_child.acknowledge();
|
||||
ram_donation_to_service.acknowledge();
|
||||
}
|
||||
catch (Transfer::Quota_exceeded) {
|
||||
warning(_policy.name(), ": upgrade of ", session.service().name(), " failed");
|
||||
catch (Ram_transfer::Quota_exceeded) {
|
||||
warning(_policy.name(), ": RAM upgrade of ", session.service().name(), " failed");
|
||||
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)
|
||||
{
|
||||
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 {
|
||||
/* transfer session quota from the service to ourself */
|
||||
Transfer donation_from_service(session.donated_ram_quota(),
|
||||
session.service().ram(), _policy.ref_ram_cap());
|
||||
Ram_transfer ram_donation_from_service(session.donated_ram_quota(),
|
||||
service_ram_account, ref_ram_account);
|
||||
|
||||
/*
|
||||
* 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
|
||||
* ('session_costs').
|
||||
*/
|
||||
Transfer donation_to_client(Ram_quota{session.donated_ram_quota().value +
|
||||
_session_factory.session_costs()},
|
||||
_policy.ref_ram_cap(), ram_session_cap());
|
||||
Ram_quota const returned_ram { session.donated_ram_quota().value +
|
||||
_session_factory.session_costs() };
|
||||
|
||||
Ram_transfer ram_donation_to_client(returned_ram,
|
||||
ref_ram_account, child_ram_account);
|
||||
/* finish transaction */
|
||||
donation_from_service.acknowledge();
|
||||
donation_to_client.acknowledge();
|
||||
ram_donation_from_service.acknowledge();
|
||||
ram_donation_to_client.acknowledge();
|
||||
}
|
||||
catch (Transfer::Quota_exceeded) {
|
||||
warning(_policy.name(), ": could not revert session quota (", session, ")"); }
|
||||
catch (Ram_transfer::Quota_exceeded) {
|
||||
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();
|
||||
_policy.session_state_changed();
|
||||
|
Reference in New Issue
Block a user