2009-5-13 声明:该篇文章参考了http://blog.ednchina.com/bluehacker<?XML:NAMESPACE PREFIX = O />

 的大作

    tskTCB 结构的定义这里就不再给出来了,需要注意的是 其中 uxBasePriority 元素,它用于解决优先级反转, freertos 采用优先级继承的办法解决这个问题,在继承时,将任务原先的优先级保存在这个成员中,将来再从这里恢复任务的优先级。 <?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

       两个延时链表的正解 freertos 弄出两个延时链表是因为它的延时任务管理的需要。 freertos 根据任务延时时间的长短按序将任务插入这两个链表之一。在插入前先把任务将要延时的 xTicksToDelay 数加上系统当前 tick 数,这样得到了一个任务延时 due time (到期时间)的绝对数值。但是有可能这个相加操作会导致溢出,如果溢出则加入到 pxOverflowDelayedTaskList 指向的那个链表,否则加入 pxDelayedTaskList 指向的链表。

       xPendingReadyList; 这个链表用在调度器被lock(就是禁止调度了)的时期,如果一个任务从非就绪状态变为就绪状态,它不直接加到就绪链表中,而是加到这个pending链表中。等调度器重新启动(unlock)的时候再检查这个链表,把里面的任务加到就绪链表中。

 

任务管理:

freertos ucosii 不同,它的任务控制块并不是静态分配的,而是在创建任务的时候动态分配。另外, freertos 的优先级是优先级数越大优先级越高,和 ucosii 正好相反。任务控制块中也没有任务状态的成员变量,这是因为 freertos 中的任务总是根据他们的状态连入对应的链表,没有必要在任务控制块中维护一个状态。此外 freertos 对任务的数量没有限制,而且同一个优先级可以有多个任务。

 

任务删除:

任务创建过程前面讲过了,这里就直接看任务删除的工程。 freertos 的任务删除分两步完成,第一步在vTaskDelete中完成,FreeRTOS先把要删除的任务从就绪任务链表和事件等待链表中删除,然后把此任务添加到任务删除链表(即那个 xTasksWaitingTermination ),若删除的任务是当前运行任务,系统就执行任务调度函数.2步则是在idle任务中完成,idle任务运行时,检查 xTasksWaitingTermination 链表,如果有任务在这个表上,释放该任务占用的内存空间,并把该任务从任务删除链表中删除。

/****************************************************************

** 参数:pxTaskToDelete是一个指向被删除任务的句柄,这里其实就是等价于任务控制块

** 如果这个句柄==NULL,则表示要删除当前任务

*******************************************************************/

void vTaskDelete( xTaskHandle pxTaskToDelete )

{

    tskTCB *pxTCB;

    taskENTER_CRITICAL();

    {

         /* 如果删除的是当前任务,则删除完成后需要进行调度*/

        if( pxTaskToDelete == pxCurrentTCB )

        {

            pxTaskToDelete = NULL;

        }

 

         /* 通过传进来的任务句柄得到对应的tcb*/

        pxTCB = prvGetTCBFromHandle( pxTaskToDelete );

        traceTASK_DELETE( pxTCB );

 

         /* 把任务从就绪链表或者延时链表或者挂起链表中删除*/

        vListRemove( &( pxTCB->xGenericListItem ) );

 

         /* 判断任务是否在等待事件(semaphore消息队列等) */              

        if( pxTCB->xEventListItem.pvContainer )

        {// 如果是,则把它从事件等待链表中删除

            vListRemove( &( pxTCB->xEventListItem ) );

        }

        // 插入等待删除链表

        vListInsertEnd( ( xList * ) &xTasksWaitingTermination, &( pxTCB->xGenericListItem ) );

        // 增加uxTasksDeleted计数

        ++uxTasksDeleted;

    }

    taskEXIT_CRITICAL();

 

    /* 如果调度器已经运行,并且删除的是当前任务,则调度*/

    if( xSchedulerRunning != pdFALSE )

    {

        if( ( void * ) pxTaskToDelete == NULL )

        {

            taskYIELD();

        }

    }

}

再看空闲任务做的第2步工作:

static portTASK_FUNCTION( prvIdleTask, pvParameters )

{

    /* Stop warnings. */

    ( void ) pvParameters;

 

    for( ;; )

    {

        /* See if any tasks have been deleted. */

        prvCheckTasksWaitingTermination();

        …………………………….÷

* The portTASK_FUNCTION() macro is used to allow port/compiler specific

 * language extensions.  The equivalent prototype for this function is:

 * void prvIdleTask( void *pvParameters );

这里prvCheckTasksWaitingTermination()就是干这第2步的工作:每次调用它删除一个任务

static void prvCheckTasksWaitingTermination( void )

{                          

    #if ( INCLUDE_vTaskDelete == 1 )

    {              

        portBASE_TYPE xListIsEmpty;

 

        /* ucTasksDeleted is used to prevent vTaskSuspendAll() being called

        too often in the idle task. */

        if( uxTasksDeleted > ( unsigned portBASE_TYPE ) 0 )

        { // 禁止调度

            vTaskSuspendAll();

            // 打开调度

            xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination );

            xTaskResumeAll();

 

            if( !xListIsEmpty )

            {

                tskTCB *pxTCB;

                // 关中断

                portENTER_CRITICAL();

                {          

                    pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( ( xList * ) &xTasksWaitingTermination ) );

                    vListRemove( &( pxTCB->xGenericListItem ) );

                    --uxCurrentNumberOfTasks;

                    --uxTasksDeleted;

                }

                portEXIT_CRITICAL();

               // 释放内存,删除tcb

                prvDeleteTCB( pxTCB );

            }

        }

    }

    #endif