FreeRTOS 原理 --- 任务调度机制

发布时间 2023-09-25 23:24:15作者: 流水灯

任务的状态

  • 运行态
  • 就绪态
  • 阻塞态(被动让出CPU)
  • 挂起态(主动让出CPU)

就绪链表

就绪态,每个任务优先级对应一个链表,如下:

PRIVILEGED_DATA static List_t pxReadyTasksLists[ configMAX_PRIORITIES ] = {0};    /*< Prioritised ready tasks. */

 

xPortPendSVHandler 中断只会从高优先级链表取任务,最高优先级链表没有任务,则往低优先级链表取任务,其内调用如下宏:

    #define taskSELECT_HIGHEST_PRIORITY_TASK()                                                        \
    {                                                                                                \
    UBaseType_t uxTopPriority;                                                                        \
                                                                                                    \
        /* Find the highest priority list that contains ready tasks. */                                \
        portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority );                                \
        configASSERT( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ uxTopPriority ] ) ) > 0 );        \
        listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) );        \
    } /* taskSELECT_HIGHEST_PRIORITY_TASK() */

 

如下可知,链表的成员变量 pxIndex 指向当前正在指向的任务。链表是一个循环链表,新插入的任务放在 pxIndex 的前面(保证后插入的任务后执行)。

#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList )                                        \
{                                                                                            \
List_t * const pxConstList = ( pxList );                                                    \
    /* Increment the index to the next item and return the item, ensuring */                \
    /* we don't return the marker used at the end of the list.  */                            \
    ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;                            \
    if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) )    \
    {                                                                                        \
        ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;                        \
    }                                                                                        \
    ( pxTCB ) = ( pxConstList )->pxIndex->pvOwner;                                            \
}

阻塞链表

当获取不到互斥锁,把当前任务从就绪链表移到阻塞链表

何时触发任务切换

tick中断

高优先级任务变为就绪态

  • 释放信号量导致高优先级任务可以获得信号量
  • 释放互斥锁导致高优先级任务可以获得互斥锁
  • 创建了一个高优先级任务,且调度器已启动
  • ......

当释放信号量,会把等待此信号量的任务从阻塞链表移到就绪链表,如果优先级大于当前正在执行的任务,则调用如下函数触发 xPortPendSVHandler 中断

#define taskYIELD_IF_USING_PREEMPTION() portYIELD_WITHIN_API()

#define portYIELD_WITHIN_API portYIELD

#define portYIELD()                                            \
{                                                            \
    /* Set a PendSV to request a context switch. */            \
    portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;            \
    __DSB();                                                \
    __ISB();                                                \
}