base: Allocator_avl cleanup meta data

After reverting unused ranges during allocator destruction
'_meta_data.free_empty_blocks' may lead to more unused ranges because
meta data blocks maybe freed where the meta data for the blocks is
managed by other meta data blocks. This leads to dangling allocation
warnings which are caused by meta data. Therefore, we call
'_revert_unused_ranges' and 'free_empty_blocks' until no more ranges
can be freed.

issue #4466
This commit is contained in:
Sebastian Sumpf 2022-03-31 13:58:53 +02:00 committed by Christian Helmuth
parent f704a50e9f
commit da1ef67064
2 changed files with 18 additions and 7 deletions

View File

@ -208,7 +208,7 @@ class Genode::Allocator_avl_base : public Range_allocator
void _cut_from_block(Block &b, addr_t cut_addr, size_t cut_size, Two_blocks);
template <typename ANY_BLOCK_FN>
void _revert_block_ranges(ANY_BLOCK_FN const &);
bool _revert_block_ranges(ANY_BLOCK_FN const &);
template <typename SEARCH_FN>
Alloc_result _allocate(size_t, unsigned, Range, SEARCH_FN const &);
@ -225,7 +225,7 @@ class Genode::Allocator_avl_base : public Range_allocator
* from the meta-data allocator.
*/
void _revert_allocations_and_ranges();
void _revert_unused_ranges();
bool _revert_unused_ranges();
/**
* Find block by specified address
@ -354,7 +354,15 @@ class Genode::Allocator_avl_tpl : public Allocator_avl_base
~Allocator_avl_tpl()
{
_revert_unused_ranges();
_metadata.free_empty_blocks();
/*
* The release of empty blocks may add unused ranges (formerly used
* by metadata). Thus, we loop until all empty blocks are freed and
* no additional unused ranges appear.
*/
do {
_metadata.free_empty_blocks();
} while (_revert_unused_ranges());
_revert_allocations_and_ranges();
}

View File

@ -172,9 +172,10 @@ void Allocator_avl_base::_cut_from_block(Block &b, addr_t addr, size_t size, Two
template <typename FN>
void Allocator_avl_base::_revert_block_ranges(FN const &any_block_fn)
bool Allocator_avl_base::_revert_block_ranges(FN const &any_block_fn)
{
for (bool loop = true; loop; ) {
size_t blocks = 0;
for (bool loop = true; loop; blocks++) {
Block *block_ptr = any_block_fn();
if (!block_ptr)
@ -188,12 +189,14 @@ void Allocator_avl_base::_revert_block_ranges(FN const &any_block_fn)
loop = false; /* give up on OUT_OF_RAM or OUT_OF_CAPS */
});
}
return blocks > 0;
}
void Allocator_avl_base::_revert_unused_ranges()
bool Allocator_avl_base::_revert_unused_ranges()
{
_revert_block_ranges([&] () {
return _revert_block_ranges([&] () {
return _find_any_unused_block(_addr_tree.first()); });
}