mirror of
https://github.com/genodelabs/genode.git
synced 2025-06-21 00:23:16 +00:00
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:
committed by
Christian Helmuth
parent
959bcae557
commit
231ac187fe
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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 { }
|
||||
|
Reference in New Issue
Block a user