目录
任务的挂起与恢复的API函数
挂起:挂起任务类似暂停,可恢复;删除任务,无法恢复,类似“人死两清”。
恢复:恢复被挂起的任务
FromISR: 带FromISR后缀是在中断函数中专用的API函数
任务挂起函数介绍
void vTaskSuspend(TaskHandle_t xTaskToSuspend)
此函数用于挂起任务,使用时需将宏INCLUDE_vTaskSuspend配置为1。
无论优先级如何,被挂起的任务都将不再被执行,直到任务被恢复。
注意:当传入的参数为NULL,则代表挂起任务自身(当前正在运行的任务)
任务恢复函数介绍
void vTaskResume(TaskHandle_t xTaskToResume)
使用该函数注意宏:INCLUDE_vTaskSuspend必须定义为1
注意:任务无论被 vTaskSuspend 挂起多少次,只需在任务中调用 vTakResume()恢复一次,就可以继续运行。且被恢复的任务会进入就绪态!
中断中恢复函数
BaseType_t xTaskResumeFromISR(TaskHandle_t xTaskToResume)
xTaskResumeFromISR返回值描述如下:
使用该函数注意宏: INCLUDE_vTaskSuspend和INCLUDE_xTaskResumeFromISR必须定义为1
该函数专用于中断服务函数中,用于解挂被挂起任务
注意:中断服务程序中要调用freeRTOS的ARI函数则中断优先级不能高于FreeRTOS所管理的最高优先级
vTaskSuspend()任务挂起函数
1.根据任务句柄获取任务控制块,如果任务句柄为NULL,表示挂起任务自身
2.将要挂起的任务从相应的状态列表和事件列表中移除
3.将待挂起任务的任务状态列表向插入到挂起态任务列表末尾
4.判断任务调度器是否运行,在运行,更新下一次阻塞时间,防止被挂起任务为下一次阻塞超时任务
5.如果挂起的是任务自身:
(1)调度器正在运行,强制进行一次任务切换;
(2)调度器没有运行,判断挂起任务数是否等于任务总数,是:代表所有任务均被挂起,则当前控制块赋值为NULL,否:通过函数vTaskSwitchContext寻找下一个最高优先级任务
void vTaskSuspend( TaskHandle_t xTaskToSuspend )
{
/*TCB结构体指针*/
TCB_t *pxTCB;
/*进入临界区*/
taskENTER_CRITICAL();
{
/* If null is passed in here then it is the running task that is
being suspended. */
/*获取要挂起任务TCB控制块*/
pxTCB = prvGetTCBFromHandle( xTaskToSuspend );
/*没实现*/
traceTASK_SUSPEND( pxTCB );
/* Remove task from the ready/delayed list and place in the
suspended list. */
/*移除状态列表项,不管是就绪还是阻塞等状态都移除*/
if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
{
/*检测这个优先级的任务是不是没有了,如果没有了就把32位变量代表此优先级那位置0*/
taskRESET_READY_PRIORITY( pxTCB->uxPriority );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* Is the task waiting on an event also? */
/*判断是否有等待事件*/
if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
{
/*移除等待事件列表项*/
( void ) uxListRemove( &( pxTCB->xEventListItem ) );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/*把TCB的状态列表项重新插入到挂起列表*/
vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xStateListItem ) );
}
/*退出临界区*/
taskEXIT_CRITICAL();
/*调度器是否正在运行*/
if( xSchedulerRunning != pdFALSE )
{
/* Reset the next expected unblock time in case it referred to the
task that is now in the Suspended state. */
/*进入临界区*/
taskENTER_CRITICAL();
{
/*更新下一个阻塞超时时间*/
prvResetNextTaskUnblockTime();
}
/*退出临界区*/
taskEXIT_CRITICAL();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/*判断挂起的任务是不是当前任务*/
if( pxTCB == pxCurrentTCB )
{
/*任务正在运行*/
if( xSchedulerRunning != pdFALSE )
{
/* The current task has just been suspended. */
/*断言*/
configASSERT( uxSchedulerSuspended == 0 );
/*任务切换*/
portYIELD_WITHIN_API();
}
else
/*不是正在运行的任务*/
{
/* The scheduler is not running, but the task that was pointed
to by pxCurrentTCB has just been suspended and pxCurrentTCB
must be adjusted to point to a different task. */
/*判断挂起任务总数等于任务总数*/
if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == uxCurrentNumberOfTasks )
{
/* No other tasks are ready, so set pxCurrentTCB back to
NULL so when the next task is created pxCurrentTCB will
be set to point to it no matter what its relative priority
is. */
/*当前控制块赋值为NULL,代表所有任务都被挂起*/
pxCurrentTCB = NULL;
}
else
/*判断挂起任务总数不等于任务总数*/
{
/*查找下一个最高优先级任务*/
vTaskSwitchContext();
}
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
vTaskResume()任务中恢复函数
1.恢复任务不能是正在运行任务且不能为NULL
2.判断任务是否被挂起,是:就会将该任务在挂起列表中移除,将该任务添加到就绪列表中
3.判断恢复的任务优先级是否大于当前正在运行的 是的话执行任务切换
void vTaskResume( TaskHandle_t xTaskToResume )
{
/*把句柄赋值给任务控制块指针*/
TCB_t * const pxTCB = ( TCB_t * ) xTaskToResume;
/* It does not make sense to resume the calling task. */
configASSERT( xTaskToResume );
/* The parameter cannot be NULL as it is impossible to resume the
currently executing task. */
/*带进来的任务块不能是正在运行任务,不能等于NULL,*/
if( ( pxTCB != NULL ) && ( pxTCB != pxCurrentTCB ) )
{
/*进入临界区*/
taskENTER_CRITICAL();
{ /*判断这个任务是在挂起列表中*/
if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE )
{
traceTASK_RESUME( pxTCB );
/* As we are in a critical section we can access the ready
lists even if the scheduler is suspended. */
/*移除状态列表,不管在什么列表都会被移除*/
( void ) uxListRemove( &( pxTCB->xStateListItem ) );
/*添加到就绪列表中*/
prvAddTaskToReadyList( pxTCB );
/* We may have just resumed a higher priority task. */
/*优先级高于当前运行任务优先级*/
if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
{
/* This yield may not cause the task just resumed to run,
but will leave the lists in the correct state for the
next yield. */
/*任务切换*/
taskYIELD_IF_USING_PREEMPTION();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
/*退出临界区*/
taskEXIT_CRITICAL();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
xTaskResumeFromISR()中断中恢复函数
1.函数portASSERT IF INTERRUPT PRIORITY INVALID(),用于检测:调用freertos的API函数的中断优先级是否在管理范围内及是否全部设置为枪占式优先级位
2.关闭freertos可管理中断,防止被其他的中断打断,并返回关闭前basepri奇存器的值
3.判断是否有挂起任务:
1.有挂起任务,检查调度器是否被挂起
(1)调度器末挂起
①判断恢复的这个任务优先级是否大于正在执行的任务是的话将xYieldRequired标
记为pdTRUE,表示需要进行一次任务切换
②将被恢复的任务从挂起列表中移除
③插入到就绪列表
(2)调度器挂起如果调度器被挂起了,就将恢复的任务插入等待就绪列表
xPendingReadyList,直到调度器被恢复再进行任务的处理
2.无挂起任务 不需操作
BaseType_t xTaskResumeFromISR( TaskHandle_t xTaskToResume )
{
/*返回值*/
BaseType_t xYieldRequired = pdFALSE;
/*赋值给任务控制块指针*/
TCB_t * const pxTCB = ( TCB_t * ) xTaskToResume;
/*保存中断状态*/
UBaseType_t uxSavedInterruptStatus;
configASSERT( xTaskToResume );
/* RTOS ports that support interrupt nesting have the concept of a
maximum system call (or maximum API call) interrupt priority.
Interrupts that are above the maximum system call priority are keep
permanently enabled, even when the RTOS kernel is in a critical section,
but cannot make any calls to FreeRTOS API functions. If configASSERT()
is defined in FreeRTOSConfig.h then
portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion
failure if a FreeRTOS API function is called from an interrupt that has
been assigned a priority above the configured maximum system call
priority. Only FreeRTOS functions that end in FromISR can be called
from interrupts that have been assigned a priority at or (logically)
below the maximum system call interrupt priority. FreeRTOS maintains a
separate interrupt safe API to ensure interrupt entry is as fast and as
simple as possible. More information (albeit Cortex-M specific) is
provided on the following link:
http://www.freertos.org/RTOS-Cortex-M3-M4.html */
/*检测中断优先级是否在FreeRTOS管理内,还判断是不是抢占式优先级是否为组4*/
portASSERT_IF_INTERRUPT_PRIORITY_INVALID();
/*保存当前中断状态*/
uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
{ /*判断是在挂起列表中*/
if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE )
{ /*未实现*/
traceTASK_RESUME_FROM_ISR( pxTCB );
/* Check the ready lists can be accessed. */
/*调度器没有挂起,正在运行*/
if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
{
/* Ready lists can be accessed so move the task from the
suspended list to the ready list directly. */
/*恢复任务的优先级高于正在运行的优先级*/
if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
{
/*赋值为TRUE*/
xYieldRequired = pdTRUE;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/*从挂起列表移除*/
( void ) uxListRemove( &( pxTCB->xStateListItem ) );
/*添加到就绪列表*/
prvAddTaskToReadyList( pxTCB );
}
else
/*调度器没挂起,没有运行*/
{
/* The delayed or ready lists cannot be accessed so the task
is held in the pending ready list until the scheduler is
unsuspended. */
/*事件列表插入到等待就绪事件列表里面,直到调度器被恢复,再从等待列表移除到就绪列表*/
vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) );
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
/*设中断状态*/
portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
/*返回值,TRUE需要任务切换,FLASH不需要任务切换*/
return xYieldRequired;
}