libmemalloc  v4.0.00
Modern Memory Allocator
Loading...
Searching...
No Matches
libmemalloc.c File Reference

Core memory management components for libmemalloc. More...

#include <inttypes.h>
#include <stdbool.h>
#include <stddef.h>
#include <sys/mman.h>
#include <sys/resource.h>
#include "libmemalloc.h"
#include "logs.h"
Include dependency graph for libmemalloc.c:

Macros

#define _GNU_SOURCE
 Enable GNU extensions on POSIX systems.
 
#define LOG_LEVEL   LOG_LEVEL_NONE
 Logging verbosity threshold for this module.
 
#define __UNUSED
 
#define __GC_HOT
 Marks garbage-collector functions as “hot” (performance critical).
 
#define __GC_COLD
 Marks garbage-collector functions as “cold” (infrequently used).
 
#define DEFAULT_NUM_BINS   (uint8_t)(10U)
 Default number of size classes (bins) for free lists.
 
#define CACHE_LINE_SIZE   (uint8_t)(64U)
 Size of the CPU cache line in bytes.
 
#define BYTES_PER_CLASS   (uint8_t)(128U)
 Fixed byte allocation per classification unit.
 
#define MMAP_THRESHOLD   (size_t)(128U * 1024U)
 Threshold size for using mmap-based allocation.
 
#define MIN_BLOCK_SIZE   (size_t)(sizeof(block_header_t) + ARCH_ALIGNMENT)
 Defines the minimum memory block size.
 
#define NR_OBJS   (uint16_t)(1000U)
 Number of iterations used to scale GC sleep duration.
 
#define LIKELY(x)   (__builtin_expect(!!(x), 1))
 Compiler hint for likely branch prediction.
 
#define UNLIKELY(x)   (__builtin_expect(!!(x), 0))
 Compiler hint for unlikely branch prediction.
 

Typedefs

typedef int(* find_fn_t) (mem_allocator_t *const, const size_t, block_header_t **)
 Type for functions that locate a suitable free block.
 

Functions

void * MEM_sbrk (const intptr_t increment)
 Invokes sbrk-like behavior by moving the program break.
 
static int MEM_getSizeClass (mem_allocator_t *const allocator, const size_t size)
 Calculates the size class index for a requested memory size.
 
static int MEM_validateBlock (mem_allocator_t *const allocator, block_header_t *const block)
 Validates the integrity and boundaries of a memory block.
 
static int MEM_insertFreeBlock (mem_allocator_t *const allocator, block_header_t *const block)
 Inserts a block into the appropriate free list based on its size.
 
static int MEM_removeFreeBlock (mem_allocator_t *const allocator, block_header_t *const block)
 Removes a block from its free list.
 
static int MEM_findFirstFit (mem_allocator_t *const allocator, const size_t size, block_header_t **fit_block)
 Searches for the first suitable free memory block in size‐class lists.
 
static int MEM_findNextFit (mem_allocator_t *const allocator, const size_t size, block_header_t **fit_block)
 Searches for the next suitable free memory block using the NEXT_FIT strategy starting from the last allocated position.
 
static int MEM_findBestFit (mem_allocator_t *const allocator, const size_t size, block_header_t **best_fit)
 Searches for the smallest suitable free memory block in size‐class lists (BEST_FIT).
 
static int MEM_splitBlock (mem_allocator_t *const allocator, block_header_t *const block, const size_t req_size)
 Splits a memory block into allocated and free portions.
 
static int MEM_mergeBlocks (mem_allocator_t *const allocator, block_header_t *block)
 Merges adjacent free memory blocks.
 
static void * MEM_growUserHeap (mem_allocator_t *const allocator, const intptr_t inc)
 Expands the user heap by a specified increment.
 
static int * MEM_mapAlloc (mem_allocator_t *const allocator, const size_t total_size)
 Allocates a page-aligned memory region via mmap and registers it in the allocator’s mmap list for later freeing.
 
static int MEM_mapFree (mem_allocator_t *const allocator, void *const addr)
 Unmaps a previously mapped memory region and removes its metadata entry from the allocator’s mmap list.
 
static void * MEM_allocatorMalloc (mem_allocator_t *const allocator, const size_t size, const char *const file, const int line, const char *const var_name, const allocation_strategy_t strategy) __LIBMEMALLOC_MALLOC
 Allocates memory using the specified strategy.
 
