_tx_byte_pool_search
_tx_byte_pool_search用于搜索可用内存,在_tx_byte_allocate和 _tx_byte_release函数中调用。
使用first-fit算法,从上次操作的空闲内存开始搜索,搜索过程中找到第一块合适大小内存,就返回成功。
内存块链表是一个循环链表,最后一块为固定块,不用内存分配,只为了适配搜索算法。
如果把一块大内存分成了两块,一块返回给应用程序,另一块需要插入链表。
搜索过程中,发现两块连续内存都是空闲内存,那么把这两块内存合并为一块,插入链表。
VOID *_tx_byte_pool_search(TX_BYTE_POOL *pool_ptr, ULONG memory_size)
{
TX_INTERRUPT_SAVE_AREA
REG_1 CHAR_PTR current_ptr; /* Current block pointer */
REG_2 CHAR_PTR next_ptr; /* Next block pointer */
REG_3 ULONG available_bytes; /* Calculate bytes available */
REG_4 ULONG examine_blocks; /* Blocks to be examined */
/* Disable interrupts. */
#def 禁止中断
TX_DISABLE
/* First, determine if there are enough bytes in the pool. */
#def 如果可用内存不够,直接返回失败。tx_byte_pool_available为内存池整个可用空间。
if (memory_size >= pool_ptr -> tx_byte_pool_available)
{
/* Restore interrupts. */
TX_RESTORE
/* Not enough memory, return a NULL pointer. */
return (TX_NULL);
}
/* Walk through the memory pool in search for a large enough block. */
#def 临时保存搜索内存起始位置, 搜索最大块数,tx_byte_pool_fragments + 1这里加1是为了方便计算
current_ptr = pool_ptr -> tx_byte_pool_search;
examine_blocks = pool_ptr -> tx_byte_pool_fragments + 1;
available_bytes = 0;
do
{
/* Check to see if this block is free. */
#def 检查控制字段第4到8个字节为TX_BYTE_BLOCK_FREE,表示为空闲内存
if (*((ULONG_PTR)(current_ptr + sizeof(CHAR_PTR))) == TX_BYTE_BLOCK_FREE)
{
/* Block is free, see if it is large enough. */
/* Pickup the next block's pointer. */
#def 控制字段前4个字节存储了下一相邻块的首地址
next_ptr = *((CHAR_PTR *) current_ptr);
/* Calculate the number of byte available in this block. */
#def 计算current_ptr 块内存的大小
available_bytes = next_ptr - current_ptr - sizeof(CHAR_PTR) - sizeof(ULONG);
/* If this is large enough, we are done because our first-fit algorithm
has been satisfied! */
#def 本块内存空间足够,那么可以退出搜索了
if (available_bytes >= memory_size)
{
/* Get out of the search loop! */
break;
}
else
{
#def 本块内存大小不够,需要继续搜索下一块
/* Clear the available bytes variable. */
available_bytes = 0;
/* Not enough memory, check to see if the neighbor is
free and can be merged. */
#def 检查下一块释放为空闲内存
if (*((ULONG_PTR)(next_ptr + sizeof(CHAR_PTR))) == TX_BYTE_BLOCK_FREE)
{
#def 下一块也为空闲内存,那么可以把这两个内存合并为一块大的内存
/* Yes, neighbor block can be merged! This is quickly accomplished
by updating the current block with the next blocks pointer. */
#def 当前块控制字段前4字节存储 下下块内存的首地址。*((CHAR_PTR *) next_ptr)中存储了下下块内存首地址
#def 这样就想相当于,下一块内存从链表中去掉了。
*((CHAR_PTR *) current_ptr) = *((CHAR_PTR *) next_ptr);
/* Reduce the fragment total. We don't need to increase the bytes
available because all free headers are also included in the available
count. */
#def 减少一块
pool_ptr -> tx_byte_pool_fragments--;
/* See if the search pointer is affected. */
#def 需要把搜索指针重新设置为刚刚合并的大块首地址
if (pool_ptr -> tx_byte_pool_search == next_ptr)
pool_ptr -> tx_byte_pool_search = current_ptr;
}
else
{
#def 下一块不是空闲块,那么查找下下块
/* Neighbor is not free so we can skip over it! */
current_ptr = *((CHAR_PTR *) next_ptr);
/* Decrement the examined block count to account for this one. */
#def 检查块数减1
if (examine_blocks)
examine_blocks--;
}
}
}
else
{
/* Block is not free, move to next block. */
current_ptr = *((CHAR_PTR *) current_ptr);
}
/* Another block has been searched... decrement counter. */
if (examine_blocks)
examine_blocks--;
/* Restore interrupts temporarily. */
#def 开中断,这里主要是给其他高优先级任务调度机会。因为在这里进行内存搜索耗时可能时间较长。 提升系统实时性,响应能力。
TX_RESTORE
/* Disable interrupts. */
TX_DISABLE
/* Determine if anything has changed in terms of pool ownership. */
#def 如果线程被打断过,且高优先级线程操作过这个内存池
if (pool_ptr -> tx_byte_pool_owner != _tx_thread_current_ptr)
{
/* Pool changed ownership in the brief period interrupts were
enabled. Reset the search. */
#def 从第一个空闲块开始搜索
current_ptr = pool_ptr -> tx_byte_pool_search;
examine_blocks = pool_ptr -> tx_byte_pool_fragments + 1;
/* Setup our ownership again. */
#def 重新记录内存池拥有者为当前线程
pool_ptr -> tx_byte_pool_owner = _tx_thread_current_ptr;
}
}
#def examine_blocks不为0,继续搜索
while (examine_blocks);
/* Determine if a block was found. If so, determine if it needs to be
split. */
#def available_bytes不为0,说明前面搜索成功
if (available_bytes)
{
#def 搜索成功,如果这块内存减去申请大小 超过了TX_BYTE_BLOCK_MIN字节,只需要返回申请大小的内存,
#def 剩下内存自己成为一块,插入链表。
#def 分裂
/* Determine if we need to split this block. */
if ((available_bytes - memory_size) >= ((ULONG) TX_BYTE_BLOCK_MIN))
{
/* Split the block. */
#def 分裂后的首地址计算,首地址+申请大小+控制字段大小,就是分裂后 后一块内存首地址
next_ptr = current_ptr + memory_size + sizeof(CHAR_PTR) + sizeof(ULONG);
/* Setup the new free block. */
#def 插入链表,标记为空闲块,并指向下一块内存
*((CHAR_PTR *) next_ptr) = *((CHAR_PTR *) current_ptr);
*((ULONG_PTR)(next_ptr + sizeof(CHAR_PTR))) = TX_BYTE_BLOCK_FREE;
/* Increase the total fragment counter. */
#def 块数加1
pool_ptr -> tx_byte_pool_fragments++;
/* Update the current pointer to point at the newly created block. */
#def 当前块也要执行新分裂出来的下一块
*((CHAR_PTR *) current_ptr) = next_ptr;
/* Set available equal to memory size for subsequent calculation. */
available_bytes = memory_size;
}
/* In any case, mark the current block as allocated. */
#def 当前分配块,标记为已占用,不在存储TX_BYTE_BLOCK_FREE,而是存储内存池管理结构指针
*((TX_BYTE_POOL **)(current_ptr + sizeof(CHAR_PTR))) = pool_ptr;
/* Reduce the number of available bytes in the pool. */
#def 重新计算总的可用内存大小
pool_ptr -> tx_byte_pool_available = pool_ptr -> tx_byte_pool_available -
available_bytes - sizeof(CHAR_PTR) - sizeof(ULONG);
/* Update the search pointer to the next block. */
#def 搜索起始地址给为下一块,这里不一定是第一块空闲块。前面可能有空闲块被太小,被跨过了
pool_ptr -> tx_byte_pool_search = *((CHAR_PTR *) current_ptr);
/* Restore interrupts. */
TX_RESTORE
/* Adjust the pointer for the application. */
#def 返回给应用程序的地址,跨过控制字段
current_ptr = current_ptr + sizeof(CHAR_PTR) + sizeof(ULONG);
}
else
{
/* Restore interrupts. */
TX_RESTORE
/* Set current pointer to NULL to indicate nothing was found. */
current_ptr = TX_NULL;
}
/* Return the search pointer. */
return (current_ptr);
}