FreeRTOS源码理解(六)——时间管理

这篇文章详细解读了FreeRTOS源码中的时间管理机制,包括vTaskDelay函数如何处理延时任务、任务调度与延时列表、任务切换与唤醒条件。同时介绍了OS系统时钟节拍和任务状态管理的相关实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

FreeRTOS源码理解(一)——FreeRTOS思路梳理

FreeRTOS源码理解(二)——中断和列表项

FreeRTOS源码理解(三)——任务

FreeRTOS源码理解(四)——任务调度器

FreeRTOS源码理解(五)——任务切换

FreeRTOS源码理解(六)——时间管理

FreeRTOS源码理解(七)——队列

FreeRTOS源码理解(八)——信号量

FreeRTOS源码理解(九)——事件组和任务通知

FreeRTOS源码理解(十)——软件定时器和空闲任务

FreeRTOS源码理解(十一)——内存管理

FreeRTOS源码理解(十二)——汇总

时间管理

延时函数 vTaskDelay

表示延时多少个系统节拍

  1. 挂起任务调度器
  2. 将延时任务添加到延时列表中 prvAddCurrentTaskToDelayedList
  3. 恢复任务调度器
  4. 任务切换

将延时任务添加到延时列表中

static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait, const BaseType_t xCanBlockIndefinitely )
{
    TickType_t xTimeToWake;
    //获取当前时钟节拍值
    const TickType_t xConstTickCount = xTickCount;
    
    //将当前任务列表项从就绪列表中移除
	if( uxListRemove( &( pxCurrentTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
	{
		/* 当前任务必须在就绪列表中,因此无需检查,可以直接调用端口重置宏 */
		portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
	}
	else
	{
		mtCOVERAGE_TEST_MARKER();
	}

	#if ( INCLUDE_vTaskSuspend == 1 )
	{
        //判断
		if( ( xTicksToWait == portMAX_DELAY ) && ( xCanBlockIndefinitely != pdFALSE ) )
		{
            /* 如果等待时间为最大值,且可以被阻塞;挂起任务,将任务挂载到挂起列表末端 */
			vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xStateListItem ) );
		}
		else
		{
            //计算唤醒时间
			xTimeToWake = xConstTickCount + xTicksToWait;

			//将任务状态列表项的值设为唤醒时间
			listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xStateListItem ), xTimeToWake );

            //判断是否溢出
			if( xTimeToWake < xConstTickCount )
			{
                //xTimeToWake溢出,将任务移到溢出列表(pxOverflowDelayedTaskList)中
				vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );
			}
			else
			{
				//没有溢出,移到延时列表(pxDelayedTaskList)中
				vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );

				//更新xNextTaskUnblockTime(取消延时,唤醒任务的最近时刻)
				if( xTimeToWake < xNextTaskUnblockTime )
				{
					xNextTaskUnblockTime = xTimeToWake;
				}
				else
				{
					mtCOVERAGE_TEST_MARKER();
				}
			}
		}
	}
}

OS系统时钟节拍

BaseType_t xTaskIncrementTick( void )
{
    TCB_t * pxTCB;
    TickType_t xItemValue;
    BaseType_t xSwitchRequired = pdFALSE;

	/* 每个时钟节拍中断调用一次本函数,增加时钟节拍计数器xTickCount的值,并检查是否有任务需要取消阻塞 */
	traceTASK_INCREMENT_TICK( xTickCount );
	if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
	{
		/* 增加系统时钟节拍计数器 */
		const TickType_t xConstTickCount = xTickCount + 1;

		xTickCount = xConstTickCount;

        //如果溢出则交换延时列表指针和溢出列表指针
		if( xConstTickCount == ( TickType_t ) 0U )
		{
			taskSWITCH_DELAYED_LISTS();
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}

		/* 查看是否有任务延时时间到了 */
		if( xConstTickCount >= xNextTaskUnblockTime )
		{
			for( ;; )
			{
				if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE )
				{
					/* 延时列表为空,设置xNextTaskUnblockTime为最大值 */
					xNextTaskUnblockTime = portMAX_DELAY; 
					break;
				}
				else
				{
					/* 延时列表不为空 */
					pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList );
					xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xStateListItem ) );

                    /* 判断任务延时是否到了 */
					if( xConstTickCount < xItemValue )
					{
						/* 没到,更新xNextTaskUnblockTime */
						xNextTaskUnblockTime = xItemValue;
						break;
					}
					else
					{
						mtCOVERAGE_TEST_MARKER();
					}

					/* 到了,需要唤醒任务 */
                    /* 将任务从延时列表中移出 */
					( void ) uxListRemove( &( pxTCB->xStateListItem ) );

					/* 判断任务是否在等待其他事件,比如信号量等;如果有则移出相应列表 */
					if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
					{
						( void ) uxListRemove( &( pxTCB->xEventListItem ) );
					}
					else
					{
						mtCOVERAGE_TEST_MARKER();
					}

					/* 将任务加入到就绪列表 */
					prvAddTaskToReadyList( pxTCB );

					/* 抢占式调度? */
					#if (  configUSE_PREEMPTION == 1 )
					{
						/* 抢占式调度器的话,判断解除阻塞状态的任务优先级和当前任务的优先级;解除的任务优先级更高的话进行一次任务切换 */
						if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
						{
							xSwitchRequired = pdTRUE;
						}
						else
						{
							mtCOVERAGE_TEST_MARKER();
						}
					}
					#endif /* configUSE_PREEMPTION */
				}
			}
		}

		/* 使能了时间片的话还需要处理同优先级下的任务之间的调度 */
		#if ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) )
		{
			if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ pxCurrentTCB->uxPriority ] ) ) > ( UBaseType_t ) 1 )
			{
				xSwitchRequired = pdTRUE;
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		#endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) */

        //使能了时间钩子?
		#if ( configUSE_TICK_HOOK == 1 )
		{
			if( uxPendedTicks == ( UBaseType_t ) 0U )
			{
				vApplicationTickHook();
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		#endif /* configUSE_TICK_HOOK */
	}
	else
	{
		++uxPendedTicks;

		/* The tick hook gets called at regular intervals, even if the
		scheduler is locked. */
		#if ( configUSE_TICK_HOOK == 1 )
		{
			vApplicationTickHook();
		}
		#endif
	}

	#if ( configUSE_PREEMPTION == 1 )
	{
		if( xYieldPending != pdFALSE )
		{
			xSwitchRequired = pdTRUE;
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}
	}
	#endif /* configUSE_PREEMPTION */

	return xSwitchRequired;
}

文档汇总

文档汇总

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值