freeRTOS操作系统机器人实现
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

391 lines
12 KiB

/******************************************************************************
版权所有 (C), 2018-2099, Radkil
******************************************************************************
文 件 名 : rd_mempool.c
版 本 号 : 初稿
作 者 : Radkil
生成日期 : 2026年3月10日星期二
最近修改 :
功能描述 : 内存池模块
修改历史 :
1.日 期 : 2026年3月10日星期二
作 者 : Radkil
修改内容 : 创建文件
******************************************************************************/
#include "rd_mempool.h"
#include "rd_thread.h"
/*----------------------------------------------*
* 外部变量说明 *
*----------------------------------------------*/
/*----------------------------------------------*
* 外部函数原型说明 *
*----------------------------------------------*/
/*----------------------------------------------*
* 内部函数原型说明 *
*----------------------------------------------*/
/*----------------------------------------------*
* 全局变量 *
*----------------------------------------------*/
// 内存块头部结构 (隐藏在用户指针之前)
// 这个结构体的大小必须是 ALIGN_SIZE 的倍数
typedef struct MemBlockHeader {
size_t size; // 当前块的总大小 (包含 Header 本身)
int is_free; // 1 = 空闲, 0 = 已占用
struct MemBlockHeader* next_free; // 指向下一个空闲块 (仅在 is_free=1 时有效)
struct MemBlockHeader* prev_free; // 指向上一个空闲块 (双向链表便于删除节点)
} MemBlockHeader_t;
#define HEADER_SIZE RD_ALIGN(sizeof(MemBlockHeader_t), RD_ALIGN_SIZE)
#define MIN_BLOCK_SIZE (HEADER_SIZE + MIN_ALLOC_UNIT)
static uint8_t* g_pool_start = NULL;
static uint8_t* g_pool_end = NULL;
static MemBlockHeader_t* g_free_list_head = NULL;
static int g_initialized = 0;
#ifdef USE_HEAP_FOR_MEMPOOL
static uint8_t* g_heap_buf = NULL;
#endif
/*----------------------------------------------*
* 模块级变量 *
*----------------------------------------------*/
/*----------------------------------------------*
* 常量定义 *
*----------------------------------------------*/
/*----------------------------------------------*
* 宏定义 *
*----------------------------------------------*/
// 获取用户数据指针
rd_inline void* get_user_ptr(MemBlockHeader_t* block)
{
return (void*)((uint8_t*)block + HEADER_SIZE);
}
// 获取头部指针
rd_inline MemBlockHeader_t* get_header_ptr(void* ptr)
{
return (MemBlockHeader_t*)((uint8_t*)ptr - HEADER_SIZE);
}
// 检查指针是否在池内
rd_inline int is_valid_ptr(void* ptr)
{
if (!g_initialized || !ptr) return 0;
return ((uint8_t*)ptr >= (g_pool_start + HEADER_SIZE) &&
(uint8_t*)ptr < g_pool_end);
}
// 从空闲链表中移除节点
static void remove_from_free_list(MemBlockHeader_t* block)
{
if (!block->is_free) return;
if (block->prev_free)
{
block->prev_free->next_free = block->next_free;
}
else
{
g_free_list_head = block->next_free;
}
if (block->next_free)
{
block->next_free->prev_free = block->prev_free;
}
block->next_free = NULL;
block->prev_free = NULL;
}
// 添加节点到空闲链表头部 (简单高效)
static void add_to_free_list(MemBlockHeader_t* block)
{
block->is_free = 1;
block->next_free = g_free_list_head;
block->prev_free = NULL;
if (g_free_list_head)
{
g_free_list_head->prev_free = block;
}
g_free_list_head = block;
}
// 物理相邻的块合并 (关键步骤:消除碎片)
static void merge_free_blocks(MemBlockHeader_t* block)
{
if (!block || !block->is_free) return;
// 1. 尝试与【后一个】块合并
// 计算下一个块的地址
uint8_t* next_block_addr = (uint8_t*)block + block->size;
// 检查是否越界
if (next_block_addr < g_pool_end)
{
MemBlockHeader_t* next_block = (MemBlockHeader_t*)next_block_addr;
// 如果下一个块也是空闲的,合并!
if (next_block->is_free)
{
// 从链表中移除下一个块 (因为要合并进当前块)
remove_from_free_list(next_block);
// 扩大当前块尺寸
block->size += next_block->size;
// 注意:不需要重新设置 next_block 的 header,因为它已经被吞并了
}
}
// 2. 尝试与【前一个】块合并
// 由于单向无法直接得知前一个块,我们需要遍历或者维护额外信息。
// 优化技巧:在 Free 列表中遍历时,我们无法直接知道物理前驱。
// 简单做法:遍历整个空闲链表,看谁的 (addr + size) == 当前 addr。
// 为了效率,通常我们在分配时保证顺序,或者接受 O(N) 的前向查找。
// 这里为了代码简洁和稳健,采用遍历查找前驱 (在碎片不多时很快)。
MemBlockHeader_t* prev_block = g_free_list_head;
while (prev_block) {
if (prev_block == block) {
prev_block = prev_block->next_free;
continue;
}
uint8_t* potential_next = (uint8_t*)prev_block + prev_block->size;
if (potential_next == (uint8_t*)block)
{
// 发现前驱是空闲的,合并:前驱吞并当前
remove_from_free_list(block); // 先移除当前
remove_from_free_list(prev_block); // 移除前驱准备重组
prev_block->size += block->size;
add_to_free_list(prev_block); // 重新加入链表
return; // 合并完成
}
prev_block = prev_block->next_free;
}
}
WEAK void Rd_MemDoInit(void)
{
if (g_initialized) return;
#ifdef USE_HEAP_FOR_MEMPOOL
g_heap_buf = (uint8_t*)MP_MALLOC(MEM_POOL_TOTAL_SIZE);
if (!g_heap_buf)
{
log_e("MemPool Init Failed: Malloc error");
return;
}
g_pool_start = g_heap_buf;
#else
// 静态数组,确保对齐
static uint8_t static_pool[MEM_POOL_TOTAL_SIZE] __attribute__((aligned(RD_ALIGN_SIZE)));
g_pool_start = static_pool;
#endif
g_pool_end = g_pool_start + MEM_POOL_TOTAL_SIZE;
// 初始化整个池为一个巨大的空闲块
MemBlockHeader_t* initial_block = (MemBlockHeader_t*)g_pool_start;
initial_block->size = MEM_POOL_TOTAL_SIZE;
initial_block->is_free = 1;
initial_block->next_free = NULL;
initial_block->prev_free = NULL;
g_free_list_head = initial_block;
g_initialized = 1;
log_d("MemPool Init Success: Total %d Bytes", MEM_POOL_TOTAL_SIZE);
}
WEAK void Rd_MemDoDeinit(void)
{
#ifdef USE_HEAP_FOR_MEMPOOL
if (g_heap_buf)
{
MP_FREE(g_heap_buf);
g_heap_buf = NULL;
}
#endif
g_initialized = 0;
g_free_list_head = NULL;
}
WEAK void* Rd_MemPoolMalloc(size_t size)
{
if (!g_initialized || size == 0) return NULL;
void *pvReturn = NULL;
Rd_MutexLock(NULL, __func__, NULL);
{
// 对齐大小计算:用户数据 + 头部
size_t aligned_size = RD_ALIGN(size, RD_ALIGN_SIZE);
size_t total_needed = HEADER_SIZE + aligned_size;
// 确保不小于最小块大小
if (total_needed < MIN_BLOCK_SIZE)
{
total_needed = MIN_BLOCK_SIZE;
}
// 首次适应算法 (First Fit)
MemBlockHeader_t* current = g_free_list_head;
while (current)
{
if (current->size >= total_needed)
{
// 找到合适的块
// 检查是否可以切分 (剩下的部分是否足够形成一个新块)
size_t remaining = current->size - total_needed;
if (remaining >= MIN_BLOCK_SIZE)
{
// 【切分操作】
// 1. 创建新块 (在剩余空间)
MemBlockHeader_t* new_block = (MemBlockHeader_t*)((uint8_t*)current + total_needed);
new_block->size = remaining;
new_block->is_free = 0; // 暂时设为占用,稍后加入链表
// 2. 缩小当前块
current->size = total_needed;
// 3. 将新块加入空闲链表
add_to_free_list(new_block);
}
else
{
// 不切分,整个块都给用户 (避免产生极小碎片)
// 剩余空间被浪费在当前块内,直到下次 Free
}
// 从空闲链表移除当前块,标记为占用
remove_from_free_list(current);
current->is_free = 0;
current->next_free = NULL;
current->prev_free = NULL;
pvReturn = get_user_ptr(current);
}
current = current->next_free;
}
if (pvReturn == NULL)
{
log_d("MemPool Malloc Failed: Request %zu, No Block Found", size);
}
}
Rd_MutexUnlock(NULL, __func__, NULL);
return pvReturn;
}
WEAK void Rd_MemPoolFree(void* ptr)
{
if (!is_valid_ptr(ptr))
{
log_d("MemPool Free Error: Invalid Pointer %p", ptr);
return;
}
Rd_MutexLock(NULL, __func__, NULL);
{
MemBlockHeader_t* block = get_header_ptr(ptr);
// 双重释放保护
if (block->is_free)
{
log_d("MemPool Free Error: Double Free detected at %p", ptr);
return;
}
// 标记为空闲并加入链表
add_to_free_list(block);
// 【关键】尝试与相邻空闲块合并,减少碎片
merge_free_blocks(block);
}
Rd_MutexUnlock(NULL, __func__, NULL);
}
WEAK void* Rd_MemPoolCalloc(size_t n, size_t size)
{
size_t total = n * size;
void* ptr = Rd_MemPoolMalloc(total);
if (ptr)
{
MP_MEMSET(ptr, 0, total);
}
return ptr;
}
WEAK void* Rd_MemPoolRealloc(void* ptr, size_t new_size)
{
if (!ptr) return Rd_MemPoolMalloc(new_size);
if (new_size == 0)
{
Rd_MemPoolFree(ptr);
return NULL;
}
MemBlockHeader_t* block = get_header_ptr(ptr);
size_t old_user_size = block->size - HEADER_SIZE;
if (old_user_size >= new_size)
{
// 现有块足够大,不需要移动 (可选:这里可以不做任何事,或者返回原指针)
// 注意:标准 realloc 在缩小时行为未定义,通常不缩小块,除非为了合并
return ptr;
}
// 需要扩大:分配新的,拷贝,释放旧的
void* new_ptr = Rd_MemPoolMalloc(new_size);
if (!new_ptr) return NULL;
MP_MEMCPY(new_ptr, ptr, old_user_size);
Rd_MemPoolFree(ptr);
return new_ptr;
}
WEAK size_t Rd_MemPoolGetFreeCount(void)
{
if (!g_initialized) return 0;
size_t total_free = 0;
MemBlockHeader_t* curr = g_free_list_head;
while (curr)
{
total_free += (curr->size - HEADER_SIZE);
curr = curr->next_free;
}
return total_free;
}
WEAK size_t Rd_MemPoolGetTotalCount(void)
{
return (size_t)MEM_POOL_TOTAL_SIZE;
}
void Rd_MemPoolInit_Auto(void)
{
Rd_MemDoInit();
}
__attribute__((destructor(102)))
void Rd_MemPoolDeinit_Auto(void)
{
Rd_MemDoDeinit();
}