1. 程式人生 > 其它 >FreeRTOS Task Management(3)- 任務建立與刪除

FreeRTOS Task Management(3)- 任務建立與刪除

FreeRTOS Task Management(3)- 任務建立與刪除

/* FreeRTOS Kernel V10.4.1 */
/* 為了便於描述,原始碼中去除了一些用於除錯的語句,如常見的trace_XXX, mtCOVERAGE_TEST_MARKER()等 */

原文連結:https://www.cnblogs.com/yanpio/p/14892113.html

1 任務建立

FreeRTOS提供了一系列的任務建立函式,主要的區別是建立任務時,記憶體分配方式存在差異。下表對比了幾種任務建立函式的記憶體分配方式,從原始碼中可以具體瞭解到這些不同之處。

四種任務建立函式都會呼叫初始化函式prvInitialiseNewTask()

和新增列表函式prvAddNewTaskToReadyList().以下首先介紹這兩個函式。

1.1 prvInitialiseNewTask()

/* 初始化新的task,主要是對TCB進行操作。*/
static void prvInitialiseNewTask( TaskFunction_t pxTaskCode,/* task執行函式 */
                                  const char * const pcName, /* task名稱 */
                                  const uint32_t ulStackDepth,/* task棧深度,單位是word,即 4 bytes */
                                  void * const pvParameters,/* 用於傳遞引數給task,可以指向一個簡單變數,也可以指向一個結構體變數*/
                                  UBaseType_t uxPriority,/* 優先順序 */
                                  TaskHandle_t * const pxCreatedTask,/* 可用於返回任務控制代碼 */
                                  TCB_t * pxNewTCB, /* TCB指標 */
                                  const MemoryRegion_t * const xRegions ) /* 如果使用記憶體保護單元(MPU),則會使用該變數*/
{
    StackType_t * pxTopOfStack;
    UBaseType_t x;

    /* 如果使用 portUSING_MPU_WRAPPERS,則進行如下操作。對此不太理解,因此後文預設 portUSING_MPU_WRAPPERS = 0 */
    #if ( portUSING_MPU_WRAPPERS == 1 )
        /* Should the task be created in privileged mode? */
        BaseType_t xRunPrivileged;

        if( ( uxPriority & portPRIVILEGE_BIT ) != 0U )
        {
            xRunPrivileged = pdTRUE;
        }
        else
        {
            xRunPrivileged = pdFALSE;
        }
        uxPriority &= ~portPRIVILEGE_BIT;
    #endif /* portUSING_MPU_WRAPPERS == 1 */

    /* 如果開啟選擇,則將stack初始化為固定值0xa5(可用於除錯). */
    #if ( tskSET_NEW_STACKS_TO_KNOWN_VALUE == 1 )
    {
          ( void ) memset( pxNewTCB->pxStack, ( int ) tskSTACK_FILL_BYTE, ( size_t ) ulStackDepth * sizeof( StackType_t ) );
     }
    #endif 

    /* 根據stack生長的方向,來進行stack初始化. */
    #if ( portSTACK_GROWTH < 0 )
        {
            /* 如果stack向下生長,則棧頂在高地址 */
            pxTopOfStack = &( pxNewTCB->pxStack[ ulStackDepth - ( uint32_t ) 1 ] );
            /* 棧頂地址對齊,此操作在FreeRTOS Memory Management 有較為詳細的分析 */
            pxTopOfStack = ( StackType_t * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) ); 

            /* 檢查對齊是否OK */
            configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );

            /* 記錄棧空間最高位地址 */
            #if ( configRECORD_STACK_HIGH_ADDRESS == 1 )
                {
                    pxNewTCB->pxEndOfStack = pxTopOfStack;
                }
            #endif 
        }
    #else /* 如果stack向上生長,則棧頂在低地址 */
        {
            pxTopOfStack = pxNewTCB->pxStack;

            /* 檢查對齊情況 */
            configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxNewTCB->pxStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );

            /* 記錄棧空間最高地址 */
            pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + ( ulStackDepth - ( uint32_t ) 1 );
        }
    #endif 

    /* 儲存task name. */
    if( pcName != NULL )
    {
        for( x = ( UBaseType_t ) 0; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ )
        {
            pxNewTCB->pcTaskName[ x ] = pcName[ x ];

            /* 不能直接複製configMAX_TASK_NAME_LEN,因為可能name的實際長度沒有這麼長,並且實際長度後的記憶體訪問情況不確定 */
            if( pcName[ x ] == ( char ) 0x00 )
            {
                break;
            }           
        }

        /* 加上結束符'\0'. */
        pxNewTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1 ] = '\0';
    }
    else
    {
        pxNewTCB->pcTaskName[ 0 ] = 0x00;
    }

    /* 優先順序值要在合理範圍內. */
    if( uxPriority >= ( UBaseType_t ) configMAX_PRIORITIES )
    {
        uxPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U;
    }
   
    /* 記錄優先順序相關的變數,可參考上一篇文章中對TCB結構的相關描述 */
    pxNewTCB->uxPriority = uxPriority;
    #if ( configUSE_MUTEXES == 1 )
        {
            pxNewTCB->uxBasePriority = uxPriority;
            pxNewTCB->uxMutexesHeld = 0;
        }
    #endif 

    /* 初始化xStateListItem 和 xEventListItem(將item的pxContainer指標置為NULL) */
    vListInitialiseItem( &( pxNewTCB->xStateListItem ) );
    vListInitialiseItem( &( pxNewTCB->xEventListItem ) );

    /* 設定xStateListItem 的 owner 為當前TCB. */
    listSET_LIST_ITEM_OWNER( &( pxNewTCB->xStateListItem ), pxNewTCB );

    /* 設定 xEventListItem的值,設定為 configMAX_PRIORITIES - uxPriority. 優先順序高的(數值大的)在陣列前面。 */
    listSET_LIST_ITEM_VALUE( &( pxNewTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxPriority ); 
    /* 設定xEventListItem 的 owner 為當前TCB. */
    listSET_LIST_ITEM_OWNER( &( pxNewTCB->xEventListItem ), pxNewTCB );

    /* 將臨界區巢狀深度初始化為0 */
    #if ( portCRITICAL_NESTING_IN_TCB == 1 )
        {
            pxNewTCB->uxCriticalNesting = ( UBaseType_t ) 0U;
        }
    #endif 

    #if ( configUSE_APPLICATION_TASK_TAG == 1 )
        {
            pxNewTCB->pxTaskTag = NULL;
        }
    #endif 

    /* 執行計數初始化為0 */
    #if ( configGENERATE_RUN_TIME_STATS == 1 )
        {
            pxNewTCB->ulRunTimeCounter = 0UL;
        }
    #endif 

    /* 如果開啟portUSING_MPU_WRAPPERS, 則儲存MPUSettings */
    #if ( portUSING_MPU_WRAPPERS == 1 )
        {
            vPortStoreTaskMPUSettings( &( pxNewTCB->xMPUSettings ), xRegions, pxNewTCB->pxStack, ulStackDepth );
        }
    #else
        {
            ( void ) xRegions;
        }
    #endif

    /* 將本地引數指標內容清空 */
    #if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0 )
        {
            memset( ( void * ) &( pxNewTCB->pvThreadLocalStoragePointers[ 0 ] ), 0x00, sizeof( pxNewTCB->pvThreadLocalStoragePointers ) );
        }
    #endif

    /* 將任務通知相關的變數清空,後續會更詳細說明  */
    #if ( configUSE_TASK_NOTIFICATIONS == 1 )
        {
            memset( ( void * ) &( pxNewTCB->ulNotifiedValue[ 0 ] ), 0x00, sizeof( pxNewTCB->ulNotifiedValue ) );
            memset( ( void * ) &( pxNewTCB->ucNotifyState[ 0 ] ), 0x00, sizeof( pxNewTCB->ucNotifyState ) );
        }
    #endif

    /* newlib 相關初始化 */
    #if ( configUSE_NEWLIB_REENTRANT == 1 )
        {
            _REENT_INIT_PTR( ( &( pxNewTCB->xNewLib_reent ) ) );
        }
    #endif

    #if ( INCLUDE_xTaskAbortDelay == 1 )
        {
            pxNewTCB->ucDelayAborted = pdFALSE;
        }
    #endif

    /* 為了方便描述,以下對原始碼進行一些簡化,
     * 假設 portUSING_MPU_WRAPPERS = 0 ,portSTACK_GROWTH = -1,portHAS_STACK_OVERFLOW_CHECKING = 1 
     * portHAS_STACK_OVERFLOW_CHECKING值標誌 port 是否具有stack overflow 檢查的功能
     * pxPortInitialiseStack()功能根據port不同而異,一般是初始化棧空間中的一些暫存器值
     */
      pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxNewTCB->pxStack, pxTaskCode, pvParameters );
   
    /* 如果任務建立成功,則通過輸入指標返回任務控制代碼,用於任務的其他操作(修改優先順序,刪除任務等) */
    if( pxCreatedTask != NULL )
    {
        *pxCreatedTask = ( TaskHandle_t ) pxNewTCB;
    }
}