static void * MEM_allocatorRealloc (mem_allocator_t *const allocator, void *const ptr, const size_t new_size, const char *const file, const int line, const char *const var_name, const allocation_strategy_t strategy) __LIBMEMALLOC_REALLOC
 Reallocates memory with safety checks.
 
static void * MEM_allocatorCalloc (mem_allocator_t *const allocator, const size_t size, const char *const file, const int line, const char *const var_name, const allocation_strategy_t strategy) __LIBMEMALLOC_MALLOC
 Allocates and zero‐initializes memory.
 
static int MEM_allocatorFree (mem_allocator_t *const allocator, void *const ptr, const char *const file, const int line, const char *const var_name)
 Releases allocated memory back to the heap.
 
static bool MEM_stackGrowsDown (void)
 Determine at runtime whether the stack grows downward.
 
static int MEM_stackBounds (const pthread_t id, mem_allocator_t *const allocator)
 Query and record the bounding addresses of a thread’s stack.
 
static void * MEM_gcThreadFunc (void *arg)
 Dedicated thread loop driving mark-and-sweep iterations.
 
static int MEM_setInitialMarks (mem_allocator_t *const allocator)
 Reset “marked” flags across all allocated regions.
 
static int MEM_gcMark (mem_allocator_t *const allocator)
 Mark all live blocks reachable from the stack.
 
static int MEM_gcSweep (mem_allocator_t *const allocator)
 Reclaim any unmarked blocks from heap and mmap regions.
 
static int MEM_runGc (mem_allocator_t *const allocator)
 Start or signal the GC thread to perform a collection cycle.
 
static int MEM_stopGc (mem_allocator_t *const allocator)
 Stop the GC thread and perform a final collection.
 
void * MEM_memset (void *const source, const int value, const size_t size)
 Fills a memory block with a specified byte value using optimized operations.
 
void * MEM_memcpy (void *const dest, const void *src, const size_t size)
 Copies a memory block between buffers using optimized operations.
 
int MEM_allocatorInit (mem_allocator_t *const allocator)
 Initializes the memory allocator and its internal structures.
 
void * MEM_allocMallocFirstFit (mem_allocator_t *const allocator, const size_t size, const char *const var)
 Allocates memory using the FIRST_FIT strategy.
 
void * MEM_allocMallocBestFit (mem_allocator_t *const allocator, const size_t size, const char *const var)
 Allocates memory using the BEST_FIT strategy.
 
void * MEM_allocMallocNextFit (mem_allocator_t *const allocator, const size_t size, const char *const var)
 Allocates memory using the NEXT_FIT strategy.
 
void * MEM_allocMalloc (mem_allocator_t *const allocator, const size_t size, const char *const var, const allocation_strategy_t strategy)
 Allocates memory using the specified strategy.
 
void * MEM_allocCalloc (mem_allocator_t *const allocator, const size_t size, const char *const var, const allocation_strategy_t strategy)
 Allocates and zero‐initializes memory using the specified strategy.
 
void * MEM_allocRealloc (mem_allocator_t *const allocator, void *const ptr, const size_t new_size, const char *const var, const allocation_strategy_t strategy)
 Reallocates memory with safety checks using the specified strategy.
 
int MEM_allocFree (mem_allocator_t *const allocator, void *const ptr, const char *const var)
 Releases allocated memory back to the heap.
 
int MEM_enableGc (mem_allocator_t *const allocator)
 Start or signal the garbage collector thread.
 
int MEM_disableGc (mem_allocator_t *const allocator)
 Stop the garbage collector thread and perform a final collection.
 

Detailed Description

Core memory management components for libmemalloc.

Implements memory allocator with advanced features:

  • Architecture-specific stack allocation (alloca)
  • Garbage collection (mark & sweep)
  • Block validation with magic numbers/canaries
  • Multiple allocation strategies (First/Best/Next Fit)
Version
v1.0.00
Date
23.08.2025
Author
Rafael V. Volkmer rafae.nosp@m.l.v..nosp@m.volkm.nosp@m.er@g.nosp@m.mail..nosp@m.com

Macro Definition Documentation

◆ __GC_COLD

#define __GC_COLD

Marks garbage-collector functions as “cold” (infrequently used).

When supported by the compiler (GCC/Clang), expands to attribute((cold)), informing the optimizer that the annotated function is unlikely to execute frequently and may be placed out-of-line to reduce code size in hot paths. Otherwise, expands to nothing.

◆ __GC_HOT

#define __GC_HOT

Marks garbage-collector functions as “hot” (performance critical).

