base: introduce Ram_allocator::try_alloc

This patch replaces the 'Ram_allocator::alloc' RPC function by a
'try_alloc' function, which reflects errors as 'Attempt' return value
instead of an exception.

Issue #4322
Issue #3612
This commit is contained in:
Norman Feske 2021-11-08 21:05:11 +01:00 committed by Christian Helmuth
parent 959bcae557
commit 231ac187fe
20 changed files with 324 additions and 122 deletions

View File

@ -79,7 +79,7 @@ class Stack_area_region_map : public Genode::Region_map
struct Stack_area_ram_allocator : Genode::Ram_allocator
{
Genode::Ram_dataspace_capability alloc(Genode::size_t, Genode::Cache) override {
Alloc_result try_alloc(Genode::size_t, Genode::Cache) override {
return Genode::Ram_dataspace_capability(); }
void free(Genode::Ram_dataspace_capability) override { }

View File

@ -114,7 +114,7 @@ class Stack_area_region_map : public Region_map
struct Stack_area_ram_allocator : Ram_allocator
{
Ram_dataspace_capability alloc(size_t, Cache) override {
Alloc_result try_alloc(size_t, Cache) override {
return reinterpret_cap_cast<Ram_dataspace>(Native_capability()); }
void free(Ram_dataspace_capability) override {

View File

@ -14,10 +14,11 @@
#ifndef _INCLUDE__BASE__IPC_H_
#define _INCLUDE__BASE__IPC_H_
#include <util/attempt.h>
#include <util/meta.h>
#include <base/ipc_msgbuf.h>
#include <base/rpc_args.h>
#include <base/log.h>
#include <util/meta.h>
namespace Genode {
@ -156,6 +157,18 @@ class Genode::Ipc_unmarshaller : Noncopyable
return value;
}
/**
* Read 'Attempt' return value from buffer
*/
template <typename RESULT, typename ERROR>
Attempt<RESULT, ERROR> extract(Meta::Overload_selector<Attempt<RESULT, ERROR> >)
{
bool const ok = extract(Meta::Overload_selector<bool>());
if (ok) return extract(Meta::Overload_selector<RESULT>());
else return extract(Meta::Overload_selector<ERROR>());
}
Ipc_unmarshaller(Msgbuf_base &rcv_msg) : _rcv_msg(rcv_msg) { }
};

View File

@ -14,6 +14,7 @@
#ifndef _INCLUDE__BASE__IPC_MSGBUF_H_
#define _INCLUDE__BASE__IPC_MSGBUF_H_
#include <util/attempt.h>
#include <util/noncopyable.h>
#include <base/capability.h>
#include <base/exception.h>
@ -225,6 +226,17 @@ class Genode::Msgbuf_base : Noncopyable
Native_capability untyped_cap = typed_cap;
insert(untyped_cap);
}
/**
* Insert 'Attempt' return value into message buffer
*/
template <typename RESULT, typename ERROR>
void insert(Attempt<RESULT, ERROR> const &attempt)
{
insert(attempt.ok());
attempt.with_result([&] (RESULT result) { insert(result); },
[&] (ERROR error) { insert(error); });
}
};

View File

@ -40,6 +40,11 @@ namespace Genode {
class Quota_guard_untyped;
template <typename> class Quota_guard;
struct Reservation : Interface
{
virtual void cancel() = 0;
};
}
@ -121,6 +126,38 @@ class Genode::Quota_guard_untyped
/* clamp lower bound of used value to zero */
_used = underflow ? 0 : _used - amount;
}
/**
* Guard for rolling back a quota reservation
*/
class Reservation_guard : public Reservation, Noncopyable
{
private:
Quota_guard_untyped &_quota_guard;
size_t const _amount;
bool _canceled = false;
public:
Reservation_guard(Quota_guard_untyped &quota_guard, size_t const amount)
:
_quota_guard(quota_guard), _amount(amount)
{ }
~Reservation_guard()
{
if (_canceled)
_quota_guard.replenish(_amount);
}
/**
* Reservation interface
*/
void cancel() override { _canceled = true; }
};
};
@ -179,6 +216,11 @@ class Genode::Quota_guard
/**
* Utility used for transactional multi-step resource allocations
*
* \deprecated Use 'with_reservation' instead
*
* Note that this class is not related to the 'Genode::Reservation'
* interface.
*/
struct Reservation
{
@ -206,6 +248,33 @@ class Genode::Quota_guard
void acknowledge() { _ack = true; }
};
template <typename RET, typename FN, typename ERROR_FN>
RET with_reservation(UNIT const amount,
FN const &fn,
ERROR_FN const &error_fn)
{
if (!_guard.try_withdraw(amount.value))
return error_fn();
/*
* The withdrawal was successful. Use reservation guard to
* rollback the withdrawal depending on 'fn'.
*/
Quota_guard_untyped::Reservation_guard
reservation_guard { _guard, amount.value };
/* expose only the 'Reservation' interface to 'fn' */
::Genode::Reservation &interface = reservation_guard;
return fn(interface);
}
bool have_avail(UNIT const amount) const
{
return _guard.avail() >= amount.value;
}
};