1.2 prvAddNewTaskToReadyList()

static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB )
{
    /* 更新ready list時,需要保證不被打擾.因此使用taskENTER_CRITICAL() 和 taskEXIT_CRITICAL() 進行保護*/
    taskENTER_CRITICAL();
    {
        /* task 數量遞增 */
        uxCurrentNumberOfTasks++;

        if( pxCurrentTCB == NULL )
        {
            /* 如果 pxCurrentTCB == NULL,則意味著還沒有任務,或者所有任務都被掛起了. */
            pxCurrentTCB = pxNewTCB;

            /* 如果任務數量為1,則需要進行初始化。因為排程器會建立一個idle task,
             * 因此即使有任務的增刪操作,uxCurrentNumberOfTasks的數值不會再次變為1,初始化操作也只會進行一次 */
            if( uxCurrentNumberOfTasks == ( UBaseType_t ) 1 )
            {
                /* 詳見本節(下面),關於 prvInitialiseTaskLists() 的分析 */
                prvInitialiseTaskLists();
            }
        }
        else
        {
            /* 如果排程器不在執行,新加入的優先順序更高,則將pxCurrentTCB的值設定為pxNewTCB。等排程器恢復後,則直接執行優先順序較高的task */
            if( xSchedulerRunning == pdFALSE )
            {
                if( pxCurrentTCB->uxPriority <= pxNewTCB->uxPriority )
                {
                    pxCurrentTCB = pxNewTCB;
                }        
            }           
        }

        uxTaskNumber++;

        #if ( configUSE_TRACE_FACILITY == 1 )
            {
                /* uxTCBNumber(TCB序號)賦值,用於跟蹤除錯. */
                pxNewTCB->uxTCBNumber = uxTaskNumber;
            }
        #endif
       
        /* 詳見本節(後面)關於 prvAddTaskToReadyList()的分析*/
        prvAddTaskToReadyList( pxNewTCB );

        portSETUP_TCB( pxNewTCB );/* #define portSETUP_TCB( pxTCB )    ( void ) pxTCB */
    }
    taskEXIT_CRITICAL();

    if( xSchedulerRunning != pdFALSE )
    {
        /* 如果排程器正在執行,並且新加入的task優先順序比當前執行的task優先順序高,則當前task退出,重新排程. */
        if( pxCurrentTCB->uxPriority < pxNewTCB->uxPriority )
        {
            taskYIELD_IF_USING_PREEMPTION();
        }       
    }
}