When supported by the compiler (GCC/Clang), expands to attribute((hot)), informing the optimizer that the annotated function is on a performance-critical path and should be optimized accordingly. Otherwise, expands to nothing.

◆ __UNUSED

#define __UNUSED

◆ _GNU_SOURCE

#define _GNU_SOURCE

Enable GNU extensions on POSIX systems.

P R I V A T E P R E - I N C L U D E D E F I N E S

Defining _GNU_SOURCE before including any headers activates GNU-specific library features and extensions in glibc and other GNU-compatible C libraries. This enables additional APIs beyond the standard C/POSIX specifications, such as nonstandard functions, constants, and structures.

◆ BYTES_PER_CLASS

#define BYTES_PER_CLASS   (uint8_t)(128U)

Fixed byte allocation per classification unit.

Defines the number of bytes assigned to each classification category. Ensures memory alignment and efficient block processing in data structures.

◆ CACHE_LINE_SIZE

#define CACHE_LINE_SIZE   (uint8_t)(64U)

Size of the CPU cache line in bytes.

This constant defines the cache-line size used for prefetching and alignment optimizations, ensuring memory accesses align to hardware cache boundaries for maximum performance and correctness on platforms with strict alignment requirements.

◆ DEFAULT_NUM_BINS

#define DEFAULT_NUM_BINS   (uint8_t)(10U)

Default number of size classes (bins) for free lists.

Defines how many size categories (bins) the allocator will maintain for managing free memory blocks. This value affects allocation speed and fragmentation behavior.

◆ LIKELY

#define LIKELY (   x)    (__builtin_expect(!!(x), 1))

Compiler hint for likely branch prediction.

Parameters
[in]xCondition that is likely to be true.

Helps the compiler optimize branch prediction by indicating the condition is expected to be true.

◆ LOG_LEVEL

#define LOG_LEVEL   LOG_LEVEL_NONE

Logging verbosity threshold for this module.

Sets the minimum severity of log messages that will be compiled into this translation unit. Only log calls at or below the specified level are enabled:

  • LOG_LEVEL_NONE (0): disable all logging
  • LOG_LEVEL_ERROR (1): errors only
  • LOG_LEVEL_WARNING (2): warnings and errors
  • LOG_LEVEL_INFO (3): info, warnings, and errors
  • LOG_LEVEL_DEBUG (4): debug, info, warnings, and errors

◆ MIN_BLOCK_SIZE

#define MIN_BLOCK_SIZE   (size_t)(sizeof(block_header_t) + ARCH_ALIGNMENT)

Defines the minimum memory block size.

Ensures each memory block is large enough to hold a block header and alignment padding.

◆ MMAP_THRESHOLD

#define MMAP_THRESHOLD   (size_t)(128U * 1024U)

Threshold size for using mmap-based allocation.

When a requested allocation size meets or exceeds this value (128 KiB), the allocator will switch from using the heap (brk/sbrk) to using mmap for more efficient large-block handling and to reduce heap fragmentation.

◆ NR_OBJS

#define NR_OBJS   (uint16_t)(1000U)

Number of iterations used to scale GC sleep duration.

Specifies the multiplier applied to the base GC interval (in milliseconds) to compute the actual sleep time between successive garbage-collection cycles: sleep_time = gc_interval_ms * NR_OBJS

◆ UNLIKELY

#define UNLIKELY (   x)    (__builtin_expect(!!(x), 0))

Compiler hint for unlikely branch prediction.

Parameters
[in]xCondition that is unlikely to be true.

Helps the compiler optimize branch prediction by indicating the condition is expected to be false.

Typedef Documentation

◆ find_fn_t

find_fn_t

Type for functions that locate a suitable free block.

Parameters
[in]allocatorMemory allocator context in which to search.
[in]sizeTotal size requested (including header and canary).
[out]blockAddress of pointer to store the found block header.
Returns
Integer

Function Documentation

◆ MEM_allocatorCalloc()

static void * MEM_allocatorCalloc ( mem_allocator_t *const  allocator,
const size_t  size,
const char *const  file,
const int  line,
const char *const  var_name,
const allocation_strategy_t  strategy 
)
static

Allocates and zero‐initializes memory.

This function behaves like calloc(), allocating at least size bytes of zeroed memory via MEM_allocatorMalloc() and then setting all bytes to zero. It records debugging metadata (source file, line, variable name) and uses the given strategy for allocation.

