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

@ -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 { }