FreeRTOS空闲任务

空闲任务在启动调度器的时候被创建

/* 启动调度器 */
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();
		}
	}
}

猜你喜欢

转载自blog.csdn.net/lushoumin/article/details/88049195