/*---------------------------------------------------------------------------------------------------------*/

/* 初始化任務列表 */
static void prvInitialiseTaskLists( void )
{
    UBaseType_t uxPriority;

    /* 按照優先順序,對pxReadyTasksLists陣列逐個進行初始化。 */
    for( uxPriority = ( UBaseType_t ) 0U; uxPriority < ( UBaseType_t ) configMAX_PRIORITIES; uxPriority++ )
    {
        /* vListInitialise 函式詳見 < FreeRTOS Task Management(1)- list實現 > */
        vListInitialise( &( pxReadyTasksLists[ uxPriority ] ) );
    }

    /* 初始化各個全域性的list */
    vListInitialise( &xDelayedTaskList1 );
    vListInitialise( &xDelayedTaskList2 );
    vListInitialise( &xPendingReadyList );

    #if ( INCLUDE_vTaskDelete == 1 )
        {
            vListInitialise( &xTasksWaitingTermination );
        }
    #endif 

    #if ( INCLUDE_vTaskSuspend == 1 )
        {
            vListInitialise( &xSuspendedTaskList );
        }
    #endif 

    /* 指標指向對應的list,用於taskDelay相關操作. */
    pxDelayedTaskList = &xDelayedTaskList1;
    pxOverflowDelayedTaskList = &xDelayedTaskList2;
}

