2009-05-13 声明:该篇文章参考了http://blog.ednchina.com/bluehacker的大作
这是一种同步机制,比关中断要温和点。禁止调度由vTaskSuspendAll实现,打开调度由xTaskResumeAll实现。<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

void vTaskSuspendAll( void )

{

    portENTER_CRITICAL();

        ++uxSchedulerSuspended;

    portEXIT_CRITICAL();

}

这个很简单,系统维护一个计数uxSchedulerSuspended,当它大于0时候表示禁止调度,等于0则打开调度(允许调度)。

signed portBASE_TYPE xTaskResumeAll( void )

{

register tskTCB *pxTCB;

signed portBASE_TYPE xAlreadyYielded = pdFALSE;

 

    /* It is possible that an ISR caused a task to be removed from an event

    list while the scheduler was suspended.  If this was the case then the

    removed task will have been added to the xPendingReadyList.  Once the

    scheduler has been resumed it is safe to move all the pending ready

    tasks from this list into their appropriate ready list. */

    portENTER_CRITICAL();

    {// 将计数减一

        --uxSchedulerSuspended;

       // 如果等于0,则允许调度

        if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )

        {          

            if( uxCurrentNumberOfTasks > ( unsigned portBASE_TYPE ) 0 )

            {

                portBASE_TYPE xYieldRequired = pdFALSE;

               

                /* 将所有在xPendingReadyList中的任务移到对应的就绪链表中 */

                while( ( pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY(  ( ( xList * ) &xPendingReadyList ) ) ) != NULL )

                {

                    vListRemove( &( pxTCB->xEventListItem ) );

                    vListRemove( &( pxTCB->xGenericListItem ) );

                    prvAddTaskToReadyQueue( pxTCB );

                   

                    /* 如果我们移动的任务优先级高于当前任务优先级,则需要调度 */

                    if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )

                    {

                        xYieldRequired = pdTRUE;

                    }

                }

 

/* 如果在禁止调度期间,有时钟节拍中断发生,则我们把发生的次数记录在uxMissedTicks中,称为丢失的时钟节拍数;我们在这里模拟uxMissedTicks次时钟节拍中断,也就是说调用uxMissedTicks次时钟节拍isr: vTaskIncrementTick()。这样保证了所有任务的延时量不会出现偏差,它们将在正确的时间被唤醒*/

                if( uxMissedTicks > ( unsigned portBASE_TYPE ) 0 )

                {

                    while( uxMissedTicks > ( unsigned portBASE_TYPE ) 0 )

                    {

                        vTaskIncrementTick(); // 就是重新增加xTickCount

                        --uxMissedTicks;

                    }

 

                    /* As we have processed some ticks it is appropriate to yield

                    to ensure the highest priority task that is ready to run is

                    the task actually running. */

                    #if configUSE_PREEMPTION == 1

                    {

                        xYieldRequired = pdTRUE;

                    }

                    #endif

                }

               

                if( ( xYieldRequired == pdTRUE ) || ( xMissedYield == pdTRUE ) )

                {

                    xAlreadyYielded = pdTRUE;

                    xMissedYield = pdFALSE;

                    taskYIELD();

                }

            }

        }

    }

    portEXIT_CRITICAL();

 

    return xAlreadyYielded;

}

在这里我们顺便看下void vTaskIncrementTick( void )这个函数:

void vTaskIncrementTick( void )

{

    /* 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. */

    if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )

    {

        ++xTickCount;

        if( xTickCount == ( portTickType ) 0 )

        {

            xList *pxTemp;

 

            /* Tick count has overflowed so we need to swap the delay lists.

            If there are any items in pxDelayedTaskList here then there is

            an error! */

            pxTemp = pxDelayedTaskList;

            pxDelayedTaskList = pxOverflowDelayedTaskList;

            pxOverflowDelayedTaskList = pxTemp;

            xNumOfOverflows++;

        }

 

        /* See if this tick has made a timeout expire. */

        prvCheckDelayedTasks();

    }

    else

    {

        ++uxMissedTicks;

 

        /* The tick hook gets called at regular intervals, even if the

        scheduler is locked. */

        #if ( configUSE_TICK_HOOK == 1 )

        {

            extern void vApplicationTickHook( void );

 

            vApplicationTickHook();

        }

        #endif

    }

 

    #if ( configUSE_TICK_HOOK == 1 )

    {

        extern void vApplicationTickHook( void );

 

        /* Guard against the tick hook being called when the missed tick

        count is being unwound (when the scheduler is being unlocked. */

        if( uxMissedTicks == 0 )

        {

            vApplicationTickHook();

        }

    }

    #endif

 

    traceTASK_INCREMENT_TICK( xTickCount );

}