目录
1 任务挂起
任务挂起与任务删除类似
任务挂起业务流程:
- 从就绪列表中删除
- 从事件列表中删除
- 添加任务到挂起列表中
- 开始任务调度
源码分析
void vTaskSuspend( TaskHandle_t xTaskToSuspend )
{
TCB_t *pxTCB;
//进入临界段----原理之后会讲
taskENTER_CRITICAL();
{
/* 获取任务控制块 */
pxTCB = prvGetTCBFromHandle( xTaskToSuspend );
//trace是用户自己实现,不用分析
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 )
{
/*如果是当前任务,立即开启任务调度,释放CPU */
configASSERT( uxSchedulerSuspended == 0 );
portYIELD_WITHIN_API();
}
else
{
/*如果调度器没开启,读取当前任务挂起列表的长度
长度相同代表:如果已经把所有任务挂起
*/
if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == uxCurrentNumberOfTasks )
{
/* 那么把当前任务的控制块赋值未NULL,不让任务控制块再使用 */
pxCurrentTCB = NULL;
} //如果还有任务在就绪列表
else
{
//任务上下文切换----后面再讲解
//即再就绪列表中找到优先级最高的任务,进行调度
vTaskSwitchContext();
}
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
2 任务恢复
任务恢复业务流程:
- 从挂起列表中删除
- 添加任务到就绪列表
- 开启任务调度
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 );
/*从挂起列表中移除,就绪任务、挂起任务等都在statelist列表中 */
( void ) uxListRemove( &( pxTCB->xStateListItem ) );
//添加任务到就绪列表
prvAddTaskToReadyList( pxTCB );
/* 判断要恢复的任务,是否大于当前任务优先级
前提条件:已经使能了抢占式调度器
*/
if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
{
/* 释放CPU的使用权,开始内核调度 */
taskYIELD_IF_USING_PREEMPTION();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
//退出临界段
taskEXIT_CRITICAL();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
另外有在中断中恢复任务函数:因为有调度,这是不允许的,所以有特殊的在中断中调度的任务函数 xTaskResumeFromISR