/*---------------------------------------------------------------------------------------------------------*/

/* 主要分兩步,一是記錄當前最高的優先順序(如果pxTCB的優先順序更高), 
 * 二是將xStateListItem插入到對應優先順序的pxReadyTasksLists中,這樣排程器就可以進行排程 */
#define prvAddTaskToReadyList( pxTCB )                                                                 \
    taskRECORD_READY_PRIORITY( ( pxTCB )->uxPriority );                                                \
    vListInsertEnd( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xStateListItem ) ); 
    
/*---------------------------------------------------------------------------------------------------------*/

1.3 xTaskCreate()

/* xTaskCreate 是經常使用的一種 <動態> 建立任務的方式。僅在configSUPPORT_DYNAMIC_ALLOCATION == 1,才能進行呼叫 */

#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )

    BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
                            const char * const pcName,
                            const configSTACK_DEPTH_TYPE usStackDepth,
                            void * const pvParameters,
                            UBaseType_t uxPriority,
                            TaskHandle_t * const pxCreatedTask )
    {
        TCB_t * pxNewTCB;
        BaseType_t xReturn;

        /* 由於是動態分配,因此需要在建立任務時 分配 stack 和 TCB的空間。
         * 根據portSTACK_GROWTH(棧生產方向)的不同,需要注意stack和tcb的分配順序,以確定stack生長不會影響到TCB。*/
        
        /* 棧向高地址生長,則先分配TCB,再分配stack */
        #if ( portSTACK_GROWTH > 0 )
            {
                /* pvPortMalloc詳細介紹見FreeRTOS Memory Management 系列部落格 */
                pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );

                /* 如果TCB 和 stack 分配都OK了,則繼續進行初始化操作*/
                if( pxNewTCB != NULL )
                {   
                    pxNewTCB->pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); 
                    if( pxNewTCB->pxStack == NULL )
                    {
                        vPortFree( pxNewTCB );
                        pxNewTCB = NULL;
                    }
                }
            }       
        #else  /* 棧向低地址生長,則先分配stack,再分配TCB */
            {
                StackType_t * pxStack;
                pxStack = pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); 
                
                if( pxStack != NULL )
                {
                    
                    pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); 
                    
                    if( pxNewTCB != NULL )
                    { 
                        pxNewTCB->pxStack = pxStack;
                    }
                    else
                    {  
                        vPortFree( pxStack );
                    }
                }
                else
                {
                    pxNewTCB = NULL;
                }
            }
        #endif 

        if( pxNewTCB != NULL )
        {
            #if ( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) 
                {
                    /* stack 和 TCB 都是動態分配,在刪除任務時都需要進行free,詳見2.2節 */
                    pxNewTCB->ucStaticallyAllocated = tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB;
                }
            #endif 

            /* 初始化操作,見上述3.1節 和 3.2節的詳細分析 */
            prvInitialiseNewTask( pxTaskCode, pcName, ( uint32_t ) usStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB, NULL );
            prvAddNewTaskToReadyList( pxNewTCB );
            xReturn = pdPASS;
        }
        else
        {
            xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
        }

        return xReturn;
    }

#endif /* configSUPPORT_DYNAMIC_ALLOCATION */

1.4 xTaskCreateStatic()

