FreeRTOS任务相关API函数---查询/改变某个任务的优先级+获取全部/某个任务状态信息

本文是《ALIENTEK STM32F429 FreeRTOS 开发教程》第十一章学习笔记
第一章笔记–FreeRTOS简介与源码下载
第二章笔记–FreeRTOS在STM32F4上移植
第三章笔记-FreeRTOS系统配置
第四章笔记-FreeRTOS中断分析
第四章笔记补充-FreeRTOS临界段代码
第五章笔记-FreeRTOS任务基础
第六章笔记-FreeRTOS任务API函数的使用
第七章笔记-FreeRTOS列表和列表项
第八章笔记-1-FreeRTOS任务创建
第八章笔记-2-FreeRTOS任务调度器开启
第九章笔记-FreeRTOS任务切换
第十章笔记-FreeRTOS系统内核控制函数

1. uxTaskPriorityGet()

查询某个任务的优先级

UBaseType_t uxTaskPriorityGet( TaskHandle_t xTask )
{
    TCB_t *pxTCB;
    UBaseType_t uxReturn;

    taskENTER_CRITICAL();
    {
        pxTCB = prvGetTCBFromHandle( xTask );
        uxReturn = pxTCB->uxPriority;
    }
    taskEXIT_CRITICAL();

    return uxReturn;
}

xTask:查找任务的任务句柄

taskENTER_CRITICA()和taskEXIT_CRITICAL():屏蔽中断和打开中断即进入和退出临界区

prvGetTCBFromHandle( xTask ):返回任务的TCB的指针,原型为:

#define prvGetTCBFromHandle( pxHandle ) ( ( ( pxHandle ) == NULL ) ? ( TCB_t * ) pxCurrentTCB : ( TCB_t * ) ( pxHandle ) )

这个宏定义可以检查,参数是否为空,和返回相应的TCB指针。

uxReturn = pxTCB->uxPriority:将TCB块中的任务优先级取出赋值用来作为函数返回值

2. vTaskPrioritySet()

改变某个任务的任务优先级

void vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority )
{
    TCB_t *pxTCB;
    UBaseType_t uxCurrentBasePriority, uxPriorityUsedOnEntry;
    BaseType_t xYieldRequired = pdFALSE;
    configASSERT( ( uxNewPriority < configMAX_PRIORITIES ) );

    if( uxNewPriority >= ( UBaseType_t ) configMAX_PRIORITIES )
    {
        uxNewPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U;
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }
    taskENTER_CRITICAL();
    {
        pxTCB = prvGetTCBFromHandle( xTask );
        traceTASK_PRIORITY_SET( pxTCB, uxNewPriority );
        #if ( configUSE_MUTEXES == 1 )
        {
            uxCurrentBasePriority = pxTCB->uxBasePriority;
        }
        #else
        {
            uxCurrentBasePriority = pxTCB->uxPriority;
        }
        #endif
        if( uxCurrentBasePriority != uxNewPriority )
        {
            if( uxNewPriority > uxCurrentBasePriority )
            {
                if( pxTCB != pxCurrentTCB )
                {   
                    if( uxNewPriority >= pxCurrentTCB->uxPriority )
                    {
                        xYieldRequired = pdTRUE;
                    }
                    else
                    {
                        mtCOVERAGE_TEST_MARKER();
                    }

                }
                else
                {

                }
            }
            else if( pxTCB == pxCurrentTCB )
            {
                xYieldRequired = pdTRUE;
            }
            else
            {

            }
            uxPriorityUsedOnEntry = pxTCB->uxPriority;
            #if ( configUSE_MUTEXES == 1 )
            {
                if( pxTCB->uxBasePriority == pxTCB->uxPriority )
                {
                    pxTCB->uxPriority = uxNewPriority;
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }
                pxTCB->uxBasePriority = uxNewPriority;
            }
            #else
            {
                pxTCB->uxPriority = uxNewPriority;
            }
            #endif
            if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL )
            {
            listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxNewPriority ) )
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
            if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xStateListItem ) ) != pdFALSE )
            {
                if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
                {
                    portRESET_READY_PRIORITY( uxPriorityUsedOnEntry, uxTopReadyPriority );
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }
                prvAddTaskToReadyList( pxTCB );
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
            if( xYieldRequired != pdFALSE )
            {
                taskYIELD_IF_USING_PREEMPTION();
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
            ( void ) uxPriorityUsedOnEntry;
            }
        }
        taskEXIT_CRITICAL();
    }

xTask:改变的任务的任务句柄

uxNewPriority:任务要使用的新的优先级,范围是0~configMAX_PRIORITIES-1

