Threadx内存管理 块内存池 block pool


块内存池由固定大小的内存块构成,空闲内存块通过单向链表连接。块内存池只会分配固定大小内存块,所以不会出现字节内存池的内存碎片问题。块内存分配和释放只需操作链表头部,所以查找效率高。
应用程序可以根据业务数据构成定义多个不同大小内存池,根据需求申请不同大小内存,提供内存管理性能。

块内存池控制块

块内存池控制块(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);
}
发布了48 篇原创文章 · 获赞 2 · 访问量 4061

猜你喜欢

转载自blog.csdn.net/qq_45683435/article/details/104277630