#pragma once /// \file heap_allocator.h /// A buddy allocator for a memory heap #include #include "kutil/spinlock.h" /// Allocator for a given heap range class heap_allocator { public: /// Default constructor creates a valid but empty heap. heap_allocator(); /// Constructor. The given memory area must already have been reserved. /// \arg start Starting address of the heap /// \arg size Size of the heap in bytes heap_allocator(uintptr_t start, size_t size); /// Allocate memory from the area managed. /// \arg length The amount of memory to allocate, in bytes /// \returns A pointer to the allocated memory, or nullptr if /// allocation failed. void * allocate(size_t length); /// Free a previous allocation. /// \arg p A pointer previously retuned by allocate() void free(void *p); /// Minimum block size is (2^min_order). Must be at least 6. static const unsigned min_order = 6; /// Maximum block size is (2^max_order). Must be less than 64. static const unsigned max_order = 22; protected: class mem_header; /// Ensure there is a block of a given order, recursively splitting /// \arg order Order (2^N) of the block we want void ensure_block(unsigned order); /// Helper accessor for the list of blocks of a given order /// \arg order Order (2^N) of the block we want /// \returns A mutable reference to the head of the list mem_header *& get_free(unsigned order) { return m_free[order - min_order]; } /// Helper to get a block of the given order, growing if necessary /// \arg order Order (2^N) of the block we want /// \returns A detached block of the given order mem_header * pop_free(unsigned order); uintptr_t m_start, m_end; size_t m_blocks; mem_header *m_free[max_order - min_order + 1]; size_t m_allocated_size; kutil::spinlock m_lock; heap_allocator(const heap_allocator &) = delete; };