/* xTaskCreateStatic 函式的特點是靜態分配TCB 和stack */
#if ( configSUPPORT_STATIC_ALLOCATION == 1 )

    TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode,
                                    const char * const pcName,
                                    const uint32_t ulStackDepth,
                                    void * const pvParameters,
                                    UBaseType_t uxPriority,
                                    StackType_t * const puxStackBuffer, /* 分配好的stack 空間 */
                                    StaticTask_t * const pxTaskBuffer ) /* 分配好的TCB空間 */
    {
        TCB_t * pxNewTCB;
        TaskHandle_t xReturn;

        /* 進行一波檢查,以確定輸入的空間地址和大小是否正常 */
        configASSERT( puxStackBuffer != NULL );
        configASSERT( pxTaskBuffer != NULL );

        #if ( configASSERT_DEFINED == 1 )
            {
                volatile size_t xSize = sizeof( StaticTask_t );
                configASSERT( xSize == sizeof( TCB_t ) );
                ( void ) xSize; 
            }
        #endif 

        /* 如果上述檢查沒有問題,則對pxNewTCB 和 pxNewTCB->pxStack進行賦值 */
        if( ( pxTaskBuffer != NULL ) && ( puxStackBuffer != NULL ) )
        {
            pxNewTCB = ( TCB_t * ) pxTaskBuffer; 
            pxNewTCB->pxStack = ( StackType_t * ) puxStackBuffer;

            #if ( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) 
                {
                    /* stack 和 TCB 都是靜態分配,在刪除任務時都不需要進行free,詳見2.2節 */
                    pxNewTCB->ucStaticallyAllocated = tskSTATICALLY_ALLOCATED_STACK_AND_TCB;
                }
            #endif 

            /* 初始化操作,見上述3.1節 和 3.2節的詳細分析 */
            prvInitialiseNewTask( pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, &xReturn, pxNewTCB, NULL );
            prvAddNewTaskToReadyList( pxNewTCB );
        }
        else
        {
            xReturn = NULL;
        }

        return xReturn;
    }

#endif 

1.5 xTaskCreateRestrictedStatic()

/* 僅在實現了MPU的系統上,才能呼叫此函式 */
/* 
 *   typedef struct xTASK_PARAMETERS
 *   {
 *       TaskFunction_t pvTaskCode;
 *       const char * const pcName;     
 *       configSTACK_DEPTH_TYPE usStackDepth;
 *       void * pvParameters;
 *       UBaseType_t uxPriority;
 *       StackType_t * puxStackBuffer;
 *       MemoryRegion_t xRegions[ portNUM_CONFIGURABLE_REGIONS ];
 *       #if ( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) )
 *           StaticTask_t * const pxTaskBuffer;
 *       #endif
 *    } TaskParameters_t;
 */

#if ( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) )

    /* pxTaskDefinition引數的定義如上,除了xTaskCreate函式的輸入引數之外,還包含了xRegions,用於prvInitialiseNewTask函式進行初始化。
     * 函式實現與xTaskCreateStatic基本一致  */ 
    BaseType_t xTaskCreateRestrictedStatic( const TaskParameters_t * const pxTaskDefinition,
                                            TaskHandle_t * pxCreatedTask ) /* 建立的task控制代碼 */
    {
        TCB_t * pxNewTCB;
        BaseType_t xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;

        configASSERT( pxTaskDefinition->puxStackBuffer != NULL );
        configASSERT( pxTaskDefinition->pxTaskBuffer != NULL );

        if( ( pxTaskDefinition->puxStackBuffer != NULL ) && ( pxTaskDefinition->pxTaskBuffer != NULL ) )
        {
            pxNewTCB = ( TCB_t * ) pxTaskDefinition->pxTaskBuffer;
            pxNewTCB->pxStack = pxTaskDefinition->puxStackBuffer;

            #if ( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 )
                {
                   /* stack 和 TCB 都是靜態分配,在刪除任務時都不需要進行free,詳見2.2節 */
                    pxNewTCB->ucStaticallyAllocated = tskSTATICALLY_ALLOCATED_STACK_AND_TCB;
                }
            #endif

            /* 初始化操作,見上述3.1節 和 3.2節的詳細分析 */
            prvInitialiseNewTask( pxTaskDefinition->pvTaskCode,
                                  pxTaskDefinition->pcName,
                                  ( uint32_t ) pxTaskDefinition->usStackDepth,
                                  pxTaskDefinition->pvParameters,
                                  pxTaskDefinition->uxPriority,
                                  pxCreatedTask, pxNewTCB,
                                  pxTaskDefinition->xRegions );/* 在portUSING_MPU_WRAPPERS == 0時 ,此引數輸入NULL */

            prvAddNewTaskToReadyList( pxNewTCB );
            xReturn = pdPASS;
        }

        return xReturn;
    }

