//如果一个临界区太长而不适合简单地关中断来实现,可以考虑采用挂起调度器的方式。但是唤醒(resuming, or un-suspending)调度器却是一个
//相对较长的操作。所以评估哪种是最佳方式需要结合实际情况。如果某个中断在调度器挂起过程中要求进行上下文切换,则个这请求也会被
//挂起,直到调度器被唤醒后才会得到执行
void vTaskSuspendAll( void )
{
//通过挂起调度器来创建临界区,挂起调度器有些时候也被称为锁定调度器
++uxSchedulerSuspended;//系统维护一个uxSchedulerSuspended计数值,当其大于0时表示禁止调度;等于0时则表示允许调度。
//返回值 在调度器挂起过程中,上下文切换请求也会被挂起,直到调度器被唤醒后才会得到执行。
//如果一个挂起的上下文切换请求在xTaskResumeAll()返回前得到执行,则函数返回pdTRUE,表示CPU要求被抢占,
//在其它情况下,xTaskResumeAll()返回pdFALSE,然后根据返回值,强制使任务交出CPU(或者叫做任务切换)
}
//如果一个临界区太长而不适合简单地关中断来实现,可以考虑采用挂起调度器的方式。但是唤醒(resuming, or un-suspending)调度器却是一个
//相对较长的操作。所以评估哪种是最佳方式需要结合实际情况。如果某个中断在调度器挂起过程中要求进行上下文切换,则个这请求也会被
//挂起,直到调度器被唤醒后才会得到执行
BaseType_t xTaskResumeAll ( void )
{
TCB_t *pxTCB;
BaseType_t xAlreadyYielded = pdFALSE;
//在禁止调度任务期间,若ISR导致了一个任务的就绪,这个任务就会放到xPendingReadyList中,
//一旦调度允许,必须把所有xPendingReadyList中的任务移动到一个合适的就绪链表中。
//要考虑调度器被挂起时,放在xPendingReadyList链表中的任务
taskENTER_CRITICAL();//关中断,进入临界区
{
--uxSchedulerSuspended;//调度器挂起计数器减一操作,如果仍大于0,则不止一个任务使调度器挂起;直到调度器不再挂起,则进入以下操作
if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
{
if( uxCurrentNumberOfTasks > ( UBaseType_t ) 0U )
{
//目前正在运行的任务数是否大于0,如果大于0,则进入以下操作,否则跳出本函数
//移除所有的被调度器挂起时就绪的任务,进入合适的就绪链表,直到xPendingReadyList链表为空
while( listLIST_IS_EMPTY( &xPendingReadyList ) == pdFALSE )
{
pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xPendingReadyList ) );
( void ) uxListRemove( &( pxTCB->xEventListItem ) );
( void ) uxListRemove( &( pxTCB->xGenericListItem ) );
prvAddTaskToReadyList( pxTCB );
//我们转移的任务是否有比当前任务的优先级高的,如果有,则抢占申请成功,进行任务切换
if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )//新获取任务的优先级不低于当前任务的优先级
{
xYieldPending = pdTRUE;//任务切换被使能
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
//在调度器被挂起的时间之内,是否有丢失未处理的滴答数。uxMissedTicks是丢失的滴答数
if( uxPendedTicks > ( UBaseType_t ) 0U )//若在任务挂起了则其值的改变在心跳时钟中++。若大于0说明有丢失的时钟数。
{
while( uxPendedTicks > ( UBaseType_t ) 0U )
{
if( xTaskIncrementTick() != pdFALSE ) //模拟进入心跳时钟中断,若!pdFALSE则说明进行任务切换。即:补齐缺失的滴答数。
{
xYieldPending = pdTRUE;//允许任务切换
}
else
{
mtCOVERAGE_TEST_MARKER();
}
--uxPendedTicks;//将丢失的时钟数--,保证其准确性。
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
if( xYieldPending == pdTRUE )//若允许任务切换
{
#if( configUSE_PREEMPTION != 0 )//若使用抢占式的系统
{
xAlreadyYielded = pdTRUE;//返回值设为已经切换成功
}
#endif
taskYIELD_IF_USING_PREEMPTION();//启用抢占式的方式进行任务切换
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
taskEXIT_CRITICAL();
return xAlreadyYielded;//返回任务是否已经切换;已经切换返回pdTRUE;反之返回pdFALSE。
}