首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

FreeRTOS分析(4)

FreeRTOS分析(4)

调度器的禁止和打开
这是一种同步机制,比关中断要温和点。禁止调度由vTaskSuspendAll实现,打开调度由xTaskResumeAll实现。
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();
                        --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;
}

任务挂起与唤醒
freertos的任务关起与ucosii也不大一样。它把所有挂起的任务加到xSuspendedTaskList中,而且一旦调用vTaskSuspend()函数挂起一个任务,该任务就将从所有它原先连入的链表中删除(包括就绪表,延时表和它等待的事件链表),也就是说,和 ucosii不同,一旦一个任务被挂起,它将取消先前它的延时和对事件的等待。ucosii中是不同的,在ucosii里面一个任务被挂起仅仅是把任务的状态或上一个OS_STAT_SUSPEND并从就绪表中删除,如果先前这个任务正在等待某事件,则并不取消等待。
//如果传进来的pxTaskToSuspend==NULL,则表示挂起当前任务
void vTaskSuspend( xTaskHandle pxTaskToSuspend )
{
    tskTCB *pxTCB;

        taskENTER_CRITICAL();
        {
            /* Ensure a yield is performed if the current task is being
            suspended. */
            if( pxTaskToSuspend == pxCurrentTCB )
            {
                pxTaskToSuspend = NULL;
            }

            /* 得到对应任务tcb */
            pxTCB = prvGetTCBFromHandle( pxTaskToSuspend );

            traceTASK_SUSPEND( pxTaskToSuspend );

            /* 把任务从就绪表或者延时链表中删除 */
            vListRemove( &( pxTCB->xGenericListItem ) );

            /* 如果任务也在等待某事件,则取消等待 */                                                
            if( pxTCB->xEventListItem.pvContainer )
            {
                vListRemove( &( pxTCB->xEventListItem ) );
            }
           //插到xSuspendedTaskList
            vListInsertEnd( ( xList * ) &xSuspendedTaskList, &( pxTCB->xGenericListItem ) );
        }
        taskEXIT_CRITICAL();

        /* 如果挂起的是当前任务,则调度 */
        if( ( void * ) pxTaskToSuspend == NULL )
        {
            taskYIELD();
        }
    }
继承事业,薪火相传
返回列表