base: introduce Allocator::try_alloc

This patch changes the 'Allocator' interface to the use of 'Attempt'
return values instead of using exceptions for propagating errors.

To largely uphold compatibility with components using the original
exception-based interface - in particluar use cases where an 'Allocator'
is passed to the 'new' operator - the traditional 'alloc' is still
supported. But it existes merely as a wrapper around the new
'try_alloc'.

Issue #4324
This commit is contained in:
Norman Feske
2021-11-10 12:01:32 +01:00
committed by Christian Helmuth
parent 9591e6caee
commit dc39a8db62
102 changed files with 2128 additions and 1710 deletions

View File

@@ -389,15 +389,16 @@ static Genode::Allocator_avl& allocator()
extern "C" void *dde_dma_alloc(dde_size_t size, dde_size_t align,
dde_size_t offset)
{
void *ptr;
if (allocator().alloc_aligned(size, &ptr, Genode::log2(align)).error()) {
Genode::error("memory allocation failed in alloc_memblock ("
"size=", size, " "
"align=", Genode::Hex(align), " "
"offset=", Genode::Hex(offset), ")");
return 0;
}
return ptr;
return allocator().alloc_aligned(size, Genode::log2(align)).convert<void *>(
[&] (void *ptr) { return ptr; },
[&] (Genode::Range_allocator::Alloc_error) -> void * {
Genode::error("memory allocation failed in alloc_memblock ("
"size=", size, " "
"align=", Genode::Hex(align), " "
"offset=", Genode::Hex(offset), ")");
return nullptr; });
}
@@ -477,26 +478,53 @@ struct Slab_backend_alloc : public Genode::Allocator,
Genode::Allocator_avl _range;
Genode::Ram_allocator &_ram;
bool _alloc_block()
struct Extend_ok { };
using Extend_result = Genode::Attempt<Extend_ok, Alloc_error>;
Extend_result _extend_one_block()
{
using namespace Genode;
if (_index == ELEMENTS) {
error("slab backend exhausted!");
return false;
return Alloc_error::DENIED;
}
try {
_ds_cap[_index] = _ram.alloc(BLOCK_SIZE);
Region_map_client::attach_at(_ds_cap[_index], _index * BLOCK_SIZE, BLOCK_SIZE, 0);
} catch (...) { return false; }
return _ram.try_alloc(BLOCK_SIZE).convert<Extend_result>(
/* return base + offset in VM area */
Genode::addr_t block_base = _base + (_index * BLOCK_SIZE);
++_index;
[&] (Ram_dataspace_capability ds) -> Extend_result {
_range.add_range(block_base, BLOCK_SIZE);
return true;
_ds_cap[_index] = ds;
Alloc_error error = Alloc_error::DENIED;
try {
Region_map_client::attach_at(_ds_cap[_index],
_index * BLOCK_SIZE,
BLOCK_SIZE, 0);
/* return base + offset in VM area */
addr_t block_base = _base + (_index * BLOCK_SIZE);
++_index;
_range.add_range(block_base, BLOCK_SIZE);
return Extend_ok();
}
catch (Out_of_ram) { error = Alloc_error::OUT_OF_RAM; }
catch (Out_of_caps) { error = Alloc_error::OUT_OF_CAPS; }
catch (...) { error = Alloc_error::DENIED; }
Genode::error("Slab_backend_alloc: local attach_at failed");
_ram.free(ds);
_ds_cap[_index] = { };
return error;
},
[&] (Alloc_error e) -> Extend_result {
error("Slab_backend_alloc: backend allocator exhausted");
return e; });
}
Slab_backend_alloc(Genode::Env &env, Genode::Region_map &rm,
@@ -518,20 +546,15 @@ struct Slab_backend_alloc : public Genode::Allocator,
** Allocator interface **
*************************/
bool alloc(Genode::size_t size, void **out_addr)
Alloc_result try_alloc(Genode::size_t size) override
{
bool done = _range.alloc(size, out_addr);
Alloc_result result = _range.try_alloc(size);
if (result.ok())
return result;
if (done)
return done;
done = _alloc_block();
if (!done) {
Genode::error("backend allocator exhausted");
return false;
}
return _range.alloc(size, out_addr);
return _extend_one_block().convert<Alloc_result>(
[&] (Extend_ok) { return _range.try_alloc(size); },
[&] (Alloc_error error) { return error; });
}
void free(void *addr, Genode::size_t size) { _range.free(addr, size); }
@@ -562,8 +585,9 @@ class Slab_alloc : public Genode::Slab
Genode::addr_t alloc()
{
Genode::addr_t result;
return (Slab::alloc(_object_size, (void **)&result) ? result : 0);
return Slab::try_alloc(_object_size).convert<Genode::addr_t>(
[&] (void *ptr) { return (Genode::addr_t)ptr; },
[&] (Alloc_error) -> Genode::addr_t { return 0; });
}
void free(void *ptr) { Slab::free(ptr, _object_size); }