文章目录
块内存池由固定大小的内存块构成,空闲内存块通过单向链表连接。块内存池只会分配固定大小内存块,所以不会出现字节内存池的内存碎片问题。块内存分配和释放只需操作链表头部,所以查找效率高。
应用程序可以根据业务数据构成定义多个不同大小内存池,根据需求申请不同大小内存,提供内存管理性能。
块内存池控制块
块内存池控制块(BCB)是用来保持运行时块内存池状态的数据结构。
/* Define the block memory pool structure utilized by the application. */
typedef struct TX_BLOCK_POOL_STRUCT
{
/* Define the block pool ID used for error checking. */
ULONG tx_block_pool_id;
/* Define the block pool's name. */
CHAR_PTR tx_block_pool_name;
/* Define the number of available memory blocks in the pool. */
ULONG tx_block_pool_available;
/* Save the initial number of blocks. */
ULONG tx_block_pool_total;
/* Define the head pointer of the available block pool. */
CHAR_PTR tx_block_pool_available_list;
/* Save the start address of the block pool's memory area. */
CHAR_PTR tx_block_pool_start;
/* Save the block pool's size in bytes. */
ULONG tx_block_pool_size;
/* Save the individual memory block size - rounded for alignment. */
ULONG tx_block_pool_block_size;
/* Define the block pool suspension list head along with a count of
how many threads are suspended. */
struct TX_THREAD_STRUCT *tx_block_pool_suspension_list;
ULONG tx_block_pool_suspended_count;
/* Define the created list next and previous pointers. */
struct TX_BLOCK_POOL_STRUCT
*tx_block_pool_created_next,
*tx_block_pool_created_previous;
} TX_BLOCK_POOL;
域 | 意义 |
---|---|
tx_block_pool_id | 块内存池id |
tx_block_pool_name | 块内存池名字指针 |
tx_block_pool_available | 块内存池总的空闲块个数 |
tx_block_pool_total | 块内存池总的块个数 |
tx_block_pool_available_list | 块内存池空闲链表头部 |
tx_block_pool_start | 块内存池连续内存的起始地址 |
tx_block_pool_size | 块内存池整个内存大小 |
tx_block_pool_block_size | 块内存池固定块大小 |
tx_block_pool_suspension_list | 块内存池挂起链表 |
tx_block_pool_suspended_count | 块内存池挂起链表中线程个数 |
tx_block_pool_created_next | 指向下一个块内存池 |
tx_block_pool_created_previous | 指向前一个块内存池 |
系统块内存池链表
系统块内存池链表用来保持所有块内存池,_tx_block_pool_created_ptr为链表头部指针。
tx_block_pool_created_next指向下一个块内存池,tx_block_pool_created_previous指向前一个块内存池。
块内存池初始化
tx_block_pool_create用来创建块内存池,应用程序指定内存池起始地址,内存大小,固定块大小。 固定块个数=内存大小/固定块大小。
固定块通过单向链表连接起来,链表指针存储在每个固定块头部前4字节,也就是每个固定块头部指向相邻下一块的内存首地址,最后一块头部前4字节存储为NULL。
tx_block_pool_available_list指向第一个空闲内存块。
块内存池分配
内存分配时,从tx_block_pool_available_list找到第一块空闲内存块,直接返回,tx_block_pool_available_list指向下一个空闲内存块。
分配的内存块头部4个字节不再指向下一个内存块首地址,而是存储了内存池TX_BLOCK_POOL管理结构地址,用于后续内存释放时使用。
如果没有空闲内存块,线程可以挂起等待,插入tx_block_pool_suspension_list链表,插入规则为先进先出FIFO,而不是线程优先级高低顺序。
下图第一次分配,第一块被分配给应用程序使用,tx_block_pool_available_list指向第二块,也就是当前第一个空闲内存块。
第一块头部4字节指向了TX_BLOCK_POOL管理结构地址。操作简单,只改变了tx_block_pool_available_list指针和第一块头部4字节。
下图第二次分配,第二块块被分配给应用程序使用,tx_block_pool_available_list指向第三块,也就是当前第一个空闲内存块。
第二块头部4字节指向了TX_BLOCK_POOL管理结构地址。操作简单,只改变了tx_block_pool_available_list指针和第二块头部4字节。
块内存池释放
内存释放时,找到tx_block_pool_available_list指向空闲块,将要释放的内存块前4字节指向tx_block_pool_available_list指向的空闲块,然后tx_block_pool_available_list指向释放的内存块。如下,第一块内存为释放的内存块。
释放内存时,如果tx_block_pool_suspension_list链表中有线程挂起,那么尝试为挂起线程重新申请内存,并恢复线程。通常恢复线程顺序为FIFO,而不是线程优先级高低。但应用程序可以在释放内存前,调用tx_block_pool_prioritize把挂起链表中最高优先级线程移动到最前面,保证最高优先级线程先恢复。
块内存池API
函数 | 描述 |
---|---|
tx_block_pool_create | 创建块内存池 |
tx_block_pool_delete | 删除内存块 |
tx_block_allocate | 分配内存块 |
tx_block_release | 释放内存块 |
tx_block_pool_info_get | 获取内存池信息 |
tx_block_pool_prioritize | 调整挂起链表最高优先级到最前面 |
tx_block_pool_create
应用程序调用tx_block_pool_create创建块内存池。
pool_ptr内存池管理结构指针
pool_ptr内存池名字指针
block_size内存池固定块大小
pool_start内存池内存的起始地址
pool_size内存池整个内存的大小
UINT _tx_block_pool_create(TX_BLOCK_POOL *pool_ptr, CHAR *name_ptr, ULONG block_size,
VOID *pool_start, ULONG pool_size)
{
TX_INTERRUPT_SAVE_AREA
TX_BLOCK_POOL *tail_ptr; /* Working block pool pointer */
ULONG blocks; /* Number of blocks in pool */
CHAR_PTR block_ptr; /* Working block pointer */
CHAR_PTR next_block_ptr; /* Next block pointer */
CHAR_PTR end_of_pool; /* End of pool area */
/* Round the block size up to something that is evenly divisible by
an ULONG. This helps guarantee proper alignment. */
#def 保证内存固定块大小 ULONG大小对齐
block_size = ((block_size + sizeof(ULONG) - 1) / sizeof(ULONG)) * sizeof(ULONG);
/* Round the pool size down to something that is evenly divisible by
an ULONG. */
#def 整个内存池大小 也要ULONG大小对齐
pool_size = (pool_size / sizeof(ULONG)) * sizeof(ULONG);
/* Setup the basic block pool fields. */
#def 初始化各字段
pool_ptr -> tx_block_pool_name = name_ptr;
pool_ptr -> tx_block_pool_suspension_list = TX_NULL;
pool_ptr -> tx_block_pool_suspended_count = 0;
#def内存池内存起始地址
pool_ptr -> tx_block_pool_start = (CHAR_PTR) pool_start;
pool_ptr -> tx_block_pool_size = pool_size;
pool_ptr -> tx_block_pool_block_size = block_size;
/* Calculate the end of the pool's memory area. */
#def 内存池内存尾部地址
end_of_pool = ((CHAR_PTR) pool_start) + (UINT) pool_size;
/* Walk through the pool area, setting up the available block list. */
blocks = 0;
block_ptr = (CHAR_PTR) pool_start;
#def 每个固定块头部预留sizeof(CHAR_PTR)字节作为控制字段 计算下一块首地址
next_block_ptr = block_ptr + (UINT)(block_size + sizeof(CHAR_PTR));
#def 循环初始化所有段,每个块的控制字段指向相邻下一块的首地址,构成单向链表,最后一块控制字段指向NULL
while (next_block_ptr <= end_of_pool)
{
/* Yes, we have another block. Increment the block count. */
blocks++;
/* Setup the link to the next block. */
#def 每个块的控制字段指向相邻下一块的首地址
*((CHAR_PTR *) block_ptr) = next_block_ptr;
/* Advance to the next block. */
block_ptr = next_block_ptr;
/* Update the next block pointer. */
#def next_block_ptr 指向下一块
next_block_ptr = block_ptr + (UINT)(block_size + sizeof(CHAR_PTR));
}
/* Backup to the last block in the pool. */
#def 计算出最后一块首地址
block_ptr = block_ptr - (UINT)(block_size + sizeof(CHAR_PTR));
/* Set the last block's forward pointer to NULL. */
#def 最后一块控制字段指向NULL
*((CHAR_PTR *) block_ptr) = TX_NULL;
/* Save the remaining information in the pool control block. */
#def 可用块数量,总的块数量
pool_ptr -> tx_block_pool_available = blocks;
pool_ptr -> tx_block_pool_total = blocks;
/* Quickly check to make sure at least one block is in the pool. */
#def tx_block_pool_available_list 指向第一个空闲块,第一个开始查找的块指针
if (blocks)
pool_ptr -> tx_block_pool_available_list = (CHAR_PTR) pool_start;
else
pool_ptr -> tx_block_pool_available_list = TX_NULL;
/* Disable interrupts to place the block pool on the created list. */
TX_DISABLE
/* Setup the block pool ID to make it valid. */
#def 设置内存池id
pool_ptr -> tx_block_pool_id = TX_BLOCK_POOL_ID;
/* Place the block pool on the list of created block pools. First,
check for an empty list. */
#def 内存池插入_tx_block_pool_created_ptr链表
if (_tx_block_pool_created_ptr)
{
/* Pickup tail pointer. */
tail_ptr = _tx_block_pool_created_ptr -> tx_block_pool_created_previous;
/* Place the new block pool in the list. */
_tx_block_pool_created_ptr -> tx_block_pool_created_previous = pool_ptr;
tail_ptr -> tx_block_pool_created_next = pool_ptr;
/* Setup this block pool's created links. */
pool_ptr -> tx_block_pool_created_previous = tail_ptr;
pool_ptr -> tx_block_pool_created_next = _tx_block_pool_created_ptr;
}
else
{
/* The created block pool list is empty. Add block pool to empty list. */
_tx_block_pool_created_ptr = pool_ptr;
pool_ptr -> tx_block_pool_created_next = pool_ptr;
pool_ptr -> tx_block_pool_created_previous = pool_ptr;
}
/* Increment the number of block pools created. */
_tx_block_pool_created_count++;
/* Restore interrupts. */
TX_RESTORE
/* Return TX_SUCCESS. */
return (TX_SUCCESS);
}
tx_block_pool_delete
应用程序调用tx_block_pool_delete删除内存池。
从_tx_block_pool_created_ptr链表删除内存池,并且恢复挂起在tx_block_pool_suspension_list中线程。
UINT _tx_block_pool_delete(TX_BLOCK_POOL *pool_ptr)
{
TX_INTERRUPT_SAVE_AREA
TX_THREAD *thread_ptr; /* Working thread pointer */
/* Disable interrupts to remove the block pool from the created list. */
TX_DISABLE
/* Decrement the number of block pools created. */
_tx_block_pool_created_count--;
/* Clear the block pool ID to make it invalid. */
#def 标记内存池为无效
pool_ptr -> tx_block_pool_id = 0;
/* See if the block pool is the only one on the list. */
#def 从_tx_block_pool_created_ptr 删除内存池
if (pool_ptr == pool_ptr -> tx_block_pool_created_next)
{
/* Only created block pool, just set the created list to NULL. */
_tx_block_pool_created_ptr = TX_NULL;
}
else
{
/* Link-up the neighbors. */
(pool_ptr -> tx_block_pool_created_next) -> tx_block_pool_created_previous =
pool_ptr -> tx_block_pool_created_previous;
(pool_ptr -> tx_block_pool_created_previous) -> tx_block_pool_created_next =
pool_ptr -> tx_block_pool_created_next;
/* See if we have to update the created list head pointer. */
if (_tx_block_pool_created_ptr == pool_ptr)
/* Yes, move the head pointer to the next link. */
_tx_block_pool_created_ptr = pool_ptr -> tx_block_pool_created_next;
}
/* Temporarily disable preemption. */
_tx_thread_preempt_disable++;
/* Restore interrupts. */
TX_RESTORE
/* Walk through the block pool list to resume any and all threads suspended
on this block pool. */
#def 恢复挂起链表中线程
thread_ptr = pool_ptr -> tx_block_pool_suspension_list;
while (pool_ptr -> tx_block_pool_suspended_count)
{
/* Lockout interrupts. */
TX_DISABLE
/* Clear the cleanup pointer, this prevents the timeout from doing
anything. */
thread_ptr -> tx_suspend_cleanup = TX_NULL;
/* Temporarily disable preemption again. */
_tx_thread_preempt_disable++;
/* Restore interrupts. */
TX_RESTORE
/* Yes, deactivate the thread's timer just in case. */
_tx_timer_deactivate(&(thread_ptr -> tx_thread_timer));
/* Clear the remaining time to ensure timer doesn't get activated. */
thread_ptr -> tx_thread_timer.tx_remaining_ticks = 0;
/* Set the return status in the thread to TX_DELETED. */
#def 设置挂起状态为TX_DELETED,tx_suspend_status 在恢复线程中作为返回值,比如tx_block_allocate中
thread_ptr -> tx_suspend_status = TX_DELETED;
/* Move the thread pointer ahead. */
thread_ptr = thread_ptr -> tx_suspended_next;
/* Resume the thread. */
_tx_thread_resume(thread_ptr -> tx_suspended_previous);
/* Decrease the suspended count. */
pool_ptr -> tx_block_pool_suspended_count--;
}
/* Disable interrupts. */
TX_DISABLE
/* Release previous preempt disable. */
_tx_thread_preempt_disable--;
/* Restore interrupts. */
TX_RESTORE
/* Check for preemption. */
#def 恢复线程后,可能有高优先级线程,需要切换
if (_tx_thread_current_ptr != _tx_thread_execute_ptr)
/* Transfer control to system. */
_tx_thread_system_return();
/* Return TX_SUCCESS. */
return (TX_SUCCESS);
}
_tx_block_pool_prioritize
调整tx_block_pool_suspension_list中的线程,把优先级最高线程移动链表头部。
UINT _tx_block_pool_prioritize(TX_BLOCK_POOL *pool_ptr)
{
TX_INTERRUPT_SAVE_AREA
REG_1 TX_THREAD *thread_ptr; /* Working thread pointer */
REG_2 TX_THREAD *priority_thread_ptr; /* Highest priority thread */
/* Disable interrupts. */
#def 禁止中断
TX_DISABLE
/* Determine if there how many threads are suspended on this block memory pool. */
#def 只有两个线程,交换一下
if (pool_ptr -> tx_block_pool_suspended_count == 2)
{
/* Determine if the next suspended thread has a higher priority. */
if (((pool_ptr -> tx_block_pool_suspension_list) -> tx_suspended_next) -> tx_priority <
((pool_ptr -> tx_block_pool_suspension_list) -> tx_priority))
{
/* Yes, move the list head to the next thread. */
pool_ptr -> tx_block_pool_suspension_list =
(pool_ptr -> tx_block_pool_suspension_list) -> tx_suspended_next;
}
}
else if (pool_ptr -> tx_block_pool_suspended_count > 2)
{
#def 线程数量大于2,先选择出优先级最高先线程
/* Default the highest priority thread to the thread at the front of the list. */
priority_thread_ptr = pool_ptr -> tx_block_pool_suspension_list;
/* Setup search pointer. */
thread_ptr = priority_thread_ptr -> tx_suspended_next;
/* Search through the list to find the highest priority thread. */
#def 查找出优先级最高线程
do
{
/* Is the current thread higher priority? */
if (thread_ptr -> tx_priority < priority_thread_ptr -> tx_priority)
{
/* Yes, remember that this thread is the highest priority. */
priority_thread_ptr = thread_ptr;
}
/* Move the thread pointer to the next thread. */
thread_ptr = thread_ptr -> tx_suspended_next;
}
while (thread_ptr != pool_ptr -> tx_block_pool_suspension_list);
/* Now determine if the highest priority thread is at the front
of the list. */
#def 如果优先级最高线程不在头部,从链表移除,再插到头部
if (priority_thread_ptr != pool_ptr -> tx_block_pool_suspension_list)
{
/* No, we need to move the highest priority suspended thread to the
front of the list. */
/* First, remove the highest priority thread by updating the
adjacent suspended threads. */
(priority_thread_ptr -> tx_suspended_next) -> tx_suspended_previous =
priority_thread_ptr -> tx_suspended_previous;
(priority_thread_ptr -> tx_suspended_previous) -> tx_suspended_next =
priority_thread_ptr -> tx_suspended_next;
/* Now, link the highest priority thread at the front of the list. */
priority_thread_ptr -> tx_suspended_next =
pool_ptr -> tx_block_pool_suspension_list;
priority_thread_ptr -> tx_suspended_previous =
(pool_ptr -> tx_block_pool_suspension_list) -> tx_suspended_previous;
((pool_ptr -> tx_block_pool_suspension_list) -> tx_suspended_previous) -> tx_suspended_next =
priority_thread_ptr;
(pool_ptr -> tx_block_pool_suspension_list) -> tx_suspended_previous = priority_thread_ptr;
/* Move the list head pointer to the highest priority suspended thread. */
pool_ptr -> tx_block_pool_suspension_list = priority_thread_ptr;
}
}
/* Restore interrupts. */
TX_RESTORE
/* Return completion status. */
return (TX_SUCCESS);
}