genode/repos/base/include/base/quota_transfer.h

155 lines
3.9 KiB
C
Raw Normal View History

/*
* \brief Utility for implementing transactional quota transfers
* \author Norman Feske
* \date 2017-04-28
*/
/*
* Copyright (C) 2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _INCLUDE__BASE__QUOTA_TRANSFER_H_
#define _INCLUDE__BASE__QUOTA_TRANSFER_H_
#include <base/capability.h>
#include <ram_session/ram_session.h>
#include <pd_session/pd_session.h>
namespace Genode {
template <typename SESSION, typename UNIT> class Quota_transfer;
typedef Quota_transfer<Ram_session, Ram_quota> Ram_transfer;
typedef Quota_transfer<Pd_session, Cap_quota> Cap_transfer;
}
/**
* Guard for transferring quota donation
*
* This class template is used to transfer quotas in a transactional way.
* 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 instantiated at a local scope, a
* transfer object guards a quota transfer. If the scope is left without an
* explicit prior acknowledgement of the transfer (for example via an
* exception), the destructor the transfer object reverts the transfer in
* flight.
*/
template <typename SESSION, typename UNIT>
class Genode::Quota_transfer
{
public:
class Quota_exceeded : Exception { };
Follow practices suggested by "Effective C++" The patch adjust the code of the base, base-<kernel>, and os repository. To adapt existing components to fix violations of the best practices suggested by "Effective C++" as reported by the -Weffc++ compiler argument. The changes follow the patterns outlined below: * A class with virtual functions can no longer publicly inherit base classed without a vtable. The inherited object may either be moved to a member variable, or inherited privately. The latter would be used for classes that inherit 'List::Element' or 'Avl_node'. In order to enable the 'List' and 'Avl_tree' to access the meta data, the 'List' must become a friend. * Instead of adding a virtual destructor to abstract base classes, we inherit the new 'Interface' class, which contains a virtual destructor. This way, single-line abstract base classes can stay as compact as they are now. The 'Interface' utility resides in base/include/util/interface.h. * With the new warnings enabled, all member variables must be explicitly initialized. Basic types may be initialized with '='. All other types are initialized with braces '{ ... }' or as class initializers. If basic types and non-basic types appear in a row, it is nice to only use the brace syntax (also for basic types) and align the braces. * If a class contains pointers as members, it must now also provide a copy constructor and assignment operator. In the most cases, one would make them private, effectively disallowing the objects to be copied. Unfortunately, this warning cannot be fixed be inheriting our existing 'Noncopyable' class (the compiler fails to detect that the inheriting class cannot be copied and still gives the error). For now, we have to manually add declarations for both the copy constructor and assignment operator as private class members. Those declarations should be prepended with a comment like this: /* * Noncopyable */ Thread(Thread const &); Thread &operator = (Thread const &); In the future, we should revisit these places and try to replace the pointers with references. In the presence of at least one reference member, the compiler would no longer implicitly generate a copy constructor. So we could remove the manual declaration. Issue #465
2017-12-21 15:42:15 +01:00
struct Account : Noncopyable, Interface
{
/**
* Return capability used for transfers to the account
*
* The 'UNIT' argument is solely used as an overload selector
* to disambiguate the 'cap' methods of multiple inherited
* 'Account' types (as done by 'Service').
*/
virtual Capability<SESSION> cap(UNIT) const
{
return Capability<SESSION>();
}
/**
* Transfer quota to the specified account
*
* \throw Out_of_ram
* \throw Out_of_caps
* \throw Invalid_session
* \throw Undefined_ref_account
*/
Follow practices suggested by "Effective C++" The patch adjust the code of the base, base-<kernel>, and os repository. To adapt existing components to fix violations of the best practices suggested by "Effective C++" as reported by the -Weffc++ compiler argument. The changes follow the patterns outlined below: * A class with virtual functions can no longer publicly inherit base classed without a vtable. The inherited object may either be moved to a member variable, or inherited privately. The latter would be used for classes that inherit 'List::Element' or 'Avl_node'. In order to enable the 'List' and 'Avl_tree' to access the meta data, the 'List' must become a friend. * Instead of adding a virtual destructor to abstract base classes, we inherit the new 'Interface' class, which contains a virtual destructor. This way, single-line abstract base classes can stay as compact as they are now. The 'Interface' utility resides in base/include/util/interface.h. * With the new warnings enabled, all member variables must be explicitly initialized. Basic types may be initialized with '='. All other types are initialized with braces '{ ... }' or as class initializers. If basic types and non-basic types appear in a row, it is nice to only use the brace syntax (also for basic types) and align the braces. * If a class contains pointers as members, it must now also provide a copy constructor and assignment operator. In the most cases, one would make them private, effectively disallowing the objects to be copied. Unfortunately, this warning cannot be fixed be inheriting our existing 'Noncopyable' class (the compiler fails to detect that the inheriting class cannot be copied and still gives the error). For now, we have to manually add declarations for both the copy constructor and assignment operator as private class members. Those declarations should be prepended with a comment like this: /* * Noncopyable */ Thread(Thread const &); Thread &operator = (Thread const &); In the future, we should revisit these places and try to replace the pointers with references. In the presence of at least one reference member, the compiler would no longer implicitly generate a copy constructor. So we could remove the manual declaration. Issue #465
2017-12-21 15:42:15 +01:00
virtual void transfer(Capability<SESSION>, UNIT) { }
/**
* Try to transfer quota, ignoring possible exceptions
*
* This method is solely meant to be used in destructors.
*/
void try_transfer(Capability<SESSION> to, UNIT amount)
{
try { transfer(to, amount); } catch (...) { }
}
};
/**
* Account implementation that issues quota transfers via RPC
*/
struct Remote_account : Account
{
Capability<SESSION> _cap;
SESSION &_session;
Remote_account(SESSION &session, Capability<SESSION> cap)
: _cap(cap), _session(session) { }
Capability<SESSION> cap(UNIT) const override { return _cap; }
void transfer(Capability<SESSION> to, UNIT amount) override
{
if (to.valid()) _session.transfer_quota(to, amount);
}
};
private:
bool _ack;
UNIT const _amount;
Account &_from;
Account &_to;
public:
/**
* Constructor
*
* \param amount amount of quota to transfer
* \param from donor account
* \param to receiving account
*/
Quota_transfer(UNIT amount, Account &from, Account &to)
:
_ack(false), _amount(amount), _from(from), _to(to)
{
if (!_from.cap(UNIT()).valid() || !_to.cap(UNIT()).valid())
return;
try { _from.transfer(_to.cap(UNIT()), amount); }
catch (typename SESSION::Undefined_ref_account) { }
catch (typename SESSION::Invalid_session) { }
catch (... /* 'Out_of_ram' / 'Out_of_caps' */) {
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.
*/
~Quota_transfer()
{
if (_ack || !_from.cap(UNIT()).valid() || !_to.cap(UNIT()).valid())
return;
_to.try_transfer(_from.cap(UNIT()), _amount);
}
/**
* Acknowledge quota donation
*/
void acknowledge() { _ack = true; }
};
#endif /* _INCLUDE__BASE__QUOTA_TRANSFER_H_ */