Parameters
[in]allocatorPointer to the mem_allocator_t context.
[in]sizeNumber of bytes to allocate.
[in]fileSource file name for debugging metadata.
[in]lineSource line number for debugging metadata.
[in]var_nameVariable name for tracking.
[in]strategyAllocation strategy to use.
Returns
Pointer to the start of the allocated zeroed region; an error‐encoded pointer via PTR_ERR() on failure.
Return values
ptrValid pointer to size bytes of zeroed memory.
-EINVALallocator is NULL or size is zero.
-ENOMEMOut of memory: allocation failed.
-EIOI/O error for large mmap‐based allocations.

◆ MEM_allocatorFree()

static int MEM_allocatorFree ( mem_allocator_t *const  allocator,
void *const  ptr,
const char *const  file,
const int  line,
const char *const  var_name 
)
static

Releases allocated memory back to the heap.

This function frees a pointer previously returned by MEM_allocatorMalloc(). It supports both heap‐based and mmap‐based allocations:

  • For mmap regions, it delegates to MEM_mapFree() to unmap and remove metadata.
  • For heap blocks, it validates the block, checks for double frees, marks the block free, merges with adjacent free blocks, and reinserts the merged block into the free list. If the freed block lies at the current heap end, it shrinks the heap via MEM_sbrk().
Parameters
[in]allocatorMemory allocator context.
[in]ptrPointer to memory to free.
[in]fileSource file name for debugging metadata.
[in]lineSource line number for debugging metadata.
[in]var_nameVariable name for tracking.
Returns
Integer status code.
Return values
EXIT_SUCCESSMemory freed (and heap possibly shrunk) successfully.
-EINVALallocator or ptr is NULL, ptr not found in allocator, or double free detected.
-ENOMEMmunmap() failed when freeing an mmap region.
-EFAULTBlock lies outside heap and mmap regions.
-EPROTOHeader canary mismatch (block corrupted).
-EOVERFLOWData canary mismatch (buffer overrun detected).
-EFBIGBlock size extends past heap end.
rer<0Errors returned by MEM_validateBlock(), MEM_removeFreeBlock(), MEM_mergeBlocks(), or MEM_insertFreeBlock().

◆ MEM_allocatorMalloc()

static void * MEM_allocatorMalloc ( mem_allocator_t *const  allocator,
const size_t  size,
const char *const  file,
const int  line,
const char *const  var_name,
const allocation_strategy_t  strategy 
)
static

Allocates memory using the specified strategy.

This function attempts to allocate at least size bytes of user data by choosing between heap‐based allocation (via free‐lists and optional heap growth) or mmap (for large requests > MMAP_THRESHOLD). It uses the given strategy (FIRST_FIT, NEXT_FIT, BEST_FIT) to locate a free block, grows the heap if necessary, splits a larger block to fit exactly, and records debugging metadata (source file, line, variable name). For mmap allocations it rounds up to page size and tracks the region in the allocator.

Parameters
[in]allocatorMemory allocator context.
[in]sizeNumber of bytes requested.
[in]fileSource file name for debugging metadata.
[in]lineSource line number for debugging metadata.
[in]var_nameVariable name for tracking.
[in]strategyAllocation strategy.
Returns
Pointer to the start of the allocated user region (just past the internal header) on success; an error‐encoded pointer (via PTR_ERR()) on failure.
Return values
ptrValid user pointer on success.
-EINVALallocator is NULL or size is zero.
-ENOMEMOut of memory: heap grow failed, no free block found, or internal metadata allocation (e.g. mmap_t node) failed.
-EIOmmap() I/O error for large allocations.

◆ MEM_allocatorRealloc()

static void * MEM_allocatorRealloc ( mem_allocator_t *const  allocator,
void *const  ptr,
const size_t  new_size,
const char *const  file,
const int  line,
const char *const  var_name,
const allocation_strategy_t  strategy 
)
static

Reallocates memory with safety checks.

This function resizes an existing allocation to new_size bytes:

  • If ptr is NULL, behaves like malloc().
  • If the existing block is already large enough, returns the same pointer.
  • Otherwise, allocates a new block with the specified strategy, copies the lesser of old and new sizes, frees the old block, and returns the new pointer.