#endif 

1.6 xTaskCreateRestricted()

#if ( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )

    BaseType_t xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition,
                                      TaskHandle_t * pxCreatedTask )
    {
        TCB_t * pxNewTCB;
        BaseType_t xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;

        configASSERT( pxTaskDefinition->puxStackBuffer );

        if( pxTaskDefinition->puxStackBuffer != NULL )
        {
            /* 分配TCB. */
            pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );

            if( pxNewTCB != NULL )
            {
                /* 從輸入引數中獲取stack空間 */
                pxNewTCB->pxStack = pxTaskDefinition->puxStackBuffer;

                #if ( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 )
                    {
                       /* stack 是靜態分配,在刪除任務時需要free TCB,詳見2.2節 */
                        pxNewTCB->ucStaticallyAllocated = tskSTATICALLY_ALLOCATED_STACK_ONLY;
                    }
                #endif 

                /* 初始化操作,見上述3.1節 和 3.2節的詳細分析 */
                prvInitialiseNewTask( pxTaskDefinition->pvTaskCode,
                                      pxTaskDefinition->pcName,
                                      ( uint32_t ) pxTaskDefinition->usStackDepth,
                                      pxTaskDefinition->pvParameters,
                                      pxTaskDefinition->uxPriority,
                                      pxCreatedTask, pxNewTCB,
                                      pxTaskDefinition->xRegions );/* 在portUSING_MPU_WRAPPERS == 0時 ,此引數輸入NULL */

                prvAddNewTaskToReadyList( pxNewTCB );
                xReturn = pdPASS;
            }
        }

        return xReturn;
    }

#endif 

2 任務刪除

2.1 vTaskDelete()

#if ( INCLUDE_vTaskDelete == 1 )
 
    /* 刪除任務主要是將TCB中包含的各種ListItem從list中移除,並釋放資源 */

    void vTaskDelete( TaskHandle_t xTaskToDelete )
    {
        TCB_t * pxTCB;

        /* 刪除過程要進行保護,防止中斷打斷 */
        taskENTER_CRITICAL();
        {
            /* 獲取控制代碼對應的TCB. */
            pxTCB = prvGetTCBFromHandle( xTaskToDelete );

            /* 將task從 ready/delayed list中移除 */
            if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
            {
                taskRESET_READY_PRIORITY( pxTCB->uxPriority );
            }
           
            /* 如果task在等待事件,則從事件列表中移除該task */
            if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
            {
                ( void ) uxListRemove( &( pxTCB->xEventListItem ) );
            }
            
            /* 需要注意,此值是一個靜態全域性變數,與TCB結構體中的uxTaskNumber不是一個東西。該值在任務數量發生變化時(建立或刪除)都會+1,
             * 並以此提醒排程器,任務數量已經發生變化,需要重新生成任務列表 */
            uxTaskNumber++;

            /* 如果被刪除的是當前正在執行的Task,則需要idle task 去執行清理操作。因為task無法釋放自己的資源。
             * 需要的做的是將任務新增到待刪除列表中  */
            if( pxTCB == pxCurrentTCB )
            {
                /* 將需要刪除的task新增到刪除列表,等待idle task去做後續的清理工作,詳見2.4節 */
                vListInsertEnd( &xTasksWaitingTermination, &( pxTCB->xStateListItem ) );

                /* 待清除任務計數加1. */
                ++uxDeletedTasksWaitingCleanUp;
            }
            else /* 如果不是當前正在執行的Task,則直接進行清理即可 */
            {
                /* 當前task數量減1。需要指出的是,在pxTCB == pxCurrentTCB時,並沒有直接減1,
                 * 是因為在idle task 裡進行了減1 操作,詳見2.4節 */
                --uxCurrentNumberOfTasks;
                
                /* 見2.2 節詳細分析,主要工作是釋放記憶體 */
                prvDeleteTCB( pxTCB );

                /* 重置延時時間,詳見2.3節. */
                prvResetNextTaskUnblockTime();
            }
        }
        taskEXIT_CRITICAL();

        /* 如果排程器在運作,並且當前的Task被刪除,則需要主動釋放執行權,排程器重新排程. */
        if( xSchedulerRunning != pdFALSE )
        {
            if( pxTCB == pxCurrentTCB )
            {
                configASSERT( uxSchedulerSuspended == 0 );
                portYIELD_WITHIN_API();
            }  
        }
    }

