当前位置: 首页 > article >正文

FreeRTOS的时间管理

1. vTaskDelay

	void vTaskDelay( const TickType_t xTicksToDelay )
	{
	TickType_t xTimeToWake;
	BaseType_t xAlreadyYielded = pdFALSE;


		/* A delay time of zero just forces a reschedule. */
		/* 延时周期要大于0 */
		if( xTicksToDelay > ( TickType_t ) 0U )
		{
			configASSERT( uxSchedulerSuspended == 0 );
			vTaskSuspendAll();  /* 挂起调度器 */
			{
				traceTASK_DELAY();

				/* A task that is removed from the event list while the
				scheduler is suspended will not get placed in the ready
				list or removed from the blocked list until the scheduler
				is resumed.

				This task cannot be in an event list as it is the currently
				executing task. */

				/* Calculate the time to wake - this may overflow but this is
				not a problem. */
				xTimeToWake = xTickCount + xTicksToDelay;   /* 获取进入函数的时间点并保存在xConstTickCount中 */

				/* We must remove ourselves from the ready list before adding
				ourselves to the blocked list as the same list item is used for
				both lists. */
				  /* 把当前任务从就绪状态链表中移除 */
				if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 )
				{
					/* The current task must be in a ready list, so there is
					no need to check, and the port reset macro can be called
					directly. */
					 /* 取消任务在uxTopReadyPriority中的就绪标记 */
					portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
				}
				else
				{
					mtCOVERAGE_TEST_MARKER();
				}

				

                 /* 将要延时的任务添加到延时列表中 */
				prvAddCurrentTaskToDelayedList( xTimeToWake );
			}
			xAlreadyYielded = xTaskResumeAll();
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}

		/* Force a reschedule if xTaskResumeAll has not already done so, we may
		have put ourselves to sleep. */
		if( xAlreadyYielded == pdFALSE )
		{
			portYIELD_WITHIN_API();
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}
	}

2.prvAddCurrentTaskToDelayedList

static void prvAddCurrentTaskToDelayedList( const TickType_t xTimeToWake )
{
	/* The list item will be inserted in wake time order. */
	/* 设置xItemValue的值为xTimeToWake */
	listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );

    /* 计算得到的任务唤醒时间点小于xConstTickCount,说明发生了溢出 */
	if( xTimeToWake < xTickCount )
	{
		/* Wake time has overflowed.  Place this item in the overflow list. */
		/* 若溢出,就把任务添加到延时溢出列表里 */
		vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCB->xGenericListItem ) );
	}
	else
	{
		/* The wake time has not overflowed, so the current block list is used. */
		/* 没有溢出,把任务添加到延时列表中 */
		vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xGenericListItem ) );

		/* If the task entering the blocked state was placed at the head of the
		list of blocked tasks then xNextTaskUnblockTime needs to be updated
		too. */
		/* 更新xNextTaskUnblockTime */
		if( xTimeToWake < xNextTaskUnblockTime )
		{
			xNextTaskUnblockTime = xTimeToWake;
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}
	}
}

3.xPortSysTickHandler

void xPortSysTickHandler( void )
{
	/* The SysTick runs at the lowest interrupt priority, so when this interrupt
	executes all interrupts must be unmasked.  There is therefore no need to
	save and then restore the interrupt mask value as its value is already
	known. */

/*SysTick以最低的中断优先级运行,因此所有中断都必须取消屏蔽。因此,没有必要保存并恢复中断掩码值,因为其值已经存在已知*/
	( void ) portSET_INTERRUPT_MASK_FROM_ISR();
	{
		/* Increment the RTOS tick. */
		/* 若调度器返回true,触发pendSV异常 */
		if( xTaskIncrementTick() != pdFALSE )
		{
			/* A context switch is required.  Context switching is performed in
			the PendSV interrupt.  Pend the PendSV interrupt. */
			portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
		}
	}
	/* 清除可屏蔽中断,即打开全部中断 */
	portCLEAR_INTERRUPT_MASK_FROM_ISR( 0 );
}

