空闲任务在启动调度器的时候被创建
/* 启动调度器 */
void vTaskStartScheduler( void )
{
BaseType_t xReturn;
#if (configSUPPORT_STATIC_ALLOCATION == 1)
{
......
}
#else
{
/* 创建空闲任务 */
xReturn = xTaskCreate(prvIdleTask, configIDLE_TASK_NAME, configMINIMAL_STACK_SIZE,
(void *)NULL, portPRIVILEGE_BIT, &xIdleTaskHandle);
}
#endif
....
if(xReturn == pdPASS)
{
......
/* 启动调度器 */
if(xPortStartScheduler() != pdFALSE)
{
}
else
{
}
}
else
{
......
}
......
}
空闲任务的作用包括:保证系统至少有一个任务在运行、检查等待终结列表中是否有任务并释放它们。
/* 空闲任务 */
static portTASK_FUNCTION(prvIdleTask, pvParameters)
{
(void)pvParameters;
portTASK_CALLS_SECURE_FUNCTIONS();
for(;;)
{
/* 检查等待终结任务列表,释放所有等待终结的任务 */
prvCheckTasksWaitingTermination();
#if (configUSE_PREEMPTION == 0)
{
taskYIELD();
}
#endif
#if ((configUSE_PREEMPTION == 1) && (configIDLE_SHOULD_YIELD == 1))
{
/* 空闲任务优先级所在就绪列表中,还有其他任务 */
if(listCURRENT_LIST_LENGTH(&(pxReadyTasksLists[tskIDLE_PRIORITY])) > (UBaseType_t)1)
{
/* 能运行到空闲任务,说明高优先级的任务都不在就绪态 */
/* 如果有和空闲任务优先级一样的任务,不切换的话,就要等系统节拍器去切换 */
/* 在这里直接申请切换,效率更高 */
taskYIELD();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif
#if (configUSE_IDLE_HOOK == 1)
{
extern void vApplicationIdleHook(void);
vApplicationIdleHook();
}
#endif
#if (configUSE_TICKLESS_IDLE != 0)
{
TickType_t xExpectedIdleTime;
xExpectedIdleTime = prvGetExpectedIdleTime();
if(xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP)
{
vTaskSuspendAll();
{
configASSERT(xNextTaskUnblockTime >= xTickCount);
xExpectedIdleTime = prvGetExpectedIdleTime();
configPRE_SUPPRESS_TICKS_AND_SLEEP_PROCESSING(xExpectedIdleTime);
if(xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP)
{
traceLOW_POWER_IDLE_BEGIN();
portSUPPRESS_TICKS_AND_SLEEP(xExpectedIdleTime);
traceLOW_POWER_IDLE_END();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
(void)xTaskResumeAll();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif
}
}
其中prvCheckTasksWaitingTermination()函数,负责检查等待终结列表并释放所有等待终结的任务
/* 检查等待终结任务列表,释放所有等待终结的任务 */
static void prvCheckTasksWaitingTermination(void)
{
#if (INCLUDE_vTaskDelete == 1)
{
TCB_t *pxTCB;
/* 将所有等待终结的线程都释放掉 */
while(uxDeletedTasksWaitingCleanUp > (UBaseType_t)0U)
{
/* 进入临界区 */
taskENTER_CRITICAL();
{
/* 从等待终结列表中获取任务 */
pxTCB = listGET_OWNER_OF_HEAD_ENTRY((&xTasksWaitingTermination));
/* 将任务从等待终结列表中移除 */
(void)uxListRemove(&(pxTCB->xStateListItem));
/* 当前任务数减一 */
--uxCurrentNumberOfTasks;
/* 等待终结的任务数减一 */
--uxDeletedTasksWaitingCleanUp;
}
/* 退出临界区 */
taskEXIT_CRITICAL();
/* 释放任务TCB */
prvDeleteTCB(pxTCB);
}
}
#endif
}
任务被删除的时候,如果一个任务删除另外一个任务,被删除任务的堆栈和TCB立即释放。如果一个任务删除自己,则会将任务挂接到检查等待终结列表,有空闲任务负责释放。
/* 删除任务 */
void vTaskDelete(TaskHandle_t xTaskToDelete)
{
TCB_t *pxTCB;
/* 进入临界区 */
taskENTER_CRITICAL();
{
/* 通过任务句柄获取任务TCB */
pxTCB = prvGetTCBFromHandle(xTaskToDelete);
/* 将任务从状态列表中移除,状态列表中没有挂接任何任务 */
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();
}
/* 任务id号加一 */
uxTaskNumber++;
/* 该任务为当前任务 */
if(pxTCB == pxCurrentTCB)
{
/* 任务挂接到等待终结列表 */
vListInsertEnd(&xTasksWaitingTermination, &(pxTCB->xStateListItem));
/* 等待终结任务数加一 */
++uxDeletedTasksWaitingCleanUp;
portPRE_TASK_DELETE_HOOK(pxTCB, &xYieldPending);
}
else
{
/* 当前任务数减一 */
--uxCurrentNumberOfTasks;
/* 删除任务TCB */
prvDeleteTCB(pxTCB);
/* 更新下一个要解除阻塞的时间,防止该任务是先需要解除的任务 */
prvResetNextTaskUnblockTime();
}
traceTASK_DELETE(pxTCB);
}
/* 退出临界区 */
taskEXIT_CRITICAL();
/* 调度器正在运行 */
if(xSchedulerRunning != pdFALSE)
{
/* 该任务为当前任务 */
if(pxTCB == pxCurrentTCB)
{
configASSERT(uxSchedulerSuspended == 0);
/* 请求切换任务 */
portYIELD_WITHIN_API();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
}