Parameters
[in]allocatorMemory allocator context.
[in]ptrPointer to the block to resize, or NULL to allocate.
[in]new_sizeNew requested size in bytes.
[in]fileSource file name for debugging metadata.
[in]lineSource line number for debugging metadata.
[in]var_nameVariable name for tracking.
[in]strategyAllocation strategy to use.
Returns
Pointer to the reallocated memory region (which may be the same as ptr) on success; an error-encoded pointer (via PTR_ERR()) on failure.
Return values
ptrValid pointer to a block of at least new_size bytes.
-EINVALallocator is NULL, new_size is zero.
-ENOMEMOut of memory (allocation or free failure).
-EIOI/O error for large mmap-based allocations.

◆ MEM_findBestFit()

static int MEM_findBestFit ( mem_allocator_t *const  allocator,
const size_t  size,
block_header_t **  best_fit 
)
static

Searches for the smallest suitable free memory block in size‐class lists (BEST_FIT).

This function computes the starting size class for the requested size via MEM_getSizeClass(), then scans each free‐list from that class upward. It validates each candidate with MEM_validateBlock() and tracks the smallest free block that is large enough. Once a block in any class is chosen, the search stops.

Parameters
[in]allocatorPointer to the allocator context.
[in]sizeRequested allocation size in bytes.
[out]best_fitOn success, set to the pointer of the free block.
Returns
Integer status code.
Return values
EXIT_SUCCESSSuitable block found successfully.
-EINVALallocator or best_fit is NULL.
-ENOMEMSize calculation failed or no suitable block found.

◆ MEM_findFirstFit()

static int MEM_findFirstFit ( mem_allocator_t *const  allocator,
const size_t  size,
block_header_t **  fit_block 
)
static

Searches for the first suitable free memory block in size‐class lists.

This function computes the starting size class for the requested size via MEM_getSizeClass(), then scans each free‐list from that class upward. For each candidate block, it calls MEM_validateBlock() to ensure integrity, and returns the first block that is marked free and large enough. The found block pointer is stored in fit_block.

Parameters
[in]allocatorPointer to the allocator context.
[in]sizRequested allocation size in bytes.
[out]fit_blockOn success, set to the pointer of a suitable free block.
Returns
Integer status code.
Return values
EXIT_SUCCESSSuitable block found successfully.
-EINVALallocator or fit_block are NULL;
-ENOMEMSiz calculation failed or no suitable block found.

◆ MEM_findNextFit()

static int MEM_findNextFit ( mem_allocator_t *const  allocator,
const size_t  size,
block_header_t **  fit_block 
)
static

Searches for the next suitable free memory block using the NEXT_FIT strategy starting from the last allocated position.

This function attempts to find a free block of at least size bytes by scanning the heap starting at allocator->last_allocated. If last_allocated is NULL, not free, or corrupted, it falls back to First-Fit. It wraps around to the heap start if needed, stopping once it returns to the start.

Parameters
[in]allocatorPointer to the allocator context.
[in]sizeRequested allocation size in bytes.
[out]fit_blockPointer to store the address of the found block.
Returns
Integer status code.
Return values
EXIT_SUCCESSSuitable block found and fit_block set.
-EINVALallocator or fit_block is NULL.
-ENOMEMNo suitable block found in heap.

◆ MEM_gcMark()

static int MEM_gcMark ( mem_allocator_t *const  allocator)
static

Mark all live blocks reachable from the stack.

This function performs the marking phase of garbage collection by:

  • Calling MEM_setInitialMarks() to clear previous marks.
  • Capturing stack bounds via MEM_stackBounds() for the current thread.
  • Optionally informing Valgrind to treat the stack region as defined.
  • Scanning each word between stack_bottom and stack_top: • If the word’s value lies within the heap bounds, validating the corresponding block header and marking the block if it is live.
  • Iterating the allocator’s mmap_list and marking any mmap’d block whose payload contains a stack reference.
Parameters
[in]allocatorMemory allocator context.
Returns
Integer status code.
Return values
EXIT_SUCCESSAll reachable blocks marked successfully.
-EINVALallocator is NULL.
ret<0Error code returned by MEM_stackBounds(), MEM_validateBlock(), or other internal calls.

◆ MEM_gcSweep()

static int MEM_gcSweep ( mem_allocator_t *const  allocator)
static

Reclaim any unmarked blocks from heap and mmap regions.

This function performs the “sweep” phase of garbage collection:

  • It iterates over every block in the heap: • Logs each block’s free and marked status. • If a block is allocated (free0) but unmarked, calls MEM_allocatorFree() on its payload pointer to reclaim it. • Clears each block’s marked flag.
  • It then traverses allocator->mmap_list via a pointer-to-pointer scan: • Logs each mmap’d region’s status. • If an mmap’d block is unmarked and not already free, unlinks the mmap_t node, calls munmap() on the region, and frees its metadata header via MEM_allocatorFree(). • Otherwise, clears the block’s marked flag and advances to the next node.
