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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值