View File

@ -14,6 +14,7 @@
#ifndef _INCLUDE__BASE__RAM_ALLOCATOR_H_
#define _INCLUDE__BASE__RAM_ALLOCATOR_H_
#include <util/attempt.h>
#include <base/capability.h>
#include <base/quota_guard.h>
#include <base/cache.h>
@ -33,6 +34,23 @@ namespace Genode {
struct Genode::Ram_allocator : Interface
{
enum class Alloc_error { OUT_OF_RAM, OUT_OF_CAPS, DENIED };
using Alloc_result = Attempt<Ram_dataspace_capability, Alloc_error>;
struct Denied : Exception { };
/**
* Allocate RAM dataspace
*
* \param size size of RAM dataspace
* \param cache selects cacheability attributes of the memory,
* uncached memory, i.e., for DMA buffers
*
* \return capability to RAM dataspace, or error code of type 'Alloc_error'
*/
virtual Alloc_result try_alloc(size_t size, Cache cache = CACHED) = 0;
/**
* Allocate RAM dataspace
*
@ -42,10 +60,25 @@ struct Genode::Ram_allocator : Interface
*
* \throw Out_of_ram
* \throw Out_of_caps
* \throw Denied
*
* \return capability to new RAM dataspace
*/
virtual Ram_dataspace_capability alloc(size_t size, Cache cache = CACHED) = 0;
Ram_dataspace_capability alloc(size_t size, Cache cache = CACHED)
{
return try_alloc(size, cache).convert<Ram_dataspace_capability>(
[&] (Ram_dataspace_capability cap) {
return cap; },
[&] (Alloc_error error) -> Ram_dataspace_capability {
switch (error) {
case Alloc_error::OUT_OF_RAM: throw Out_of_ram();
case Alloc_error::OUT_OF_CAPS: throw Out_of_caps();
case Alloc_error::DENIED: break;
}
throw Denied();
});
}
/**
* Free RAM dataspace
@ -57,7 +90,7 @@ struct Genode::Ram_allocator : Interface
/**
* Return size of dataspace in bytes
*/
virtual size_t dataspace_size(Ram_dataspace_capability ds) const = 0;
virtual size_t dataspace_size(Ram_dataspace_capability) const = 0;
};
@ -81,22 +114,44 @@ class Genode::Constrained_ram_allocator : public Ram_allocator
_ram_alloc(ram_alloc), _ram_guard(ram_guard), _cap_guard(cap_guard)
{ }
Ram_dataspace_capability alloc(size_t size, Cache cache = CACHED) override
Alloc_result try_alloc(size_t size, Cache cache = CACHED) override
{
size_t page_aligned_size = align_addr(size, 12);
using Result = Alloc_result;
Ram_quota_guard::Reservation ram (_ram_guard, Ram_quota{page_aligned_size});
Cap_quota_guard::Reservation caps(_cap_guard, Cap_quota{1});
size_t const page_aligned_size = align_addr(size, 12);
/*
* \throw Out_of_caps, Out_of_ram
*/
Ram_dataspace_capability ds = _ram_alloc.alloc(page_aligned_size, cache);
Ram_quota const needed_ram { page_aligned_size };
Cap_quota const needed_caps { 1 };
ram. acknowledge();
caps.acknowledge();
return _ram_guard.with_reservation<Result>(needed_ram,
return ds;
[&] (Reservation &ram_reservation) {
return _cap_guard.with_reservation<Result>(needed_caps,
[&] (Reservation &cap_reservation) -> Result {
return _ram_alloc.try_alloc(page_aligned_size, cache)
.convert<Result>(
[&] (Ram_dataspace_capability ds) -> Result {
return ds; },
[&] (Alloc_error error) {
cap_reservation.cancel();
ram_reservation.cancel();
return error; }
);
},
[&] () -> Result {
ram_reservation.cancel();
return Alloc_error::OUT_OF_CAPS;
}
);
},
[&] () -> Result {
return Alloc_error::OUT_OF_RAM; }
);
}
void free(Ram_dataspace_capability ds) override

View File

@ -21,8 +21,8 @@ namespace Genode {
template <typename> struct Rpc_client;
/**
* Count capabilities of a RPC_FUNCTION which are out parameters.
/*
* Number of capabilities received by RPC_FUNCTION as out parameters
*/
template <typename T> struct Cap_para_out { enum { Value = 0 }; };
template <typename T> struct Cap_para_out<Capability<T> *> { enum { Value = 1 }; };
@ -30,6 +30,9 @@ namespace Genode {
template <> struct Cap_para_out<Native_capability *> { enum { Value = 1 }; };
template <> struct Cap_para_out<Native_capability &> { enum { Value = 1 }; };
/*
* Presence of capability received as return value from RPC_FUNCTION
*/
template <typename T> struct Cap_return { enum { Value = 0 }; };
template <typename T> struct Cap_return<Capability<T> > { enum { Value = 1 }; };
template <typename T> struct Cap_return<Capability<T> *> { enum { Value = 1 }; };
@ -38,11 +41,17 @@ namespace Genode {
template <> struct Cap_return<Native_capability *> { enum { Value = 1 }; };
template <> struct Cap_return<Native_capability &> { enum { Value = 1 }; };
/*
* Presence of capability received as 'Attempt' return value from RPC_FUNCTION
*/
template <typename T, typename E>
struct Cap_return<Attempt<T, E> > { enum { Value = Cap_return<T>::Value }; };
template <typename ARGS>
struct Rpc_caps_out {
enum { Value = Cap_para_out<typename ARGS::Head>::Value
+ Rpc_caps_out<typename ARGS::Tail>::Value }; };
template <>
struct Rpc_caps_out<Meta::Empty> { enum { Value = 0 }; };
@ -51,6 +60,7 @@ namespace Genode {
enum { Value = Rpc_caps_out<typename RPC_FUNCTION::Server_args>::Value +
Cap_return <typename RPC_FUNCTION::Ret_type>::Value}; };
/***************************************************
** Implementation of 'Capability:call' functions **
***************************************************/

View File

@ -73,9 +73,9 @@ struct Genode::Pd_session_client : Rpc_client<Pd_session>
Cap_quota cap_quota() const override { return call<Rpc_cap_quota>(); }
Cap_quota used_caps() const override { return call<Rpc_used_caps>(); }
Ram_dataspace_capability alloc(size_t size, Cache cache = CACHED) override
Alloc_result try_alloc(size_t size, Cache cache = CACHED) override
{
return call<Rpc_alloc>(size, cache);
return call<Rpc_try_alloc>(size, cache);
}
void free(Ram_dataspace_capability ds) override { call<Rpc_free>(ds); }

View File

@ -15,6 +15,7 @@
#ifndef _INCLUDE__PD_SESSION__PD_SESSION_H_
#define _INCLUDE__PD_SESSION__PD_SESSION_H_
#include <util/attempt.h>
#include <base/exception.h>
#include <cpu/cpu_state.h>
#include <session/session.h>
@ -348,9 +349,7 @@ struct Genode::Pd_session : Session, Ram_allocator
GENODE_RPC(Rpc_cap_quota, Cap_quota, cap_quota);
GENODE_RPC(Rpc_used_caps, Cap_quota, used_caps);
GENODE_RPC_THROW(Rpc_alloc, Ram_dataspace_capability, alloc,
GENODE_TYPE_LIST(Out_of_ram, Out_of_caps, Undefined_ref_account),
size_t, Cache);
GENODE_RPC(Rpc_try_alloc, Alloc_result, try_alloc, size_t, Cache);
GENODE_RPC(Rpc_free, void, free, Ram_dataspace_capability);
GENODE_RPC_THROW(Rpc_transfer_ram_quota, void, transfer_quota,
GENODE_TYPE_LIST(Out_of_ram, Invalid_session, Undefined_ref_account),
@ -369,7 +368,7 @@ struct Genode::Pd_session : Session, Ram_allocator
Rpc_alloc_rpc_cap, Rpc_free_rpc_cap, Rpc_address_space,
Rpc_stack_area, Rpc_linker_area, Rpc_ref_account,
Rpc_transfer_cap_quota, Rpc_cap_quota, Rpc_used_caps,
Rpc_alloc, Rpc_free,
Rpc_try_alloc, Rpc_free,
Rpc_transfer_ram_quota, Rpc_ram_quota, Rpc_used_ram,
Rpc_native_pd, Rpc_managing_system);
};

View File

@ -315,7 +315,7 @@ class Genode::Pd_session_component : public Session_object<Pd_session>
** RAM allocation and accounting **
***********************************/
Ram_dataspace_capability alloc(size_t, Cache) override;
Alloc_result try_alloc(size_t, Cache) override;
void free(Ram_dataspace_capability) override;

View File

@ -106,7 +106,7 @@ class Genode::Ram_dataspace_factory : public Ram_allocator,
** Ram_allocator interface **
*****************************/
Ram_dataspace_capability alloc(size_t, Cache) override;
Alloc_result try_alloc(size_t, Cache) override;
void free(Ram_dataspace_capability) override;
size_t dataspace_size(Ram_dataspace_capability ds) const override;
};

View File

@ -33,10 +33,10 @@ class Genode::Synced_ram_allocator : public Ram_allocator
Synced_ram_allocator(Ram_allocator &alloc) : _alloc(alloc) { }
Ram_dataspace_capability alloc(size_t size, Cache cache) override
Alloc_result try_alloc(size_t size, Cache cache) override
{
Mutex::Guard mutex_guard(_mutex);
return _alloc.alloc(size, cache);
return _alloc.try_alloc(size, cache);
}
void free(Ram_dataspace_capability ds) override

View File

@ -20,57 +20,57 @@
using namespace Genode;
Ram_dataspace_capability
Pd_session_component::alloc(size_t ds_size, Cache cache)
Ram_allocator::Alloc_result
Pd_session_component::try_alloc(size_t ds_size, Cache cache)
{
/* zero-sized dataspaces are not allowed */
if (!ds_size) return Ram_dataspace_capability();
if (!ds_size)
return Alloc_error::DENIED;
/* dataspace allocation granularity is page size */
ds_size = align_addr(ds_size, 12);
/*
* Track quota usage
*
* We use a guard to roll back the withdrawal of the quota whenever
* we leave the method scope via an exception. The withdrawal is
* acknowledge just before successfully leaving the method.
*/
Ram_quota_guard::Reservation
dataspace_ram_costs(_ram_quota_guard(), Ram_quota{ds_size});
using Result = Ram_allocator::Alloc_result;
using Reservation = Genode::Reservation;
/*
* In the worst case, we need to allocate a new slab block for the
* meta data of the dataspace to be created. Therefore, we temporarily
* withdraw the slab block size here to trigger an exception if the
* account does not have enough room for the meta data.
*/
{
Ram_quota const overhead { Ram_dataspace_factory::SLAB_BLOCK_SIZE };
Ram_quota_guard::Reservation sbs_ram_costs(_ram_quota_guard(), overhead);
}
/* track quota use */
return _ram_quota_guard().with_reservation<Result>(Ram_quota{ds_size},
/*
* Each dataspace is an RPC object and thereby consumes a capability.
*/
Cap_quota_guard::Reservation
dataspace_cap_costs(_cap_quota_guard(), Cap_quota{1});
[&] (Reservation &ram_reservation) -> Result {
/*
* Allocate physical dataspace
*
* \throw Out_of_ram
* \throw Out_of_caps
*/
Ram_dataspace_capability ram_ds = _ram_ds_factory.alloc(ds_size, cache);
/*
* In the worst case, we need to allocate a new slab block for
* the meta data of the dataspace to be created. Therefore, we
* temporarily withdraw the slab block size here to trigger an
* exception if the account does not have enough room for the meta
* data.
*/
Ram_quota const overhead { Ram_dataspace_factory::SLAB_BLOCK_SIZE };
/*
* We returned from '_ram_ds_factory.alloc' with a valid dataspace.
*/
dataspace_ram_costs.acknowledge();
dataspace_cap_costs.acknowledge();
if (!_ram_quota_guard().have_avail(overhead)) {
ram_reservation.cancel();
return Ram_allocator::Alloc_error::OUT_OF_RAM;
}
return ram_ds;
/*
* Each dataspace is an RPC object and thereby consumes a
* capability.
*/
return _cap_quota_guard().with_reservation<Result>(Cap_quota{1},
[&] (Genode::Reservation &) -> Result {
return _ram_ds_factory.try_alloc(ds_size, cache);
},
[&] () -> Result {
ram_reservation.cancel();
return Ram_allocator::Alloc_error::OUT_OF_CAPS;
}
);
},
[&] () -> Result {
return Ram_allocator::Alloc_error::OUT_OF_RAM;
}
);
}

View File

@ -20,11 +20,12 @@
using namespace Genode;
Ram_dataspace_capability
Ram_dataspace_factory::alloc(size_t ds_size, Cache cache)
Ram_allocator::Alloc_result
Ram_dataspace_factory::try_alloc(size_t ds_size, Cache cache)
{
/* zero-sized dataspaces are not allowed */
if (!ds_size) return Ram_dataspace_capability();
if (!ds_size)
return Alloc_error::DENIED;
/* dataspace allocation granularity is page size */
ds_size = align_addr(ds_size, 12);
@ -59,7 +60,7 @@ Ram_dataspace_factory::alloc(size_t ds_size, Cache cache)
}
}
/* apply constraints or re-try because higher memory allocation failed */
/* apply constraints, or retry if larger memory allocation failed */
if (!alloc_succeeded) {
for (size_t align_log2 = log2(ds_size); align_log2 >= 12; align_log2--) {
if (_phys_alloc.alloc_aligned(ds_size, &ds_addr, align_log2,
@ -106,19 +107,24 @@ Ram_dataspace_factory::alloc(size_t ds_size, Cache cache)
if (!alloc_succeeded) {
error("out of physical memory while allocating ", ds_size, " bytes ",
"in range [", Hex(_phys_range.start), "-", Hex(_phys_range.end), "]");
throw Out_of_ram();
return Alloc_error::OUT_OF_RAM;
}
/*
* For non-cached RAM dataspaces, we mark the dataspace as write
* combined and expect the pager to evaluate this dataspace property
* when resolving page faults.
*
* \throw Out_of_ram
* \throw Out_of_caps
*/
Dataspace_component &ds = *new (_ds_slab)
Dataspace_component(ds_size, (addr_t)ds_addr, cache, true, this);
Dataspace_component *ds_ptr = nullptr;
try {
ds_ptr = new (_ds_slab)
Dataspace_component(ds_size, (addr_t)ds_addr, cache, true, this);
}
catch (Out_of_ram) { return Alloc_error::OUT_OF_RAM; }
catch (Out_of_caps) { return Alloc_error::OUT_OF_CAPS; }
catch (...) { return Alloc_error::DENIED; }
Dataspace_component &ds = *ds_ptr;
/* create native shared memory representation of dataspace */
try { _export_ram_ds(ds); }
@ -127,7 +133,7 @@ Ram_dataspace_factory::alloc(size_t ds_size, Cache cache)
/* cleanup unneeded resources */
destroy(_ds_slab, &ds);
throw Out_of_ram();
return Alloc_error::DENIED;
}
/*
@ -137,11 +143,11 @@ Ram_dataspace_factory::alloc(size_t ds_size, Cache cache)
*/
_clear_ds(ds);
Dataspace_capability result = _ep.manage(&ds);
Dataspace_capability ds_cap = _ep.manage(&ds);
phys_alloc_guard.ack = true;
return static_cap_cast<Ram_dataspace>(result);
return static_cap_cast<Ram_dataspace>(ds_cap);
}

View File

@ -121,7 +121,7 @@ class Stack_area_region_map : public Region_map
struct Stack_area_ram_allocator : Ram_allocator
{
Ram_dataspace_capability alloc(size_t, Cache) override {
Alloc_result try_alloc(size_t, Cache) override {
return reinterpret_cap_cast<Ram_dataspace>(Native_capability()); }
void free(Ram_dataspace_capability) override { }

View File

@ -38,36 +38,49 @@ struct Genode::Expanding_pd_session_client : Pd_session_client
Expanding_pd_session_client(Parent &parent, Pd_session_capability cap)
: Pd_session_client(cap), _parent(parent) { }
Ram_dataspace_capability alloc(size_t size, Cache cache = UNCACHED) override
Alloc_result try_alloc(size_t size, Cache cache = UNCACHED) override
{
/*
* If the RAM session runs out of quota, issue a resource request
* If the PD session runs out of quota, issue a resource request
* to the parent and retry.
*/
enum { NUM_ATTEMPTS = 10 };
enum { UPGRADE_CAPS = 4 };
return retry<Out_of_ram>(
[&] () {
return retry<Out_of_caps>(
[&] () { return Pd_session_client::alloc(size, cache); },
[&] () { _request_caps_from_parent(UPGRADE_CAPS); },
NUM_ATTEMPTS);
},
[&] () {
/*
* The RAM service withdraws the meta data for the allocator
* from the RAM quota. In the worst case, a new slab block
* may be needed. To cover the worst case, we need to take
* this possible overhead into account when requesting
* additional RAM quota from the parent.
*
* Because the worst case almost never happens, we request
* a bit too much quota for the most time.
*/
enum { OVERHEAD = 4096UL };
_request_ram_from_parent(size + OVERHEAD);
},
NUM_ATTEMPTS);
for (;;) {
Alloc_result const result = Pd_session_client::try_alloc(size, cache);
if (result.ok())
return result;
bool denied = false;
result.with_error(
[&] (Alloc_error error) {
switch (error) {
case Alloc_error::OUT_OF_RAM:
/*
* The RAM service withdraws the meta data for the allocator
* from the RAM quota. In the worst case, a new slab block
* may be needed. To cover the worst case, we need to take
* this possible overhead into account when requesting
* additional RAM quota from the parent.
*
* Because the worst case almost never happens, we request
* a bit too much quota for the most time.
*/
enum { OVERHEAD = 4096UL };
_request_ram_from_parent(size + OVERHEAD);
break;
case Alloc_error::OUT_OF_CAPS:
_request_caps_from_parent(4);
break;
case Alloc_error::DENIED:
denied = true;
}
});
if (denied)
return Alloc_error::DENIED;
}
}
void transfer_quota(Pd_session_capability pd_session, Ram_quota amount) override

View File

@ -46,8 +46,20 @@ bool Sliced_heap::alloc(size_t size, void **out_addr)
Ram_dataspace_capability ds_cap;
Block *block = nullptr;
_ram_alloc.try_alloc(size).with_result(
[&] (Ram_dataspace_capability cap) { ds_cap = cap; },
[&] (Ram_allocator::Alloc_error error) {
switch (error) {
case Ram_allocator::Alloc_error::OUT_OF_CAPS: throw Out_of_caps();
case Ram_allocator::Alloc_error::OUT_OF_RAM: break;
case Ram_allocator::Alloc_error::DENIED: break;
}
});
if (!ds_cap.valid())
return false;
try {
ds_cap = _ram_alloc.alloc(size);
block = _region_map.attach(ds_cap);
}
catch (Region_map::Region_conflict) {

View File

@ -53,11 +53,16 @@ struct Libc::Malloc_ram_allocator : Ram_allocator
_release(ds); });
}
Ram_dataspace_capability alloc(size_t size, Cache cache) override
Alloc_result try_alloc(size_t size, Cache cache) override
{
Ram_dataspace_capability cap = _ram.alloc(size, cache);
new (_md_alloc) Registered<Dataspace>(_dataspaces, cap);
return cap;
return _ram.try_alloc(size, cache).convert<Alloc_result>(
[&] (Ram_dataspace_capability cap) {
new (_md_alloc) Registered<Dataspace>(_dataspaces, cap);
return cap; },
[&] (Alloc_error error) {
return error; });
}
void free(Ram_dataspace_capability ds_cap) override

View File

@ -113,18 +113,26 @@ class Genode::Session_env : public Ram_allocator,
** Ram_allocator **
*******************/
Ram_dataspace_capability alloc(size_t size, Cache cache) override
Alloc_result try_alloc(size_t size, Cache cache) override
{
enum { MAX_SHARED_CAP = 1 };
enum { MAX_SHARED_RAM = 4096 };
enum { DS_SIZE_GRANULARITY_LOG2 = 12 };
Alloc_result result = Alloc_error::DENIED;
size_t const ds_size = align_addr(size, DS_SIZE_GRANULARITY_LOG2);
Ram_dataspace_capability ds;
_consume(ds_size, MAX_SHARED_RAM, 1, MAX_SHARED_CAP, [&] () {
ds = _env.pd().alloc(ds_size, cache);
});
return ds;
try {
_consume(ds_size, MAX_SHARED_RAM, 1, MAX_SHARED_CAP, [&] ()
{
result = _env.pd().try_alloc(ds_size, cache);
});
}
catch (Out_of_ram) { result = Alloc_error::OUT_OF_RAM; }
catch (Out_of_caps) { result = Alloc_error::OUT_OF_CAPS; }
return result;
}

View File

@ -128,8 +128,8 @@ class Gdb_monitor::Pd_session_component : public Rpc_object<Pd_session>
Cap_quota cap_quota() const override { return _pd.cap_quota(); }
Cap_quota used_caps() const override { return _pd.used_caps(); }
Ram_dataspace_capability alloc(size_t amount, Cache cache) override {
return _pd.alloc(amount, cache); }
Alloc_result try_alloc(size_t amount, Cache cache) override {
return _pd.try_alloc(amount, cache); }
void free(Ram_dataspace_capability ds) override { _pd.free(ds); }