概要

prvAddTaskToReadyList() 是 FreeRTOS 内部将任务添加到就绪列表的核心函数。下面详细解析其实现机制。

函数原型和作用

主要作用:
1 将任务插入到对应优先级的就绪列表中
2 更新就绪任务位图(Ready Bitmap)

源码实现

  1. 就绪任务列表定义和初始化
/* 在 task.c 中定义 */
PRIVILEGED_DATA static List_t pxReadyTasksLists[ configMAX_PRIORITIES ];

/* 初始化 */
void prvInitialiseTaskLists( void )
{
    UBaseType_t uxPriority;
    
    for( uxPriority = ( UBaseType_t ) 0U;
         uxPriority < ( UBaseType_t ) configMAX_PRIORITIES;
         uxPriority++ )
    {
    	// 初始化各个优先级readyList中各个元素
        vListInitialise( &( pxReadyTasksLists[ uxPriority ] ) );
    }
}
  1. 函数原型
/* 标准版本(使用列表和位图) */
#define prvAddTaskToReadyList( pxTCB )                                   \
    traceREADY_TASK( pxTCB );                                            \
    taskRECORD_READY_PRIORITY( ( pxTCB )->uxPriority );                  \
    vListInsertEnd( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ),     \
                    &( ( pxTCB )->xStateListItem ) );                    \
    traceTASK_SWITCHED_IN();

详细分解

  1. 宏定义展开
/* 完整的宏展开逻辑 */
#define prvAddTaskToReadyList( pxTCB )                                   \
{                                                                        \
    /* 1. 跟踪任务就绪事件(如果启用跟踪) */                               \
    traceREADY_TASK( pxTCB );                                            \
                                                                         \
    /* 2. 在就绪位图中标记该优先级有就绪任务 */                            \
    portRECORD_READY_PRIORITY( ( pxTCB )->uxPriority, uxTopReadyPriority );\
                                                                         \
    /* 3. 将任务的状态列表项插入到对应优先级的就绪列表末尾 */                 \
    vListInsertEnd( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ),     \
                    &( ( pxTCB )->xStateListItem ) );                    \
                                                                         \
    /* 4. 跟踪任务切换事件 */                                            \
    traceTASK_SWITCHED_IN();                                             \
}
  1. 就绪任务位图(Ready Bitmap)
    FreeRTOS 使用位图快速查找最高优先级的就绪任务
/* 位图定义 */
#if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 )
    /* 通用实现:数组形式 */
    #define taskRECORD_READY_PRIORITY( uxPriority ) \
        uxTopReadyPriority |= ( 1UL << ( uxPriority ) )
    
    #define taskRESET_READY_PRIORITY( uxPriority ) \
        if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ uxPriority ] ) ) == 0 ) \
            uxTopReadyPriority &= ~( 1UL << ( uxPriority ) )
#else
    /* 使用前导零指令(CLZ)优化 */
    #define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) \
        ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) )
    
    #define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) \
        if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ ( uxPriority ) ] ) ) == 0 ) \
            ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) )
#endif

调度器通过位图快速找到最高优先级任务

/* 查找最高优先级就绪任务 */
#define taskSELECT_HIGHEST_PRIORITY_TASK()                              \
{                                                                       \
    UBaseType_t uxTopPriority;                                          \
                                                                        \
    /* 方法1:使用前导零指令(硬件加速) */                               \
    #if ( configUSE_PORT_OPTIMISED_TASK_SELECTION != 0 )                \
        /* 使用 CLZ 指令找到最高优先级位 */                               \
        UBaseType_t uxTopPriority;                                      \
        portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority );  \
    #else                                                               \
        /* 方法2:软件查找最高优先级 */                                   \
        /* 从最高优先级向下搜索 */                                       \
        const List_t *pxConstList;                                      \
                                                                        \
        for( uxTopPriority = ( UBaseType_t ) configMAX_PRIORITIES - 1;  \
             uxTopPriority > ( UBaseType_t ) 0;                         \
             uxTopPriority-- )                                          \
        {                                                               \
            if( listCURRENT_LIST_LENGTH( &pxReadyTasksLists[ uxTopPriority ] ) > 0 )\
            {                                                           \
                break;                                                  \
            }                                                           \
        }                                                               \
    #endif                                                              \
                                                                        \
    /* 获取该优先级列表的第一个任务 */                                   \
    listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB,                          \
                                 &( pxReadyTasksLists[ uxTopPriority ] ) );\
}
  1. 使用vListInsertEnd将新的列表项插入到列表的末尾(对于 FreeRTOS 的环形列表,实际上是插入到列表头pxIndex的前面)
void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem )
{
    ListItem_t * const pxIndex = pxList->pxIndex;
    
    /* 调试断言检查 */
    listTEST_LIST_INTEGRITY( pxList );
    listTEST_LIST_ITEM_INTEGRITY( pxNewListItem );
    
    /* 插入新列表项到pxIndex前面 */
    pxNewListItem->pxNext = pxIndex;
    pxNewListItem->pxPrevious = pxIndex->pxPrevious;
    
    /* 重要:因为这是环形列表,pxIndex->pxPrevious指向的是"列表末尾" */
    pxIndex->pxPrevious->pxNext = pxNewListItem;
    pxIndex->pxPrevious = pxNewListItem;
    
    /* 记录该列表项所属的列表 */
    pxNewListItem->pvContainer = ( void * ) pxList;
    
    /* 增加列表项计数 */
    ( pxList->uxNumberOfItems )++;
}

图形化理解

插入前状态:
pxList:
    pxIndex → [Item C]
    xListEnd ← 列表头(哨兵)  
环形结构:
    [xListEnd] ←→ [Item A] ←→ [Item B] ←→ [Item C] ←→ [xListEnd]
     ↑                                                    ↓
      ←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←

插入后状态:
插入位置:在 pxIndex 指向的项(Item C)之前插入NewItem
新环形结构:
    [xListEnd] ←→ [Item A] ←→ [Item B] ←→ [NewItem] ←→ [Item C] ←→ [xListEnd]
     ↑                                                                    ↓
      ←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←

总结

prvAddTaskToReadyList() 是 FreeRTOS 调度器的核心函数之一,它:
1 高效管理就绪任务:通过位图+列表的双重结构
2 支持快速调度:O(1)时间找到最高优先级任务

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