42#define FALLBACK_PAGE_SIZE 4096U
50#define MAX_NUMBER_OF_BLOCKS 256U
53#define DEFAULT_BLOCK_ALIGNMENT 16U
63#define SRN_BLOCK_NO_ID SIZE_MAX
70 void *(*allocate)(
size_t size,
size_t alignment);
92_Static_assert(offsetof(
srn_block_t,
base) % 16 == 0,
"srn_block_t::base must be 16-byte aligned");
95typedef struct srn_allocation_stats_t {
96 size_t total_allocations;
97 size_t total_os_allocations;
98 size_t allocated_pages;
100} srn_allocation_stats_t;
109 srn_allocation_stats_t stats;
151[[nodiscard]] [[gnu::nonnull(1)]]
169[[nodiscard]] [[gnu::nonnull(1)]]
177[[nodiscard]] [[gnu::nonnull(1)]]
180#define srn_mm_allocate_in_block(mm, id, T) \
181 (T *)srn_mm_allocate_in_block_aligned(mm, id, sizeof(T), alignof(T))
183#define srn_mm_immortal_allocate(mm, T) \
184 (T *)srn_mm_immortal_allocate_aligned(mm, sizeof(T), alignof(T))
228[[nodiscard]] [[gnu::nonnull(1)]]
231[[nodiscard]] [[gnu::nonnull(1)]]
244void srn_mm_print_blocks_summary(
srn_mm_t *mm);
The single place that holds every runtime knob.
size_t srn_block_id_t
The block id is effectively just an index in the blocks array in srn_mm_t.
void srn_mm_release_block(srn_mm_t *mm, srn_block_id_t id)
Release the given block id and free the memory for later allocations.
void * srn_mm_allocate_in_block_aligned(srn_mm_t *mm, srn_block_id_t block_id, size_t size, size_t alignment)
Allocate memory on a block with the given block_id.
void srn_lock_memory_manager(srn_mm_t *mm)
Locks the memory manager.
srn_block_t * srn_mm_get_block(srn_mm_t *mm, srn_block_id_t block_id)
Return the block object associated by the given block_id.
void * srn_mm_reallocate(srn_mm_t *mm, void *ptr, size_t new_size)
void * srn_mm_immortal_allocate_aligned(srn_mm_t *mm, size_t size, size_t alignment)
Allocate memory on the importal block which will never gets freed.
void srn_mm_free(srn_mm_t *mm, void *ptr)
Release a pointer previously returned by srn_mm_malloc or srn_mm_reallocate.
srn_block_id_t srn_mm_allocate_block(srn_mm_t *mm)
Allocate a new block in the memory manager and return its ID.
size_t srn_mm_get_os_page_size(void)
Retutrns the OS page size.
void srn_mm_shutdown(srn_mm_t *mm)
Shut down the memory manager and release the resources.
srn_mm_t * srn_mm_init(const srn_configuration_t *config)
Initialize the memory manager, this function will panic on error.
#define MAX_NUMBER_OF_BLOCKS
array of blocks is enough for us, we can tweak the size as we see fit.
void * srn_mm_malloc(srn_mm_t *mm, size_t size)
Generic allocations that do not participate in the block based pools.
#define DEFAULT_BLOCK_ALIGNMENT
We strictly use 16 bytes alignment for blocks.
void srn_unlock_memory_manager(srn_mm_t *mm)
Unocks the memory manager.
uint8_t base[]
Where the data area starts.
size_t offset
Offset from the base.
size_t size
This is the TOTAL size of the block, header + payloud.
struct srn_block_t * next
when the block does not have space to allocate a request, we will allocate a new block and point to i...
Every runtime knob, in one place.
This interface is here to abstract over the allocator.
Main memory manager structure that will own all the allocated blocks and data.
srn_block_t * blocks[MAX_NUMBER_OF_BLOCKS]
srn_spinlock_t lock
This spinlock is here to protect the srn_mm_t when allocating/deallocating new blocks.
srn_block_t * immortal_block
Immortal block is a chain of blocks which will never die.
size_t block_count
Number of live chains.
srn_spinlock_t chain_locks[MAX_NUMBER_OF_BLOCKS]
One lock per chain, keyed by block id.
uint64_t block_bitmap[4]
This is a 256bit bitmap we treat it as a whole.
srn_memory_provider_t * provider
An abstraction over a memory provider like the malloc/free pair.
srn_spinlock_t immortal_lock
The immortal chain has no block id, so it gets its own chain lock.