#include "kutil/frame_allocator.h" namespace kutil { int frame_block::compare(const frame_block *rhs) const { if (address < rhs->address) return -1; else if (address > rhs->address) return 1; return 0; } frame_block_list frame_block::consolidate(frame_block_list &list) { frame_block_list freed; for (auto *cur : list) { auto *next = cur->next(); while ( next && cur->flags == next->flags && cur->end() == next->address) { cur->count += next->count; list.remove(next); freed.push_back(next); } } return freed; } void frame_block::zero() { address = 0; count = 0; flags = frame_block_flags::none; } void frame_block::copy(frame_block *other) { address = other->address; count = other->count; flags = other->flags; } frame_allocator::frame_allocator( frame_block_list cache) { m_block_slab.append(cache); } void frame_allocator::init( frame_block_list free, frame_block_list used) { m_free.append(free); m_used.append(used); } void frame_allocator::consolidate_blocks() { m_block_slab.append(frame_block::consolidate(m_free)); m_block_slab.append(frame_block::consolidate(m_used)); } size_t frame_allocator::allocate(size_t count, uintptr_t *address) { kassert(!m_free.empty(), "frame_allocator::pop_frames ran out of free frames!"); auto *first = m_free.front(); unsigned n = count < first->count ? count : first->count; *address = first->address; if (count >= first->count) { m_free.remove(first); m_used.sorted_insert(first); } else { auto *used = m_block_slab.pop(); used->copy(first); used->count = n; m_used.sorted_insert(used); first->address += n * frame_size; first->count -= n; } m_block_slab.append(frame_block::consolidate(m_used)); return n; } void frame_allocator::free(uintptr_t address, size_t count) { size_t block_count = 0; for (auto *block : m_used) { if (!block->contains(address)) continue; size_t size = frame_size * count; uintptr_t end = address + size; size_t leading = address - block->address; size_t trailing = end > block->end() ? 0 : (block->end() - end); if (leading) { size_t frames = leading / frame_size; auto *lead_block = m_block_slab.pop(); lead_block->copy(block); lead_block->count = frames; block->count -= frames; block->address += leading; m_used.insert_before(block, lead_block); } if (trailing) { size_t frames = trailing / frame_size; auto *trail_block = m_block_slab.pop(); trail_block->copy(block); trail_block->count = frames; trail_block->address += size; trail_block->address += size; block->count -= frames; m_used.insert_after(block, trail_block); } address += block->count * frame_size; m_used.remove(block); m_free.sorted_insert(block); ++block_count; } kassert(block_count, "Couldn't find existing allocated frames to free"); } } // namespace kutil