Parameters
[in]allocatorMemory allocator context.
Returns
Integer status code.
Return values
EXIT_SUCCESSAll unreachable blocks reclaimed successfully.
-EINVALallocator is NULL.
ret<0Errors returned by MEM_allocatorFree(), munmap(), or internal validation functions.

◆ MEM_gcThreadFunc()

static void * MEM_gcThreadFunc ( void *  arg)
static

Dedicated thread loop driving mark-and-sweep iterations.

This function runs as the GC worker thread. It locks gc_lock and waits on gc_cond until either gc_running or gc_exit is set. On wakeup, if gc_exit is true, it breaks and exits the loop; otherwise it unlocks and performs one full GC cycle by calling MEM_gcMark() and MEM_gcSweep(), then sleeps for gc_interval_ms before re-acquiring the lock and waiting again. On exit it ensures gc_lock is released.

Parameters
[in]argPointer to the mem_allocator_t context.
Returns
NULL on clean exit; an error-encoded pointer (via PTR_ERR()) if any initialization or GC step fails.
Return values
NULLClean exit after gc_exit.
-EINVALarg is NULL.
ret<0cond errors, or MEM_gcMark() / MEM_gcSweep() failures.

◆ MEM_getSizeClass()

static int MEM_getSizeClass ( mem_allocator_t *const  allocator,
const size_t  size 
)
static

Calculates the size class index for a requested memory size.

This function determines which size class the given allocation request belongs to by dividing the requested size by BYTES_PER_CLASS (rounding up). If the computed index exceeds the maximum available class, it will be clamped to the highest class and a warning emitted.

Parameters
[in]allocatorPointer to the allocator context.
[in]sizeRequested memory size in bytes (must be > 0).
Returns
On success, returns a non-negative integer size class index; on failure, returns a negative error code.
Return values
ret>0Valid size class index.
-EINVALallocator is NULL, or size is zero.

◆ MEM_growUserHeap()

static void * MEM_growUserHeap ( mem_allocator_t *const  allocator,
const intptr_t  inc 
)
static

Expands the user heap by a specified increment.

This function moves the program break by inc bytes via MEM_sbrk(), zeroes the newly allocated region, updates the allocator’s heap_end, and initializes a block_header_t at the start of the new region to record its size, mark it as allocated, and set its free flag to false.

Parameters
[in]allocatorPointer to the allocator context.
[in]incSigned number of bytes to grow (or shrink) the heap.
Returns
Pointer to the previous program break (start of new region) on success; an error-encoded pointer (via PTR_ERR()) on failure.
Return values
(ret>=0)Previous heap end address (new region start).
-EINVALallocator is NULL.
-ENOMEMHeap expansion failed (out of memory).

◆ MEM_insertFreeBlock()

static int MEM_insertFreeBlock ( mem_allocator_t *const  allocator,
block_header_t *const  block 
)
static

Inserts a block into the appropriate free list based on its size.

This function computes the size class index for the given block by calling MEM_getSizeClass(), then pushes the block onto the head of that free list within the allocator. It updates both forward and backward links to maintain the doubly‐linked list of free blocks.

Parameters
[in]allocatorPointer to the allocator context.
[in]blockPointer to the block header to insert.
Returns
Integer status code.
Return values
EXIT_SUCCESSblock successfully inserted.
-EINVALallocator or block is NULL.
-ENOMEMSize class calculation failed (request too large).

◆ MEM_mapAlloc()

static int * MEM_mapAlloc ( mem_allocator_t *const  allocator,
const size_t  total_size 
)
static

Allocates a page-aligned memory region via mmap and registers it in the allocator’s mmap list for later freeing.

This function rounds up total_size to a multiple of the system page size, invokes mmap() to obtain an anonymous read/write region, then allocates an mmap_t metadata node via MEM_allocatorMalloc() and links it into allocator->mmap_list. It initializes a block_header_t and trailing canary in the mapped region to integrate with the allocator’s debugging and GC.

Parameters
[in]allocatorPointer to the memory allocator context.
[in]total_sizeNumber of bytes requested.
Returns
On success, returns the address of the mapped region. On failure, returns an error-encoded pointer (via PTR_ERR()).
Return values
ret!=MAP_FAILEDAddress of the mapped region.
-EINVALallocator is NULL.
-EIOmmap() failed.
-ENOMEMAllocation of mmap_t metadata failed.

