mirror of
https://github.com/ByteWelder/Tactility.git
synced 2026-08-18 16:05:05 +00:00
New Features - Added policy-based memory allocation APIs with capability flags and optional alignment: `memory_alloc_with_policy`, `memory_realloc_with_policy`, `memory_calloc_with_policy`, and `memory_free`. - Switched heap memory reporting to `memory_print_stats`. Bug Fixes - Improved allocation robustness with capability fallback behavior. - Added overflow-safe handling for aligned zero-initialized allocations. - Tightened const-correctness for generated device-tree device arrays. Tests - Added unit tests for default policy, alignment, zero-initialization, realloc preservation, freeing, and memory stats reporting.
116 lines
4.3 KiB
C
116 lines
4.3 KiB
C
#pragma once
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/** Capability flags that describe what a memory allocation needs or prefers. */
|
|
enum MemoryCapability {
|
|
/** Internal memory (non-external/non-PSRAM) memory. */
|
|
MEMORY_CAPABILITY_INTERNAL = 1u << 0,
|
|
/** External memory (e.g. PSRAM/SPIRAM). */
|
|
MEMORY_CAPABILITY_EXTERNAL = 1u << 1,
|
|
/** Usable for code execution. */
|
|
MEMORY_CAPABILITY_EXECUTABLE = 1u << 2,
|
|
/** Usable as a DMA source/destination. */
|
|
MEMORY_CAPABILITY_DMA = 1u << 3,
|
|
/** Usable for SIMD instructions. */
|
|
MEMORY_CAPABILITY_SIMD = 1u << 4,
|
|
};
|
|
|
|
/**
|
|
* @brief Describes the constraints an allocation must (or should) satisfy.
|
|
*
|
|
* `required` capabilities must all be satisfied or the allocation fails. `desired`
|
|
* capabilities are attempted alongside `required`, but implementations fall back to
|
|
* `required`-only if `required | desired` together can't be satisfied.
|
|
*/
|
|
struct MemoryPolicy {
|
|
/** A bitset of MemoryCapability flags that are required during allocation. */
|
|
uint16_t required;
|
|
/** A bitset of MemoryCapability flags that are preferable (but optional) during allocation. */
|
|
uint16_t desired;
|
|
/** Alignment (in bytes) of the returned pointer, or 0 for the platform default. Must be a power of 2. */
|
|
size_t alignment;
|
|
};
|
|
|
|
/** The default policy: no required/desired capabilities, no alignment requirement. */
|
|
extern const struct MemoryPolicy MEMORY_POLICY_DEFAULT;
|
|
|
|
/**
|
|
* @brief Logs current heap usage (internal and external, when applicable).
|
|
* No-op on platforms without heap capability tracking.
|
|
*/
|
|
void memory_print_stats();
|
|
|
|
/**
|
|
* @brief Allocates memory that satisfies the given policy.
|
|
* @param[in] size number of bytes to allocate
|
|
* @param[in] policy the allocation constraints
|
|
* @return the allocated memory, or NULL on failure
|
|
*/
|
|
void* memory_alloc_with_policy(size_t size, const struct MemoryPolicy* policy);
|
|
|
|
/**
|
|
* @brief Resizes a previous allocation, preserving its contents up to the smaller of the old and new size.
|
|
* @warning policy->alignment is not guaranteed to be preserved across a realloc - it is only
|
|
* honored on fresh allocations (memory_alloc_with_policy()/memory_calloc_with_policy()).
|
|
* @param[in] ptr memory previously returned by memory_alloc_with_policy(), memory_calloc_with_policy(),
|
|
* or memory_realloc_with_policy(), or NULL to allocate a new block
|
|
* @param[in] size new memory size in bytes
|
|
* @param[in] policy the policy for the new allocation
|
|
* @return the (possibly moved) allocated memory, or NULL on failure - in which case ptr is left untouched
|
|
*/
|
|
void* memory_realloc_with_policy(void* ptr, size_t size, const struct MemoryPolicy* policy);
|
|
|
|
/**
|
|
* @brief Allocates zero-initialized memory that satisfies the given policy.
|
|
* @param[in] count number of elements
|
|
* @param[in] size size of each element in bytes
|
|
* @param[in] policy the allocation constraints
|
|
* @return the allocated memory, or NULL on failure
|
|
*/
|
|
void* memory_calloc_with_policy(size_t count, size_t size, const struct MemoryPolicy* policy);
|
|
|
|
/**
|
|
* @brief Allocates memory using MEMORY_POLICY_DEFAULT.
|
|
* @param[in] size number of bytes to allocate
|
|
* @return the allocated memory, or NULL on failure
|
|
*/
|
|
inline void* memory_alloc(size_t size) {
|
|
return memory_alloc_with_policy(size, &MEMORY_POLICY_DEFAULT);
|
|
}
|
|
|
|
/**
|
|
* @brief Allocates zero-initialized memory using MEMORY_POLICY_DEFAULT.
|
|
* @param[in] count number of elements
|
|
* @param[in] size size of each element in bytes
|
|
* @return the allocated memory, or NULL on failure
|
|
*/
|
|
inline void* memory_calloc(size_t count, size_t size) {
|
|
return memory_calloc_with_policy(count, size, &MEMORY_POLICY_DEFAULT);
|
|
}
|
|
|
|
/**
|
|
* @brief Resizes a previous allocation using MEMORY_POLICY_DEFAULT. See memory_realloc_with_policy().
|
|
* @param[in] ptr memory previously returned by one of the memory_* allocation functions, or NULL
|
|
* @param[in] size new memory size in bytes
|
|
* @return the (possibly moved) allocated memory, or NULL on failure - in which case ptr is left untouched
|
|
*/
|
|
inline void* memory_realloc(void* ptr, size_t size) {
|
|
return memory_realloc_with_policy(ptr, size, &MEMORY_POLICY_DEFAULT);
|
|
}
|
|
|
|
/**
|
|
* @brief Frees memory previously returned by one of the memory_* allocation functions.
|
|
* @param[in] ptr the memory to free, or NULL (a no-op)
|
|
*/
|
|
void memory_free(void* ptr);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|