#endif 

2.2 prvDeleteTCB()

static void prvDeleteTCB( TCB_t * pxTCB )
    {
        /* #define portCLEAN_UP_TCB( pxTCB )    ( void ) pxTCB */ 
        portCLEAN_UP_TCB( pxTCB ); 

        /* See the third party link http://www.nadler.com/embedded/newlibAndFreeRTOS.html
         * for additional information. */
        #if ( configUSE_NEWLIB_REENTRANT == 1 )
            {
                _reclaim_reent( &( pxTCB->xNewLib_reent ) );
            }
        #endif 

        /* 參照1中的表格,以下這種搭配,TCB和stack都需要釋放 */
        #if ( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) && ( portUSING_MPU_WRAPPERS == 0 ) )
            {
                vPortFree( pxTCB->pxStack );
                vPortFree( pxTCB );
            }
        /* 僅在tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0時,才會記錄pxTCB->ucStaticallyAllocated的值 */
        #elif ( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) 
            {
                /* 1.3節中的xTaskCreate函式的記憶體分配方式是 tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB */
                if( pxTCB->ucStaticallyAllocated == tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB )
                {
                    /* TCB 和 stack都是動態分配的,因此都需要free */
                    vPortFree( pxTCB->pxStack );
                    vPortFree( pxTCB );
                }
                
                /* 1.4節中xTaskCreateRestrictedStatic函式和1.5節中xTaskCreateRestrictedStatic函式都是                    
                 * tskSTATICALLY_ALLOCATED_STACK_ONLY. */
                else if( pxTCB->ucStaticallyAllocated == tskSTATICALLY_ALLOCATED_STACK_ONLY )
                {
                    /* 僅有stack是靜態分配,因此TCB需要free */
                    vPortFree( pxTCB );
                }
                
                /*1.6節中的 xTaskCreateRestricted函式記憶體分配方式是tskSTATICALLY_ALLOCATED_STACK_AND_TCB */
                else
                {
                    /* TCB 和 stack都是靜態分配的,因此不需要free  */
                    configASSERT( pxTCB->ucStaticallyAllocated == tskSTATICALLY_ALLOCATED_STACK_AND_TCB );
                }
            }
        #endif 
    }

2.3 prvResetNextTaskUnblockTime()

/* 此函式涉及到任務延時,此處簡單說明,會在後續的文章中詳細描述 task delay */
static void prvResetNextTaskUnblockTime( void )
{
    if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE )
    {
        /* 刪除task時,已經將其從delayed list 中刪除。如果此時list已經為空,則將xNextTaskUnblockTime 設定為最大值 */
        xNextTaskUnblockTime = portMAX_DELAY;
    }
    else
    {
        /* 如果list不為空,則將xNextTaskUnblockTime的值設定為下一個即將執行的task的delay time. */
        xNextTaskUnblockTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxDelayedTaskList );
    }
}

2.4 prvCheckTasksWaitingTermination()

static void prvCheckTasksWaitingTermination( void )
{
    /** THIS FUNCTION IS CALLED FROM THE RTOS IDLE TASK **/
    
    TCB_t * pxTCB;
    /* 當有任務需要清除時,就逐個進行清除 */
    while( uxDeletedTasksWaitingCleanUp > ( UBaseType_t ) 0U )
    {
        taskENTER_CRITICAL();
        {
            pxTCB = listGET_OWNER_OF_HEAD_ENTRY( ( &xTasksWaitingTermination ) ); 
            
            /* 執行清理工作 */
            ( void ) uxListRemove( &( pxTCB->xStateListItem ) );
            --uxCurrentNumberOfTasks;
            --uxDeletedTasksWaitingCleanUp;
        }
        taskEXIT_CRITICAL();
        
        /* 詳見2.2節 */
        prvDeleteTCB( pxTCB );
    }
}