configASSERT( ( uxNewPriority < configMAX_PRIORITIES ) ):若使用的新的优先级大于最大优先级则断言输出这一情况

if( uxNewPriority >= ( UBaseType_t ) configMAX_PRIORITIES ){…}: 确保新的优先级有效,如果大于最大优先级,则 “ uxNewPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U ” 将新的优先级赋值为最大优先级

#if ( configUSE_MUTEXES == 1 ){…}#else{…}#endif:若使用互斥信号量时,uxCurrentBasePriority = pxTCB->uxBasePriority;使用基础优先级,不使用互斥信号量时,uxCurrentBasePriority = pxTCB->uxPriority;

if( uxCurrentBasePriority != uxNewPriority ):如果任务优先级不等于要改变的优先级,则进行改变的相关操作

if( uxNewPriority > uxCurrentBasePriority ) { if( pxTCB != pxCurrentTCB ) { if( uxNewPriority >= pxCurrentTCB->uxPriority ):修改优先级高于现在优先级时,而且要修改任务不是当前执行任务,重要的是修改优先级的值大于现在执行任务的优先值,要执行xYieldRequired = pdTRUE,目的是要在后面执行任务切换,因为改变了优先级后,最高优先级任务就发生变化,处理器要去执行高优先级任务

else{}: 相对于if( pxTCB != pxCurrentTCB ),因为正在运行任务是要改变优先级的任务,而正在运行的任务必然是最高优先级的任务,所以改变优先级后不需要进行任务切换

else if( pxTCB == pxCurrentTCB ):相对于if( uxNewPriority > uxCurrentBasePriority )这条语句,即如果修改优先级的值小于现在的优先级,但是要修改的任务是现在正在执行的任务,则有可能修改后优先值不是最高优先级,需要进行任务切换,所以xYieldRequired = pdTRUE;

else{}:相对于if( uxNewPriority > uxCurrentBasePriority )和else if( pxTCB == pxCurrentTCB ),即要修改成的优先级值小于修改前优先级,并且修改任务不是当前执行任务,所以还是会执行最高优先级任务

uxPriorityUsedOnEntry = pxTCB->uxPriority:将改变前的优先级值记下,要在后面改变任务的就绪列表位置里用到

#if ( configUSE_MUTEXES == 1 ){ if( pxTCB->uxBasePriority == pxTCB->uxPriority ):当使用互斥信号量,基础优先级等于任务优先级时,即不使用继承优先级,执行pxTCB->uxPriority = uxNewPriority;pxTCB->uxBasePriority = uxNewPriority;将要更新的优先级值赋值到TCB的任务优先级和基础优先级上

if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL ):如果该事件列表项的值未用于其它操作,则执行listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxNewPriority ) );重置该事件列表项值

if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xStateListItem ) ) != pdFALSE ):判断要改变任务是不是在就绪列表中,如果是在就绪列表中则要将其放在新优先级的列表里,如果是在延迟或者阻塞列表,则只需要改变优先级变量即可。

//检查列表项是否在列表中
#define listIS_CONTAINED_WITHIN( pxList, pxListItem ) ( ( BaseType_t ) ( ( pxListItem )->pvContainer == ( void * ) ( pxList ) ) )

if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ):将任务绪前先将其从就绪列表删除

portRESET_READY_PRIORITY( uxPriorityUsedOnEntry, uxTopReadyPriority ):优先级复位宏调用

#define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) )

if( xYieldRequired != pdFALSE ) { taskYIELD_IF_USING_PREEMPTION(): 如果之前代码中判断需要进行一次任务切换,则执行taskYIELD_IF_USING_PREEMPTION()

#define taskYIELD_IF_USING_PREEMPTION() portYIELD_WITHIN_API()
#define portYIELD_WITHIN_API portYIELD
#define portYIELD()                             
{                                               
    portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;                     
    __dsb( portSY_FULL_READ_WRITE );                            
    __isb( portSY_FULL_READ_WRITE );            
}

开启PendSV中断,并用dsb和isb指令 完成数据同步隔离和指令同步隔离

( void ) uxPriorityUsedOnEntry:有可能没有使用到这一变量,这里是为了消除编译器的警告。

3. uxTaskGetSystemState()

此函数用于获取系统中所有任务的任务状态,每个任务的状态信息保存在一个TaskStatus_t类型的结构体里面,这个结构体里面包含了任务的任务句柄、任务名字、堆栈、优先级等信息

要使用此函数则要将宏configUSE_TRACE_FACILITY设置为1

UBaseType_t uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray, const UBaseType_t uxArraySize, uint32_t * const pulTotalRunTime )
    {
    UBaseType_t uxTask = 0, uxQueue = configMAX_PRIORITIES;

        vTaskSuspendAll();
        {
            if( uxArraySize >= uxCurrentNumberOfTasks )
            {
                do
                {
                    uxQueue--;
                    uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &( pxReadyTasksLists[ uxQueue ] ), eReady );

                } while( uxQueue > ( UBaseType_t ) tskIDLE_PRIORITY );
                uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( List_t * ) pxDelayedTaskList, eBlocked );
                uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( List_t * ) pxOverflowDelayedTaskList, eBlocked );

                #if( INCLUDE_vTaskDelete == 1 )
                {
                    uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xTasksWaitingTermination, eDeleted );
                }
                #endif

                #if ( INCLUDE_vTaskSuspend == 1 )
                {
                    uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xSuspendedTaskList, eSuspended );
                }
                #endif

                #if ( configGENERATE_RUN_TIME_STATS == 1)
                {
                    if( pulTotalRunTime != NULL )
                    {
                        #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE
                            portALT_GET_RUN_TIME_COUNTER_VALUE( ( *pulTotalRunTime ) );
                        #else
                            *pulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE();
                        #endif
                    }
                }
                #else
                {
                    if( pulTotalRunTime != NULL )
                    {
                        *pulTotalRunTime = 0;
                    }
                }
                #endif
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
        ( void ) xTaskResumeAll();

        return uxTask;
    }

pxTaskStatusArray:指向TaskStatus_t结构体类型的数组首地址,每个任务至少需要一个TaskStaus_t结构体,任务的数量可以使用函数uxTaskGetNumberOfTasks()

结构体TaskStatus_t:

typedef struct xTASK_STATUS
{
    TaskHandle_t xHandle;           //任务句柄
    const char *pcTaskName;         //任务名字
    UBaseType_t xTaskNumber;        //任务编号
    eTaskState eCurrentState;       //当前任务状态
    UBaseType_t uxCurrentPriority;  //任务当前优先级
    UBaseType_t uxBasePriority;     //任务基础优先级
    uint32_t ulRunTimeCounter;      //任务运行的总时间
    StackType_t *pxStackBase;       //堆栈基地址
    uint16_t usStackHighWaterMark;  //从任务创建以来任务堆栈剩余的最小大小,此值太小说明堆栈有溢出的风险
} TaskStatus_t;

uxArraySize: 保存任务状态数组的数组的大小

pulTotalRunTime:如果configGENERATE_RUN_TIME_STATS为1的话此参数用来保存系统总的运行时间

返回值:统计到的任务状态的个数,即填写到数组pxTaskStatusArray中的个数,此值等于函数uxTaskGetNumberOfTasks()的返回值。

UBaseType_t uxTaskGetNumberOfTasks( void )
{
    return uxCurrentNumberOfTasks;
}

vTaskSuspendAll():挂起调度器

prvListTasksWithinSingleList()
填充taskstatus_t结构对每个任务的信息是从pxlist列表引用(这可能是一个就绪列表,延迟列表,阻塞列表,等

static UBaseType_t prvListTasksWithinSingleList( TaskStatus_t *pxTaskStatusArray, List_t *pxList, eTaskState eState )
    {
    volatile TCB_t *pxNextTCB, *pxFirstTCB;
    UBaseType_t uxTask = 0;

        if( listCURRENT_LIST_LENGTH( pxList ) > ( UBaseType_t ) 0 )
        {
            listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );
            do
            {
                listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );
                vTaskGetInfo( ( TaskHandle_t ) pxNextTCB, &( pxTaskStatusArray[ uxTask ] ), pdTRUE, eState );
                uxTask++;
            } while( pxNextTCB != pxFirstTCB );
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }

        return uxTask;
    }

遍历pxlist列表通过函数vTaskGetInfo()并把每个任务信息赋值到pxTaskStatusArray列表中

uxTask += …..: 分别将各列表中任务信息取出放在pxTaskStatusArray列表里,返回值加到pxTask即总共任务个数

4. vTaskGetInfo()

函数用来获取单个指定的任务状态,任务的状态信息放入参数pxTaskStatus里

使用此函数将宏configUSE_TRACE_FACILITY设置为1

void vTaskGetInfo( TaskHandle_t xTask, TaskStatus_t *pxTaskStatus, BaseType_t xGetFreeStackSpace, eTaskState eState )
    {
        TCB_t *pxTCB;
        pxTCB = prvGetTCBFromHandle( xTask );

        pxTaskStatus->xHandle = ( TaskHandle_t ) pxTCB;
        pxTaskStatus->pcTaskName = ( const char * ) &( pxTCB->pcTaskName [ 0 ] );
        pxTaskStatus->uxCurrentPriority = pxTCB->uxPriority;
        pxTaskStatus->pxStackBase = pxTCB->pxStack;
        pxTaskStatus->xTaskNumber = pxTCB->uxTCBNumber;

        #if ( INCLUDE_vTaskSuspend == 1 )
        {
            if( pxTaskStatus->eCurrentState == eSuspended )
            {
                vTaskSuspendAll();
                {
                    if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
                    {
                        pxTaskStatus->eCurrentState = eBlocked;
                    }
                }
                xTaskResumeAll();
            }
        }
        #endif /* INCLUDE_vTaskSuspend */

        #if ( configUSE_MUTEXES == 1 )
        {
            pxTaskStatus->uxBasePriority = pxTCB->uxBasePriority;
        }
        #else
        {
            pxTaskStatus->uxBasePriority = 0;
        }
        #endif

        #if ( configGENERATE_RUN_TIME_STATS == 1 )
        {
            pxTaskStatus->ulRunTimeCounter = pxTCB->ulRunTimeCounter;
        }
        #else
        {
            pxTaskStatus->ulRunTimeCounter = 0;
        }
        #endif
        if( eState != eInvalid )
        {
            pxTaskStatus->eCurrentState = eState;
        }
        else
        {
            pxTaskStatus->eCurrentState = eTaskGetState( xTask );
        }
        if( xGetFreeStackSpace != pdFALSE )
        {
            #if ( portSTACK_GROWTH > 0 )
            {
                pxTaskStatus->usStackHighWaterMark = prvTaskCheckFreeStackSpace( ( uint8_t * ) pxTCB->pxEndOfStack );
            }
            #else
            {
                pxTaskStatus->usStackHighWaterMark = prvTaskCheckFreeStackSpace( ( uint8_t * ) pxTCB->pxStack );
            }
            #endif
        }
        else
        {
            pxTaskStatus->usStackHighWaterMark = 0;
        }
    }

xTask:要查找的任务句柄

pxTaskStatus: 指向类型为TaskStatus_t的结构体

xGetFreeStackSpace:结构体TaskStatus_t中有个字段usStackHighWaterMark来保存任务运行以来任务堆栈剩余的历史最小大小,计算要花费时间,xGetFreeStackSpace设置为pdFALSE可以跳过这一步骤

eState: TaskStatus_t中的字段eCurrentState用来保存任务运行状态,这个字段是eTaskState类型

eTaskState:

typedef enum
{
    eRunning = 0,   //运行状态
    eReady,         //就绪态
    eBlocked,       //阻塞态
    eSuspended,     //挂起态
    eDeleted,       //任务被删除
    eInvalid        //无效
} eTaskState;

pxTCB = prvGetTCBFromHandle( xTask ):通过任务句柄获取任务的TCB

pxTaskStatus->xHandle = ( TaskHandle_t ) pxTCB;
pxTaskStatus->pcTaskName = ( const char * ) &( pxTCB->pcTaskName [ 0 ] );
pxTaskStatus->uxCurrentPriority = pxTCB->uxPriority;
pxTaskStatus->pxStackBase = pxTCB->pxStack;
pxTaskStatus->xTaskNumber = pxTCB->uxTCBNumber;

把TCB中的相关状态信息,放入pxTaskStatus里

if( pxTaskStatus->eCurrentState == eSuspended ):如果任务在暂停列表中,那么它实际上有可能无限期地被阻塞——所以实际上它应该被报告为处于阻塞状态。

if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ){pxTaskStatus->eCurrentState = eBlocked:如果TCB的事件列表中有列表项则将状态变为阻塞

#if ( configUSE_MUTEXES == 1 );#if ( configGENERATE_RUN_TIME_STATS == 1 ) :用来条件编译是否获取基础优先级和任务运行总时间

if( eState != eInvalid ):如果传入任务运行状态参数不是无效,则放入pxTaskStatus里pxTaskStatus->eCurrentState = eState; 如果参数是无效则调用函数获得运行状态放入pxTaskStatus->eCurrentState = eTaskGetState( xTask );

if( xGetFreeStackSpace != pdFALSE ):如果xGetFreeStackSpace参数不是pdFALSE则用usStackHighWaterMark记录堆栈历史剩余最小大小

prvTaskCheckFreeStackSpace( ( uint8_t * ) pxTCB->pxEndOfStack );prvTaskCheckFreeStackSpace( ( uint8_t * ) pxTCB->pxStack ): 用来计算递增堆栈和递减堆栈的历史剩余最小大小

你可能感兴趣的:(FreeRTOS)