freeRTOS 刪除任務


直接上代碼

 1     void vTaskDelete( TaskHandle_t xTaskToDelete )
 2     {
 3     TCB_t *pxTCB;
 4 
 5         taskENTER_CRITICAL();
 6         {
 7             /* If null is passed in here then it is the calling task that is
 8             being deleted. */  如果xTaskToDel為空,刪除自己
 9             pxTCB = prvGetTCBFromHandle( xTaskToDelete );
10 
11             /* Remove task from the ready list. */  從就緒表中刪除
12             if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )  刪除后,列表長度為0 13             {
14                 taskRESET_READY_PRIORITY( pxTCB->uxPriority );  ##1,更新"最高優先級變量",函數實現見后 15             }
16             else
17             {
18                 mtCOVERAGE_TEST_MARKER();
19             }
20 
21             /* Is the task waiting on an event also? */
事件、信號量的隊列中,里面有兩個列表:WaitToSend和WaitToRcv。
而任務控制塊當中的兩個列表項item,一個是任務狀態列表項,它可能屬於就緒列表、掛起列表、延時列表等,上邊就是在從任務狀態的種種列表中刪除這個任務。
另一個列表項item,是事件列表項,它可能屬於某個信號量、事件的隊列中的,WaitToSend或WTRcv列表。 22 if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ) Container其實就是個List表頭,這個表頭屬於WaitToSend或WaitToRev. 23 { 24 ( void ) uxListRemove( &( pxTCB->xEventListItem ) ); 根據Item找到他的管理表頭,再將這個Item從列表中刪除. 25 } 26 else 27 { 28 mtCOVERAGE_TEST_MARKER(); 29 } 30 31 /* Increment the uxTaskNumber also so kernel aware debuggers can 32 detect that the task lists need re-generating. This is done before 33 portPRE_TASK_DELETE_HOOK() as in the Windows port that macro will 34 not return. */ 35 uxTaskNumber++; 36 37 if( pxTCB == pxCurrentTCB ) 38 { 39 /* A task is deleting itself. This cannot complete within the 40 task itself, as a context switch to another task is required. 41 Place the task in the termination list. The idle task will 42 check the termination list and free up any memory allocated by 43 the scheduler for the TCB and stack of the deleted task. */
刪除自己:空閑任務來釋放這個任務申請的TCB和Stack ##2,idle task內容見后 44 vListInsertEnd( &xTasksWaitingTermination, &( pxTCB->xStateListItem ) ); 45 46 /* Increment the ucTasksDeleted variable so the idle task knows 47 there is a task that has been deleted and that it should therefore 48 check the xTasksWaitingTermination list. */ 49 ++uxDeletedTasksWaitingCleanUp; 全局變量,記錄有多少個任務需要釋放內存。 50 51 /* The pre-delete hook is primarily for the Windows simulator, 52 in which Windows specific clean up operations are performed, 53 after which it is not possible to yield away from this task - 54 hence xYieldPending is used to latch that a context switch is 55 required. */ 56 portPRE_TASK_DELETE_HOOK( pxTCB, &xYieldPending ); 任務刪除鈎子函數 57 } 58 else 59 { 60 --uxCurrentNumberOfTasks; ##3 當前任務數,全局變量 61 prvDeleteTCB( pxTCB ); 刪除TCB方法 ##4 62 63 /* Reset the next expected unblock time in case it referred to 64 the task that has just been deleted. */ 65 prvResetNextTaskUnblockTime(); ##5 66 } 67 68 traceTASK_DELETE( pxTCB ); 69 } 70 taskEXIT_CRITICAL(); 71 72 /* Force a reschedule if it is the currently running task that has just 73 been deleted. */ 74 if( xSchedulerRunning != pdFALSE ) 調度器在運行 75 { 76 if( pxTCB == pxCurrentTCB ) 刪除的是當前運行的任務 77 { 78 configASSERT( uxSchedulerSuspended == 0 ); 79 portYIELD_WITHIN_API(); 執行任務切換 80 } 81 else 82 { 83 mtCOVERAGE_TEST_MARKER(); 84 } 85 } 86 }

##1  

(1)configUSE_PORT_OPTIMISED_TASK_SELECTION被定義為1的時候:

    /* A port optimised version is provided, call it only if the TCB being reset
    is being referenced from a ready list.  If it is referenced from a delayed
    or suspended list then it won't be in a ready list. */
    #define taskRESET_READY_PRIORITY( uxPriority )                                                        \
    {                                                                                                    \
        if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ ( uxPriority ) ] ) ) == ( UBaseType_t ) 0 )    \
        {                                                                                                \
            portRESET_READY_PRIORITY( ( uxPriority ), ( uxTopReadyPriority ) );                            \
        }                                                                                                \
    }

如果這個優先級的 任務就緒列表的長度為0,則調用下面的 portRESET_READY_PRIOR

#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1

    /* Store/clear the ready priorities in a bit map. */
    #define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) )
    #define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) )

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

    #define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31UL - ( uint32_t ) __clz( ( uxReadyPriorities ) ) )

#endif /* taskRECORD_READY_PRIORITY */

