/* FreeRTOS Kernel V10.4.1 */
/* 为了便于描述,源码中去除了一些用于调试的语句,如常见的trace_XXX, mtCOVERAGE_TEST_MARKER()等 */
原文链接:https://www.cnblogs.com/yanpio/p/14892113.html
FreeRTOS
提供了一系列的任务创建函数,主要的区别是创建任务时,内存分配方式存在差异。下表对比了几种任务创建函数的内存分配方式,从源码中可以具体了解到这些不同之处。
四种任务创建函数都会调用初始化函数prvInitialiseNewTask()
和添加列表函数prvAddNewTaskToReadyList()
.以下首先介绍这两个函数。
/* 初始化新的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;
}
}
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 ) );
/*---------------------------------------------------------------------------------------------------------*/
/* 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 */
/* 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
/* 仅在实现了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
#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
#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
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
}
/* 此函数涉及到任务延时,此处简单说明,会在后续的文章中详细描述 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 );
}
}
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 );
}
}
FreeRTOS Task Management(3)- 任务创建与删除
原文:https://www.cnblogs.com/yanpio/p/14892113.html