FreeRTOS之vTaskDelete实现分析
这里写自定义目录标题
1 函数接口
1.1 函数接口
void vTaskDelete( TaskHandle_t xTaskToDelete )
1.2 函数参数简介
- TaskHandle_t xTaskToDelete 要删除任务的句柄,但这个句柄其实就是我们申请任务时创建的TCB,这个参数在传入的时候可以设置为NULL,表示要删除的是自己当前的任务。
2 vTaskDelete的调用关系
2.1 调用关系
|- vTaskDelete
|- pxTCB = prvGetTCBFromHandle( xTaskToDelete );
|- uxListRemove( &( pxTCB->xStateListItem ) )
|- taskRESET_READY_PRIORITY( pxTCB->uxPriority );
|- vListInsertEnd( &xTasksWaitingTermination, &( pxTCB->xStateListItem ) );
|- taskYIELD_WITHIN_API();
2.2 调用关系示意图
3 函数源码分析
3.1 vTaskDelete
- pxTCB = prvGetTCBFromHandle( xTaskToDelete ); 获取要删除任务的TCB
- uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 将当前要删除的任务从pxReadyTasksLists对应优先级的链表里面删除,并判断该优先级的任务数是不是为0了,如果当前该优先级的链表里已经没有任务则需要调用taskRESET_READY_PRIORITY( pxTCB->uxPriority );去做重置将该优先级在uxTopReadyPriority中mask掉。
- vListInsertEnd( &xTasksWaitingTermination, &( pxTCB->xStateListItem ) ); 如果当前的任务处于运行状态,则将当前要删除的任务放入到xTasksWaitingTermination列表,等到idle task执行的时候再去执行删除操作。任务是否处于调度状态的判断依据是xSchedulerRunning是否是pdTRUE,该状态位在执行vTaskStartScheduler函数时被置位,在执行vTaskEndScheduler函数时被置位pdFALSE,因此只要是当前的系统调度没有停就需要将要删除的任务的TCB加入到xTasksWaitingTermination链表中。
- ++uxDeletedTasksWaitingCleanUp 记录等待清理任务的数量,在idle task或者vTaskEndScheduler执行时,以该全局变量作为清理数量的标准。
- xDeleteTCBInIdleTask = pdTRUE; 标记当前任务要再idle task里面做删除工作。
- taskYIELD_WITHIN_API();或者prvYieldCore( pxTCB->xTaskRunState ); 将处理器让出去,调度其他的任务。
void vTaskDelete( TaskHandle_t xTaskToDelete )
{
TCB_t * pxTCB;
BaseType_t xDeleteTCBInIdleTask = pdFALSE;
BaseType_t xTaskIsRunningOrYielding;
traceENTER_vTaskDelete( xTaskToDelete );
taskENTER_CRITICAL();
{
获取当前要删除任务的TCB,如果xTaskToDelete 为空则表示要删除当前正在运行的任务,否则就找到对应任务的TCB。
pxTCB = prvGetTCBFromHandle( xTaskToDelete );
configASSERT( pxTCB != NULL );
把当前要删除的任务从ready/delayed 链表中删除,并判断任务优先级的链表任务数是否为0
if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
{
如果当前要删除的任务优先级所对应的链表任务数为0,则将该优先级在uxTopReadyPriority中mask掉。
taskRESET_READY_PRIORITY( pxTCB->uxPriority );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
判断当前的任务是否在一个event的链表,如果是则通过uxListRemove将其移除
if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
{
( void ) uxListRemove( &( pxTCB->xEventListItem ) );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* Increment the uxTaskNumber also so kernel aware debuggers can
* detect that the task lists need re-generating. This is done before
* portPRE_TASK_DELETE_HOOK() as in the Windows port that macro will
* not return. */
uxTaskNumber++;
通过taskTASK_IS_RUNNING_OR_SCHEDULED_TO_YIELD来判断当前的任务是否在运行状态,如果其xTaskRunState被设置为-1则表明其不处于运行状态,正常运行的任务其xTaskRunState值会被设置为所运行的core的id。
xTaskIsRunningOrYielding = taskTASK_IS_RUNNING_OR_SCHEDULED_TO_YIELD( pxTCB );
根据xSchedulerRunning 来判断当前的是否还处于正常的调度状态,该全局变量在vTaskStartScheduler函数被执行时设置为pdTRUE,在vTaskEndScheduler时被设置为pdFALSE
if( ( xSchedulerRunning != pdFALSE ) && ( xTaskIsRunningOrYielding != pdFALSE ) )
{
为了防止该任务在其他core上还有运行的,所以将该任务添加到xTasksWaitingTermination链表上,等idle task运行时再做清理工作。
vListInsertEnd( &xTasksWaitingTermination, &( pxTCB->xStateListItem ) );
标记当前需要做清理的任务数
++uxDeletedTasksWaitingCleanUp;
/* Call the delete hook before portPRE_TASK_DELETE_HOOK() as
* portPRE_TASK_DELETE_HOOK() does not return in the Win32 port. */
traceTASK_DELETE( pxTCB );
用以标记有任务需要删除,如果需要设置为pdTRUE,则在后面会调用prvDeleteTCB( pxTCB );释放掉这块内存空间。
xDeleteTCBInIdleTask = pdTRUE;
/* The pre-delete hook is primarily for the Windows simulator,
* in which Windows specific clean up operations are performed,
* after which it is not possible to yield away from this task -
* hence xYieldPending is used to latch that a context switch is
* required. */
#if ( configNUMBER_OF_CORES == 1 )
portPRE_TASK_DELETE_HOOK( pxTCB, &( xYieldPendings[ 0 ] ) );
#else
portPRE_TASK_DELETE_HOOK( pxTCB, &( xYieldPendings[ pxTCB->xTaskRunState ] ) );
#endif
在SMP系统给按任务让出CPU,让其他任务去运行
#if ( configNUMBER_OF_CORES > 1 )
{
if( taskTASK_IS_RUNNING( pxTCB ) == pdTRUE )
{
if( pxTCB->xTaskRunState == ( BaseType_t ) portGET_CORE_ID() )
{
configASSERT( uxSchedulerSuspended == 0 );
taskYIELD_WITHIN_API();
}
else
{
prvYieldCore( pxTCB->xTaskRunState );
}
}
}
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
}
else
{
--uxCurrentNumberOfTasks;
traceTASK_DELETE( pxTCB );
/* Reset the next expected unblock time in case it referred to
* the task that has just been deleted. */
prvResetNextTaskUnblockTime();
}
}
taskEXIT_CRITICAL();
/* If the task is not deleting itself, call prvDeleteTCB from outside of
* critical section. If a task deletes itself, prvDeleteTCB is called
* from prvCheckTasksWaitingTermination which is called from Idle task. */
if( xDeleteTCBInIdleTask != pdTRUE )
{
prvDeleteTCB( pxTCB );
}
/* Force a reschedule if it is the currently running task that has just
* been deleted. */
#if ( configNUMBER_OF_CORES == 1 )
{
if( xSchedulerRunning != pdFALSE )
{
if( pxTCB == pxCurrentTCB )
{
configASSERT( uxSchedulerSuspended == 0 );
taskYIELD_WITHIN_API();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
}
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
traceRETURN_vTaskDelete();
}
3.2 uxListRemove
- pxList = pxItemToRemove->pxContainer; 通过pxContainer找到当前任务优先级所对应链表的链表头
- pxList->uxNumberOfItems 返回当前任务优先级链表还剩余的任务数,一般用于判断链表所挂任务是否为0,用以来确定当前任务的优先级是否需要mask掉。
UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )
{
/* The list item knows which list it is in. Obtain the list from the list
* item. */
List_t * const pxList = pxItemToRemove->pxContainer;
traceENTER_uxListRemove( pxItemToRemove );
pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;
/* Only used during decision coverage testing. */
mtCOVERAGE_TEST_DELAY();
/* Make sure the index is left pointing to a valid item. */
if( pxList->pxIndex == pxItemToRemove )
{
pxList->pxIndex = pxItemToRemove->pxPrevious;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
pxItemToRemove->pxContainer = NULL;
( pxList->uxNumberOfItems ) = ( UBaseType_t ) ( pxList->uxNumberOfItems - 1U );
traceRETURN_uxListRemove( pxList->uxNumberOfItems );
return pxList->uxNumberOfItems;
}
原文地址:https://blog.csdn.net/u014100559/article/details/143984565
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!