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 }

 

 

 

 

 

 

 

留白

posted @ 2017-11-16 21:03  为民除害  阅读(3362)  评论(0编辑  收藏  举报