4.xTaskIncrementTick

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

	/* Called by the portable layer each time a tick interrupt occurs.
	Increments the tick then checks to see if the new tick value will cause any
	tasks to be unblocked. */
	traceTASK_INCREMENT_TICK( xTickCount );
	 /* uxSchedulerSuspended表示任务调度器是否挂起,,pdFALSE表示没有被挂起 */
	if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
	{
		/* Increment the RTOS tick, switching the delayed and overflowed
		delayed lists if it wraps to 0. */
		 /* 时钟节拍计数器增加1 */
		++xTickCount;

		{
			/* Minor optimisation.  The tick count cannot change in this
			block. */
			const TickType_t xConstTickCount = xTickCount;

            /* 判断tick是否溢出越界,为0说明发生了溢出 */
			if( xConstTickCount == ( TickType_t ) 0U )
			{
				/* 若溢出,要更新延时列表 */
				taskSWITCH_DELAYED_LISTS();
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}

			/* See if this tick has made a timeout expire.  Tasks are stored in
			the	queue in the order of their wake time - meaning once one task
			has been found whose block time has not expired there is no need to
			look any further down the list. */

			/*查看此标记是否已使超时过期。任务存储在按唤醒时间顺序排列的队列-意味着一次完成一个任务已发现其阻止时间尚未到期,无需再往下*/
			if( xConstTickCount >= xNextTaskUnblockTime )
			{
				/*会一直遍历整个任务延时列表,主要目的是,找到时间片最短的任务,进行切换 */
				for( ;; )
				{
					/* 判断任务延时列表是否为空,即有没有任务在等待调度 */
					if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE )
					{
						/* The delayed list is empty.  Set xNextTaskUnblockTime
						to the maximum possible value so it is extremely
						unlikely that the
						if( xTickCount >= xNextTaskUnblockTime ) test will pass
						next time through. */
						/* 如果没有任务等待,把时间片赋值为最大值,不再调度 */
						xNextTaskUnblockTime = portMAX_DELAY;
						break;
					}
					else
					{
						/* The delayed list is not empty, get the value of the
						item at the head of the delayed list.  This is the time
						at which the task at the head of the delayed list must
						be removed from the Blocked state. */
						/* 若有任务等待,获取延时列表第一个列表项对应的任务控制块*/
						pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList );
						 /* 获取上面任务控制块的状态列表项值 */
						xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) );

                          /* 再次判断这个任务的时间片是否到达 */
						if( xConstTickCount < xItemValue )
						{
							/* It is not time to unblock this item yet, but the
							item value is the time at which the task at the head
							of the blocked list must be removed from the Blocked
							state -	so record the item value in
							xNextTaskUnblockTime. */

							/* 记录xNextTaskUnblockTime */
							xNextTaskUnblockTime = xItemValue;
							break;
						}
						else
						{
							mtCOVERAGE_TEST_MARKER();
						}


						/* It is time to remove the item from the Blocked state. */
						  /* 任务延时时间到,把任务从延时列表中移除 */
						( void ) uxListRemove( &( pxTCB->xGenericListItem ) );

						/* Is the task waiting on an event also?  If so remove
						it from the event list. */
						if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
						{
							/* 再把任务从事件列表中移除 */
							( void ) uxListRemove( &( pxTCB->xEventListItem ) );
						}
						else
						{
							mtCOVERAGE_TEST_MARKER();
						}

						/* Place the unblocked task into the appropriate ready
						list. */
						 /* 把任务添加到就绪列表中 */
						prvAddTaskToReadyList( pxTCB );

						/* A task being unblocked cannot cause an immediate
						context switch if preemption is turned off. */
						 /* 抢占式内核 */
						#if (  configUSE_PREEMPTION == 1 )
						{
							/* Preemption is on, but a context switch should
							only be performed if the unblocked task has a
							priority that is equal to or higher than the
							currently executing task. */
							 /* 判断解除阻塞的任务的优先级是否高于当前任务的优先级 */
							if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
							{
								  /* 如果是的话,就需要进行一次任务切换 */
								xSwitchRequired = pdTRUE;
							}
							else
							{
								mtCOVERAGE_TEST_MARKER();
							}
						}
						#endif /* configUSE_PREEMPTION */
					}
				}
			}
		}

		/* Tasks of equal priority to the currently running task will share
		processing time (time slice) if preemption is on, and the application
		writer has not explicitly turned time slicing off. */
		/* 若使能了时间片处理机制,还需要处理同优先级下任务之间的调度 */
		#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 )
		{
			/* Guard against the tick hook being called when the pended tick
			count is being unwound (when the scheduler is being unlocked). */
			if( uxPendedTicks == ( UBaseType_t ) 0U )
			{
				vApplicationTickHook();
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		#endif /* configUSE_TICK_HOOK */
	}
	else
	{
		/* 任务调度器挂起 */
		 /* 挂起的tick+1 */
		++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;
}

http://www.kler.cn/a/459453.html

相关文章:

  • python openyxl 用法 教程
  • arcgis模版空库怎么用(一)
  • 闪存知识科普-基本储存单元结构
  • 经验证:将数据从索尼传输到Android的 4 种方法
  • 鸿蒙应用开发(1)
  • 有什么AI辅助阅读文献工具推荐?
  • CSS过渡(transition)
  • 【Rust自学】8.2. Vector + Enum的应用
  • 第1关:博客系统数据库设计与实现之查询
  • bacnet mstp设备数据 转 opc ua项目案例
  • vue实现平滑滚动到目标标签页
  • 数据结构-1-线性表
  • Azure DevOps Server:使用TfsDeleteProject.exe删除团队项目
  • 第四期书生大模型实战营 第10关 InternVL 多模态模型部署微调实践
  • WebRTC :原理、协议和应用场景
  • 24.12.27 SpringMVCDay02
  • python3中条件判断语句:if 语句与if嵌套语句
  • CSS利用浮动实现文字环绕右下角,展开/收起效果
  • 从论文到实践:Stable Diffusion模型一键生成高质量AI绘画
  • 【笔记️】魔爪 Mini mx 使用快捷键
  • 深入解析C#异步编程:await 关键字背后的实现原理
  • Vue.js 生命周期概述:组件从诞生到销毁的全过程
  • Python世界:函数模块知识点小结
  • pytorch torch.utils.checkpoint模块介绍
  • Golang协程为什么⽐线程轻量
  • o1到o3的发展历程