freertos之scheduler浅析

前言

其实是接上一篇task这篇文章的,上一篇写的有点多。

代码分析

调度器开启、关闭

一般在调度器没有开启之前需要创建一个start_task来创建一系列任务task,然后就是调用vTaskStartScheduler来启动调度器。下面分析具体代码

void vTaskStartScheduler( void )
{
BaseType_t xReturn;

	/* 创建idle task,使其运行在最低优先级 */
	xReturn = xTaskCreate(	prvIdleTask,
							"IDLE", configMINIMAL_STACK_SIZE,
							( void * ) NULL,
							( tskIDLE_PRIORITY | portPRIVILEGE_BIT ),
							&xIdleTaskHandle );
	/*如果使能了定时器功能,那么不论你之后会使用定时器功能,
	都会先创建一个定时器函数*/
	#if ( configUSE_TIMERS == 1 )
	{
		if( xReturn == pdPASS )
		{
			xReturn = xTimerCreateTimerTask();
		}
	}

	if( xReturn == pdPASS )
	{/*只有上两步操作都ok的情况下,才能继续执行*/
	/*中断在这里被关闭,以确保在调用xPortStartScheduler()之前或期间不会发生tick。
	已经创建的任务的栈中包含了开启中断的状态字,当第一个任务执行时,
	中断将自动重新启用开始运行。*/
		portDISABLE_INTERRUPTS();
		xNextTaskUnblockTime = portMAX_DELAY;
		xSchedulerRunning = pdTRUE;
		xTickCount = ( TickType_t ) 0U;
		/* 计时器刻度的设置是决定于硬件的,因此在移植的接口设置。*/
		if( xPortStartScheduler() != pdFALSE ){对于cm3平台来说就是systick定时器
			
		}
	}
}


void vTaskEndScheduler( void )
{
	/* 停止中断,并调用可移植调度器停止函数,以便在必要时恢复原始ISRs。
	可移植层必须确保中断启用位保持在正确的状态。*/
	portDISABLE_INTERRUPTS();
	xSchedulerRunning = pdFALSE;
	vPortEndScheduler();
}

阻塞调度器

在系统运行的时候如果不想让系统继续调度task运行,可以直接阻塞调度器,这样本来的任务就可以独占cpu了,不会被抢占打断。在做完工作之后在解挂就ok了

void vTaskSuspendAll( void )
{
	/* 由于该变量是BaseType_t类型的,所以不需要临界区*/
	++uxSchedulerSuspended;
}


BaseType_t xTaskResumeAll( void )
{
TCB_t *pxTCB = NULL;
BaseType_t xAlreadyYielded = pdFALSE;
	/*ISR可能导致从事件中删除任务在调度程序暂停时列出。
	如果是这样,那么删除的任务将被添加到xPendingReadyList。
	一旦已恢复调度程序,它是安全的移动所有挂起准备任务从这个列表进入相应的就绪列表。*/
	taskENTER_CRITICAL();{
		--uxSchedulerSuspended;
		if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ){
			if( uxCurrentNumberOfTasks > ( UBaseType_t ) 0U ){
				/* 将 xPendingReadyList 中所有的的task移入 ReadyTasksLists中,所以用了个循环*/
				while( listLIST_IS_EMPTY( &xPendingReadyList ) == pdFALSE ){
					pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xPendingReadyList ) );
					( void ) uxListRemove( &( pxTCB->xEventListItem ) );
					( void ) uxListRemove( &( pxTCB->xStateListItem ) );
					prvAddTaskToReadyList( pxTCB );

					/* If the moved task has a priority higher than the current
					task then a yield must be performed. */
					if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ){
						xYieldPending = pdTRUE;
					}
				}
				if( pxTCB != NULL ){
					/*当调度器被挂起的时候,可能导致了一个任务被阻塞了,而如果这个
					任务恰好使得 xNextTaskUnblockTime 没有被重新计算,
					那就在此重新计算。主要是对于低功耗无tickless实现
					非常重要,这可以防止不必要的低功耗出口状态。*/
					prvResetNextTaskUnblockTime();
				}

				/*如果在调度器暂停时发生了tick,那么现在应该进行处理了。
				这确保了tick计数不错乱,任何延迟的任务都在正确的时间恢复。*/
				{
					UBaseType_t uxPendedCounts = uxPendedTicks; /* Non-volatile copy. */
					if( uxPendedCounts > ( UBaseType_t ) 0U ){
						do{
							if( xTaskIncrementTick() != pdFALSE ){
								xYieldPending = pdTRUE;
							}
							--uxPendedCounts;
						} while( uxPendedCounts > ( UBaseType_t ) 0U );
						uxPendedTicks = 0;
					}
				}

				if( xYieldPending != pdFALSE ){
					#if( configUSE_PREEMPTION != 0 )
					{//这个返回值会导致内核抢占调度发生
						xAlreadyYielded = pdTRUE;
					}
					#endif
					taskYIELD_IF_USING_PREEMPTION();
				}
			}
		}
	}
	taskEXIT_CRITICAL();
	return xAlreadyYielded;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值