uxTopReadyPrior的定義:

PRIVILEGED_DATA static volatile UBaseType_t uxTopReadyPriority         = tskIDLE_PRIORITY;  //tskIDLE_PRIOR = 0
typedef unsigned long           UBaseType_t;

uxTopReadyPrior變量的每一位都表示,這一個優先級上邊,有沒有就緒任務。

如果這個優先級的 任務就緒列表的長度為0,則清零 uxTopReadyPrior變量的某一位,空閑任務優先級是0.

 

(2)configUSE_PORT_OPTIMISED_TASK_SELECTION被定義為0的時候:

taskRESET_READY_PRIORITY( uxPriority ) 被定義為空,只用變量uxTopReadyPrior來記錄最高就緒的優先級。

 

 

##2  空閑任務

如果某個任務要調用函數 vTaskDelete()刪除自身,那么這個任務的任務控制塊 TCB 和任務堆棧等

這些由 FreeRTOS 系統自動分配的內存需要在空閑任務中釋放掉 。空閑任務IdleTask的操作參見"低功耗模式 和 空閑任務"章節。

 

 

##3  當前任務數

uxCurrentNumOfTasks 在任務搶占的時候,應該會用,先保留。

 

##4  看看TCB和任務堆棧哪個是動態創建的,把它free掉,如果是靜態的那就不用free了...

 1 static void prvDeleteTCB( TCB_t *pxTCB )
 2     {
 3         /* This call is required specifically for the TriCore port.  It must be
 4         above the vPortFree() calls.  The call is also used by ports/demos that
 5         want to allocate and clean RAM statically. */
 6         portCLEAN_UP_TCB( pxTCB );  空的
 7 
 8         /* Free up the memory allocated by the scheduler for the task.  It is up
 9         to the task to free any memory allocated at the application level. */
10         #if ( configUSE_NEWLIB_REENTRANT == 1 )   不知道是啥
11         {
12             _reclaim_reent( &( pxTCB->xNewLib_reent ) );
13         }
14         #endif /* configUSE_NEWLIB_REENTRANT */
15 
16         #if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) && ( portUSING_MPU_WRAPPERS == 0 ) )
17         {
18             /* The task can only have been allocated dynamically - free both
19             the stack and TCB. */   這些宏導致TCB和Stack只能是動態創建的,直接free掉
20             vPortFree( pxTCB->pxStack );
21             vPortFree( pxTCB );
22         }
23         #elif( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE == 1 )
24         {
25             /* The task could have been allocated statically or dynamically, so
26             check what was statically allocated before trying to free the
27             memory. */
28             if( pxTCB->ucStaticallyAllocated == tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB )
29             {
30                 /* Both the stack and TCB were allocated dynamically, so both
31                 must be freed. */  TCB和stack都是動態創建的
32                 vPortFree( pxTCB->pxStack );
33                 vPortFree( pxTCB );
34             }
35             else if( pxTCB->ucStaticallyAllocated == tskSTATICALLY_ALLOCATED_STACK_ONLY )
36             {
37                 /* Only the stack was statically allocated, so the TCB is the
38                 only memory that must be freed. */  只有TCB是動態創建的
39                 vPortFree( pxTCB );
40             }
41             else
42             {
43                 /* Neither the stack nor the TCB were allocated dynamically, so
44                 nothing needs to be freed. */  TCB和stack都不是動態創建的
45                 configASSERT( pxTCB->ucStaticallyAllocated == tskSTATICALLY_ALLOCATED_STACK_AND_TCB    )
46                 mtCOVERAGE_TEST_MARKER();
47             }
48         }
49         #endif /* configSUPPORT_DYNAMIC_ALLOCATION */
50     }

 

 

##5

重新計算一下還要多長時間執行下一個任務,也就是下一個任務的解鎖時間。

如果下個任務的解鎖,剛好是被刪除的那個任務,那么變量NextTaskUnblockTime就不對了,所以要重新從延時列表中獲取一下。

  它是從延時列表的頭部來獲取的任務TCB,也可以再次驗證,延時任務列表是按延時時間排序的。   見“List_t列表

如果延時列表是空的,直接給默認值MAX_DELAY賦給NextTaskUnblockTime.

 1 static void prvResetNextTaskUnblockTime( void ) 2 {
 3 TCB_t *pxTCB;
 4 
 5     if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE )  延時列表是空的
 6     {
 7         /* The new current delayed list is empty.  Set xNextTaskUnblockTime to
 8         the maximum possible value so it is    extremely unlikely that the
 9         if( xTickCount >= xNextTaskUnblockTime ) test will pass until
10         there is an item in the delayed list. */
11         xNextTaskUnblockTime = portMAX_DELAY;
12     }
13     else
14     {
15         /* The new current delayed list is not empty, get the value of
16         the item at the head of the delayed list.  This is the time at
17         which the task at the head of the delayed list should be removed
18         from the Blocked state. */
19         ( pxTCB ) = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList );
20         xNextTaskUnblockTime = listGET_LIST_ITEM_VALUE( &( ( pxTCB )->xStateListItem ) );
21     }
22 }

 

 

 

 

 

 

 

留白


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM