任务管理
注:本次引用的两个重要函数的源码来源是FreeRTOS_V9.0中源码
一、函数分析
任务挂起函数
#if ( INCLUDE_vTaskSuspend == 1 )
void vTaskSuspend( TaskHandle_t xTaskToSuspend )
{
TCB_t *pxTCB;
/*进入临界态*/
taskENTER_CRITICAL();
{
/* 如果要挂起的任务的TCB返回值是NULL就说明,将要挂起的任务是正在运行的任务 */
pxTCB = prvGetTCBFromHandle( xTaskToSuspend );
traceTASK_SUSPEND( pxTCB );
/*查找将要放入挂起态链表的任务,在不在就绪态链表或者延时链表中*/
if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
{
taskRESET_READY_PRIORITY( pxTCB->uxPriority );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/*查看将要挂起的函数在不在等待事件 */
if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
{
/*如果在等待事件,就将其从等待事件中移除*/
( void ) uxListRemove( &( pxTCB->xEventListItem ) );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/*将要挂起的任务放入挂起态链表的尾部*/
vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xStateListItem ) );
}
/*退出临界态*/
taskEXIT_CRITICAL();
/* 判断调度器是否在运行 */
if( xSchedulerRunning != pdFALSE )
{
taskENTER_CRITICAL();
{
/*复位下一次解除阻塞的时间*/
prvResetNextTaskUnblockTime();
}
taskEXIT_CRITICAL();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/*如果挂起的任务是当前在运行的任务*/
if( pxTCB == pxCurrentTCB )
{
/*当调度器在运行*/
if( xSchedulerRunning != pdFALSE )
{
/* 刚刚被挂起 */
configASSERT( uxSchedulerSuspended == 0 );
/*请求发起一次任务调度*/
portYIELD_WITHIN_API();
}
else
{
/* 如果调度器不运行,且所有任务都被挂起 */
if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == uxCurrentNumberOfTasks )
{
/* 将TCB指针置空 */
pxCurrentTCB = NULL;
}
else
{
/*将TCB指针指向最高优先级的任务*/
vTaskSwitchContext();
}
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif
任务恢复函数
#if ( INCLUDE_vTaskSuspend == 1 )
void vTaskResume( TaskHandle_t xTaskToResume )
{
TCB_t * const pxTCB = ( TCB_t * ) xTaskToResume;
/* 断言:如果任务不支持挂起,那释放也没有意义 */
configASSERT( xTaskToResume );
/* 参数为空表明恢复正在运行的任务,那是不可能的,那就没有了意义 */
if( ( pxTCB != NULL ) && ( pxTCB != pxCurrentTCB ) )
{
taskENTER_CRITICAL();
{
/*如果任务是挂起的*/
if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE )
{
traceTASK_RESUME( pxTCB );
/* 将任务从挂起态链表中移除 */
( void ) uxListRemove( &( pxTCB->xStateListItem ) );
/*将任务加入到就绪态链表中*/
prvAddTaskToReadyList( pxTCB );
/* 如果恢复的任务是最高优先级的任务 */
if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
{
/* 将任务放到下一个就可以运行的位置,并请求发起任务调度 */
taskYIELD_IF_USING_PREEMPTION();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
taskEXIT_CRITICAL();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif
二、运行机制
挂起任务
1.访问将要挂起的函数的任务句柄,去得到TCB来判断任务是不是正在执行。
2.如果任务不是正在执行,那么从就绪链表、延时链表中查找,找到后将其从其链表中移除。
3.如果没找到,就查看是不是在等待事件,如果是就从事件链表中移除。
4.以上就确保找到了任务所在位置,将其挂载到挂起态链表的尾部。
5.如果调度器在运行,复位下一次解除阻塞的时间。
6.如果是正在运行的任务,刚刚被挂起,就发起一次任务调度。
7.所有任务都不在运行,检测是否还有任务在等待运行,有就将TCB指针指向它,如果没有就将TCB指针置空。
恢复任务
1.将要恢复的任务是正在运行的任务,那是一件荒谬的事。
2.将将要恢复的任务从挂起态链表中移除。
3.将其添加到就绪态链表中。
4.如果恢复的任务是优先级最高的任务,就将其放入将要执行的位置,并申请发生一次任务调度。