◆ MEM_mapFree()

static int MEM_mapFree ( mem_allocator_t *const  allocator,
void *const  addr 
)
static

Unmaps a previously mapped memory region and removes its metadata entry from the allocator’s mmap list.

This function searches the allocator’s mmap_list for an entry matching addr, calls munmap() to unmap the region, unlinks the corresponding mmap_t metadata node, and frees it via MEM_allocatorFree(). Errors during munmap are returned; if metadata freeing fails, an error is logged but success is returned.

Parameters
[in]allocatorMemory allocator context.
[in]addrAddress of the memory region to unmap.
Returns
Integer status code.
Return values
EXIT_SUCCESSRegion unmapped and metadata entry removed.
-EINVALallocator / addr is NULL, or not found in list.
-ENOMEMmunmap() failed to unmap the region.

◆ MEM_mergeBlocks()

static int MEM_mergeBlocks ( mem_allocator_t *const  allocator,
block_header_t block 
)
static

Merges adjacent free memory blocks.

This function removes the specified block from its free list, then checks its immediate neighbor blocks in memory. If the next block is free and valid, it unlinks and combines it with block, updating size, links, and trailing canary. It then checks the previous block; if it is also free and valid, it merges block into the previous block. Finally, the resulting merged block is reinserted into the appropriate free list.

Parameters
[in]allocatorPointer to the allocator context.
[in]blockPointer to the free block header to merge.
Returns
Integer status code.
Return values
EXIT_SUCCESSBlocks merged (or single block reinserted) successfully.
-EINVALallocator or block is NULL.
ret<0Returned by MEM_removeFreeBlock(), MEM_validateBlock(), MEM_insertFreeBlock(), or munmap() in inner calls indicating the specific failure.

◆ MEM_removeFreeBlock()

static int MEM_removeFreeBlock ( mem_allocator_t *const  allocator,
block_header_t *const  block 
)
static

Removes a block from its free list.

This function unlinks the specified block from the free list corresponding to its size class within the allocator. It computes the size‐class index via MEM_getSizeClass(), validates parameters, then adjusts the neighboring blocks’ fl_next and fl_prev pointers (or the list head) to remove block. The block’s own fl_next and fl_prev are then cleared.

Parameters
[in]allocatorMemory allocator context.
[in]blockBlock header to remove.
Returns
Integer status code.
Return values
EXIT_SUCCESSBlock removed successfully.
-EINVALallocator or block is NULL.
-ENOMEMSize‐class calculation failed.

◆ MEM_runGc()

static int MEM_runGc ( mem_allocator_t *const  allocator)
static

Start or signal the GC thread to perform a collection cycle.

This function saves the caller’s thread ID as main_thread, locks gc_lock, and if the GC thread has not been started, sets gc_running and gc_exit flags and spawns MEM_gcThreadFunc(); otherwise it sets gc_running and signals gc_cond to wake the existing thread. Finally it unlocks gc_lock.

Parameters
[in]allocatorPointer to the mem_allocator_t context.
Returns
Integer status code.
Return values
EXIT_SUCCESSGC thread started or signaled successfully.
-EINVALallocator is NULL.
ret<0Error code returned by pthread_create().

◆ MEM_sbrk()

void * MEM_sbrk ( const intptr_t  increment)

Invokes sbrk-like behavior by moving the program break.

This function reads the current program break, attempts to move it by the signed offset increment via sbrk(), and returns the original break on success. If any call to sbrk() or reading the break fails, it encodes the negative errno into a pointer via PTR_ERR.

Parameters
[in]incrementSigned offset in bytes to move the program break: positive to grow, negative to shrink.
Returns
Original program break address on success; an error-encoded pointer (via PTR_ERR()) on failure.
Return values
ret>-1Previous break on success.
-ENOMEMFailed to read or adjust the break.

◆ MEM_setInitialMarks()

static int MEM_setInitialMarks ( mem_allocator_t *const  allocator)
static

Reset “marked” flags across all allocated regions.

This function prepares for a new garbage-collection cycle by clearing the mark flag on every heap block and every mmap’d block payload. It scans the heap from allocator->heap_start + metadata_size up to allocator->heap_end, resetting each valid block’s marked flag (and skipping malformed blocks to avoid infinite loops). It then iterates allocator->mmap_list, clearing the mark on each payload block while preserving the metadata header’s mark so the allocator’s own bookkeeping regions are never freed.

