diff --git a/repos/base/include/base/allocator_avl.h b/repos/base/include/base/allocator_avl.h index 9accdfc27e..a2e0c94c90 100644 --- a/repos/base/include/base/allocator_avl.h +++ b/repos/base/include/base/allocator_avl.h @@ -188,6 +188,7 @@ class Genode::Allocator_avl_base : public Range_allocator addr_t base, size_t size, bool used); Block *_find_any_used_block(Block *sub_tree); + Block *_find_any_unused_block(Block *sub_tree); /** * Destroy block @@ -215,6 +216,7 @@ class Genode::Allocator_avl_base : public Range_allocator * from the meta-data allocator. */ void _revert_allocations_and_ranges(); + void _revert_unused_ranges(); /** * Find block by specified address @@ -342,6 +344,7 @@ class Genode::Allocator_avl_tpl : public Allocator_avl_base ~Allocator_avl_tpl() { + _revert_unused_ranges(); _metadata.free_empty_blocks(); _revert_allocations_and_ranges(); } diff --git a/repos/base/lib/symbols/ld b/repos/base/lib/symbols/ld index 7e8aa86adc..66f83c53c5 100644 --- a/repos/base/lib/symbols/ld +++ b/repos/base/lib/symbols/ld @@ -173,6 +173,8 @@ _ZN6Genode18Allocator_avl_base14any_block_addrEPm T _ZN6Genode18Allocator_avl_base15_cut_from_blockEPNS0_5BlockEmmS2_S2_ T _ZN6Genode18Allocator_avl_base20_find_any_used_blockEPNS0_5BlockE T _ZN6Genode18Allocator_avl_base21_alloc_block_metadataEv T +_ZN6Genode18Allocator_avl_base21_revert_unused_rangesEv T +_ZN6Genode18Allocator_avl_base22_find_any_unused_blockEPNS0_5BlockE T _ZN6Genode18Allocator_avl_base26_alloc_two_blocks_metadataEPPNS0_5BlockES3_ T _ZN6Genode18Allocator_avl_base30_revert_allocations_and_rangesEv T _ZN6Genode18Allocator_avl_base4freeEPv T diff --git a/repos/base/src/lib/base/allocator_avl.cc b/repos/base/src/lib/base/allocator_avl.cc index a23379eee7..cd6807d264 100644 --- a/repos/base/src/lib/base/allocator_avl.cc +++ b/repos/base/src/lib/base/allocator_avl.cc @@ -187,6 +187,21 @@ void Allocator_avl_base::_cut_from_block(Block *b, addr_t addr, size_t size, } +void Allocator_avl_base::_revert_unused_ranges() +{ + do { + Block * const block = _find_any_unused_block(_addr_tree.first()); + if (!block) + break; + + int const error = remove_range(block->addr(), block->size()); + if (error && block == _find_any_unused_block(_addr_tree.first())) + /* if the invocation fails, release the block to break endless loop */ + _destroy_block(block); + } while (true); +} + + void Allocator_avl_base::_revert_allocations_and_ranges() { /* revert all allocations */ @@ -390,6 +405,22 @@ size_t Allocator_avl_base::size_at(void const *addr) const } +Allocator_avl_base::Block *Allocator_avl_base::_find_any_unused_block(Block *sub_tree) +{ + if (!sub_tree) + return nullptr; + + if (!sub_tree->used()) + return sub_tree; + + for (unsigned i = 0; i < 2; i++) + if (Block *block = _find_any_unused_block(sub_tree->child(i))) + return block; + + return nullptr; +} + + Allocator_avl_base::Block *Allocator_avl_base::_find_any_used_block(Block *sub_tree) { if (!sub_tree)