Parameters
[in]allocatorMemory allocator context.
Returns
Integer status code.
Return values
EXIT_SUCCESSAll marks cleared and metadata marks preserved.
-EINVALallocator is NULL.

◆ MEM_splitBlock()

static int MEM_splitBlock ( mem_allocator_t *const  allocator,
block_header_t *const  block,
const size_t  req_size 
)
static

Splits a memory block into allocated and free portions.

This function takes an existing free block and a requested allocation size req_size, and divides the block into:

  • an allocated portion of size aligned up to ALIGN(req_size) plus header and canary, marked as used;
  • a remaining free portion (if its size ≥ MIN_BLOCK_SIZE) inserted back into the appropriate free list. If the leftover space would be too small (< MIN_BLOCK_SIZE), the entire block is allocated without splitting.
Parameters
[in]allocatorPointer to the mem_allocator_t context.
[in]blockPointer to the block_header_t to split.
[in]req_sizeRequested allocation size in bytes.
Returns
Integer status code.
Return values
EXIT_SUCCESSBlock split (or fully allocated) successfully.
-EINVALnvalid allocator or block pointer.
-EPROTOHeader canary mismatch (block corrupted).
-EOVERFLOWData canary mismatch (buffer overflow detected).
-EFBIGBlock’s size would extend past heap end.
-EFAULTBlock lies outside heap or mmap regions.
-ENOMEMFailed to insert the new free remainder block.
Note
If the remaining space after splitting would be less than MIN_BLOCK_SIZE, this function allocates the entire block no split) and removes it from its free list.

◆ MEM_stackBounds()

static int MEM_stackBounds ( const pthread_t  id,
mem_allocator_t *const  allocator 
)
static

Query and record the bounding addresses of a thread’s stack.

This function retrieves the stack base address, total stack size, and guard size for the specified thread, then computes the usable stack bounds within the allocator object, taking into account whether the stack grows up or down in memory.

Parameters
[in]idThe thread identifier whose stack to inspect.
[in]allocatorPointer to the allocator object where stack_bottom and stack_top will be stored.
Returns
Integer status code.
Return values
EXIT_SUCCESSStack bounds successfully recorded.
-EINVALallocator was NULL.
ret>0Error code from one of the pthread or system calls

◆ MEM_stackGrowsDown()

static bool MEM_stackGrowsDown ( void  )
static

Determine at runtime whether the stack grows downward.

This function places two volatile local variables on the stack and compares their addresses to infer the growth direction:

  • If &addr_1 < &addr_0, the stack grows toward lower addresses.
  • Otherwise, it grows toward higher addresses.
Returns
true if stack grows down (higher addresses → lower), false if it grows up (lower addresses → higher)
Return values
trueStack grows downward (newer frames at lower addresses)
falseStack grows upward (newer frames at higher addresses)

◆ MEM_stopGc()

static int MEM_stopGc ( mem_allocator_t *const  allocator)
static

Stop the GC thread and perform a final collection.

This function clears gc_running and sets gc_exit, signals gc_cond to wake the GC thread if it’s running, then joins it. After the thread exits, it runs one final MEM_gcMark() + MEM_gcSweep() on the caller thread to reclaim any remaining garbage, then clears gc_thread_started.

Parameters
[in]allocatorPointer to the mem_allocator_t context.
Returns
Integer status code.
Return values
EXIT_SUCCESSGC thread stopped and final collection done.
-EINVALallocator is NULL.
ret<0Error code from pthread MEM_gcMark(), or MEM_gcSweep().

◆ MEM_validateBlock()

static int MEM_validateBlock ( mem_allocator_t *const  allocator,
block_header_t *const  block 
)
static

Validates the integrity and boundaries of a memory block.

This function ensures that the specified block lies within the allocator’s heap or one of its mmap regions, that its header canary matches the expected magic value to detect metadata corruption, that its data canary is intact to catch buffer overruns, and that the block’s size does not extend past the heap’s end. On any failure, an appropriate negative errno is returned.

Parameters
[in]allocatorPointer to the allocator context.
[in]blockPointer to the block header to validate.
Returns
Integer status code.
Return values
EXIT_SUCCESSblock is valid.
-EINVALallocator or block pointer is NULL.
-EFAULTblock lies outside heap and mmap regions.
-EPROTOblock canary does not match expected value.
-EFBIGblock size causes it to extend past heap end.
-EOVERFLOWblock canary indicates buffer overflow.