FreeRTOS之xTaskCreate实现分析
FreeRTOS之xTaskCreate实现分析
1 函数接口
1.1 函数接口
BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
const char * const pcName,
const configSTACK_DEPTH_TYPE uxStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t * const pxCreatedTask )
1.2 函数参数简介
- TaskFunction_t pxTaskCode 任务的处理函数
- const char * const pcName 任务的名字
- const configSTACK_DEPTH_TYPE uxStackDepth 当前任务栈的大小,栈的实际大小为uxStackDepth * sizeof(StackType_t)
- void * const pvParameters 传入到任务处理函数的参数
- UBaseType_t uxPriority 当前任务的优先级
- TaskHandle_t * const pxCreatedTask 任务句柄
2 xTaskCreate的调用关系
2.1 调用关系
|- xTaskCreate
|- prvCreateTask
|- pxStack = pvPortMallocStack( ( ( ( size_t ) uxStackDepth ) * sizeof( StackType_t ) ) );
|- pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );
|- prvInitialiseNewTask
|- vListInitialiseItem( &( pxNewTCB->xStateListItem ) );
|- vListInitialiseItem( &( pxNewTCB->xEventListItem ) );
|- pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );
|- *pxCreatedTask = ( TaskHandle_t ) pxNewTCB;
|- prvAddNewTaskToReadyList
|- prvInitialiseTaskLists
|- prvAddTaskToReadyList
|- listINSERT_END( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xStateListItem ) );
2.2 调用关系示意图
根据上面的调用关系可以总结为下面简单的示意图示例
3 函数源码分析
3.1 xTaskCreate
- pxNewTCB = prvCreateTask( pxTaskCode, pcName, uxStackDepth, pvParameters, uxPriority, pxCreatedTask ); 创建并初始化当前要创建的任务TCB
- prvAddNewTaskToReadyList( pxNewTCB ); 将当前创建的任务插入到pxReadyTasksLists对应优先级的列表中
BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
const char * const pcName,
const configSTACK_DEPTH_TYPE uxStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t * const pxCreatedTask )
{
TCB_t * pxNewTCB;
BaseType_t xReturn;
traceENTER_xTaskCreate( pxTaskCode, pcName, uxStackDepth, pvParameters, uxPriority, pxCreatedTask );
pxNewTCB = prvCreateTask( pxTaskCode, pcName, uxStackDepth, pvParameters, uxPriority, pxCreatedTask );
if( pxNewTCB != NULL )
{
#if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_CORE_AFFINITY == 1 ) )
{
/* Set the task's affinity before scheduling it. */
pxNewTCB->uxCoreAffinityMask = configTASK_DEFAULT_CORE_AFFINITY;
}
#endif
prvAddNewTaskToReadyList( pxNewTCB );
xReturn = pdPASS;
}
else
{
xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
}
traceRETURN_xTaskCreate( xReturn );
return xReturn;
}
3.2 prvCreateTask
- pxStack = pvPortMallocStack( ( ( ( size_t ) uxStackDepth ) * sizeof( StackType_t ) ) ); 申请当前任务的栈空间,栈的size为( ( size_t ) uxStackDepth ) * sizeof( StackType_t )
- pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); 申请TCB任务块
- prvInitialiseNewTask( pxTaskCode, pcName, uxStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB, NULL ); 初始化当前任务的TCB
static TCB_t * prvCreateTask( TaskFunction_t pxTaskCode,
const char * const pcName,
const configSTACK_DEPTH_TYPE uxStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t * const pxCreatedTask )
{
TCB_t * pxNewTCB;
/* If the stack grows down then allocate the stack then the TCB so the stack
* does not grow into the TCB. Likewise if the stack grows up then allocate
* the TCB then the stack. */
#if ( portSTACK_GROWTH > 0 )
{
/* Allocate space for the TCB. Where the memory comes from depends on
* the implementation of the port malloc function and whether or not static
* allocation is being used. */
/* MISRA Ref 11.5.1 [Malloc memory assignment] */
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-115 */
/* coverity[misra_c_2012_rule_11_5_violation] */
pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );
if( pxNewTCB != NULL )
{
( void ) memset( ( void * ) pxNewTCB, 0x00, sizeof( TCB_t ) );
/* Allocate space for the stack used by the task being created.
* The base of the stack memory stored in the TCB so the task can
* be deleted later if required. */
/* MISRA Ref 11.5.1 [Malloc memory assignment] */
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-115 */
/* coverity[misra_c_2012_rule_11_5_violation] */
pxNewTCB->pxStack = ( StackType_t * ) pvPortMallocStack( ( ( ( size_t ) uxStackDepth ) * sizeof( StackType_t ) ) );
if( pxNewTCB->pxStack == NULL )
{
/* Could not allocate the stack. Delete the allocated TCB. */
vPortFree( pxNewTCB );
pxNewTCB = NULL;
}
}
}
#else /* portSTACK_GROWTH */
{
StackType_t * pxStack;
/* Allocate space for the stack used by the task being created. */
/* MISRA Ref 11.5.1 [Malloc memory assignment] */
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-115 */
/* coverity[misra_c_2012_rule_11_5_violation] */
pxStack = pvPortMallocStack( ( ( ( size_t ) uxStackDepth ) * sizeof( StackType_t ) ) );
if( pxStack != NULL )
{
/* Allocate space for the TCB. */
/* MISRA Ref 11.5.1 [Malloc memory assignment] */
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-115 */
/* coverity[misra_c_2012_rule_11_5_violation] */
pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );
if( pxNewTCB != NULL )
{
( void ) memset( ( void * ) pxNewTCB, 0x00, sizeof( TCB_t ) );
/* Store the stack location in the TCB. */
pxNewTCB->pxStack = pxStack;
}
else
{
/* The stack cannot be used as the TCB was not created. Free
* it again. */
vPortFreeStack( pxStack );
}
}
else
{
pxNewTCB = NULL;
}
}
#endif /* portSTACK_GROWTH */
if( pxNewTCB != NULL )
{
#if ( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 )
{
/* Tasks can be created statically or dynamically, so note this
* task was created dynamically in case it is later deleted. */
pxNewTCB->ucStaticallyAllocated = tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB;
}
#endif /* tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE */
prvInitialiseNewTask( pxTaskCode, pcName, uxStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB, NULL );
}
return pxNewTCB;
}
3.3 prvInitialiseNewTask
- memset( pxNewTCB->pxStack, ( int ) tskSTACK_FILL_BYTE, ( size_t ) uxStackDepth * sizeof( StackType_t ) ); 将栈内存都设置为0xa5的魔鬼数字
- pxTopOfStack = &( pxNewTCB->pxStack[ uxStackDepth - ( configSTACK_DEPTH_TYPE ) 1 ] );
pxTopOfStack = ( StackType_t * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) ); 栈地址对齐设置 - pxNewTCB->pxEndOfStack = pxTopOfStack; 记录当前TCB的栈顶
- 记录当前任务的名字,如果传入的名字参数是有效的则记录任务的名字,需要注意的是任务的名字长度是有限制的,其长度受configMAX_TASK_NAME_LEN限制,所以任务的名字尽量区简短有效的字符串便于记录。
if( pcName != NULL )
{
for( x = ( UBaseType_t ) 0; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ )
{
pxNewTCB->pcTaskName[ x ] = pcName[ x ];
/* Don't copy all configMAX_TASK_NAME_LEN if the string is shorter than
* configMAX_TASK_NAME_LEN characters just in case the memory after the
* string is not accessible (extremely unlikely). */
if( pcName[ x ] == ( char ) 0x00 )
{
break;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
/* Ensure the name string is terminated in the case that the string length
* was greater or equal to configMAX_TASK_NAME_LEN. */
pxNewTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1U ] = '\0';
}
- pxNewTCB->uxPriority = uxPriority; 记录当前任务的优先级
- vListInitialiseItem( &( pxNewTCB->xStateListItem ) ); 需要注意
pxItem->pxContainer = NULL;
的处理,pxContainer 在后面的处理中会指向pxReadyTasksLists中对应优先级的地址。
void vListInitialiseItem( ListItem_t * const pxItem )
{
traceENTER_vListInitialiseItem( pxItem );
/* Make sure the list item is not recorded as being on a list. */
pxItem->pxContainer = NULL;
/* Write known values into the list item if
* configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
traceRETURN_vListInitialiseItem();
}
- vListInitialiseItem( &( pxNewTCB->xEventListItem ) ); 该处理和上面的处理流程是一样的。
- listSET_LIST_ITEM_OWNER( &( pxNewTCB->xStateListItem ), pxNewTCB ); 记录当前xStateListItem的pvOwner 为pxNewTCB 。
#define listSET_LIST_ITEM_OWNER( pxListItem, pxOwner ) ( ( pxListItem )->pvOwner = ( void * ) ( pxOwner ) )
- pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters ); 初始化栈,这个栈的设置需要根据自己的任务调度去设置。
- *pxCreatedTask = ( TaskHandle_t ) pxNewTCB; 如果pxCreatedTask是有效的,则记录当前任务的TCB。
static void prvInitialiseNewTask( TaskFunction_t pxTaskCode,
const char * const pcName,
const configSTACK_DEPTH_TYPE uxStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t * const pxCreatedTask,
TCB_t * pxNewTCB,
const MemoryRegion_t * const xRegions )
{
StackType_t * pxTopOfStack;
UBaseType_t x;
#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 */
/* Avoid dependency on memset() if it is not required. */
#if ( tskSET_NEW_STACKS_TO_KNOWN_VALUE == 1 )
{
/* Fill the stack with a known value to assist debugging. */
( void ) memset( pxNewTCB->pxStack, ( int ) tskSTACK_FILL_BYTE, ( size_t ) uxStackDepth * sizeof( StackType_t ) );
}
#endif /* tskSET_NEW_STACKS_TO_KNOWN_VALUE */
/* Calculate the top of stack address. This depends on whether the stack
* grows from high memory to low (as per the 80x86) or vice versa.
* portSTACK_GROWTH is used to make the result positive or negative as required
* by the port. */
#if ( portSTACK_GROWTH < 0 )
{
pxTopOfStack = &( pxNewTCB->pxStack[ uxStackDepth - ( configSTACK_DEPTH_TYPE ) 1 ] );
pxTopOfStack = ( StackType_t * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) );
/* Check the alignment of the calculated top of stack is correct. */
configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0U ) );
#if ( configRECORD_STACK_HIGH_ADDRESS == 1 )
{
/* Also record the stack's high address, which may assist
* debugging. */
pxNewTCB->pxEndOfStack = pxTopOfStack;
}
#endif /* configRECORD_STACK_HIGH_ADDRESS */
}
#else /* portSTACK_GROWTH */
{
pxTopOfStack = pxNewTCB->pxStack;
pxTopOfStack = ( StackType_t * ) ( ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) + portBYTE_ALIGNMENT_MASK ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) );
/* Check the alignment of the calculated top of stack is correct. */
configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0U ) );
/* The other extreme of the stack space is required if stack checking is
* performed. */
pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + ( uxStackDepth - ( configSTACK_DEPTH_TYPE ) 1 );
}
#endif /* portSTACK_GROWTH */
/* Store the task name in the TCB. */
if( pcName != NULL )
{
for( x = ( UBaseType_t ) 0; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ )
{
pxNewTCB->pcTaskName[ x ] = pcName[ x ];
/* Don't copy all configMAX_TASK_NAME_LEN if the string is shorter than
* configMAX_TASK_NAME_LEN characters just in case the memory after the
* string is not accessible (extremely unlikely). */
if( pcName[ x ] == ( char ) 0x00 )
{
break;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
/* Ensure the name string is terminated in the case that the string length
* was greater or equal to configMAX_TASK_NAME_LEN. */
pxNewTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1U ] = '\0';
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* This is used as an array index so must ensure it's not too large. */
configASSERT( uxPriority < configMAX_PRIORITIES );
if( uxPriority >= ( UBaseType_t ) configMAX_PRIORITIES )
{
uxPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
pxNewTCB->uxPriority = uxPriority;
#if ( configUSE_MUTEXES == 1 )
{
pxNewTCB->uxBasePriority = uxPriority;
}
#endif /* configUSE_MUTEXES */
vListInitialiseItem( &( pxNewTCB->xStateListItem ) );
vListInitialiseItem( &( pxNewTCB->xEventListItem ) );
/* Set the pxNewTCB as a link back from the ListItem_t. This is so we can get
* back to the containing TCB from a generic item in a list. */
listSET_LIST_ITEM_OWNER( &( pxNewTCB->xStateListItem ), pxNewTCB );
/* Event lists are always in priority order. */
listSET_LIST_ITEM_VALUE( &( pxNewTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxPriority );
listSET_LIST_ITEM_OWNER( &( pxNewTCB->xEventListItem ), pxNewTCB );
#if ( portUSING_MPU_WRAPPERS == 1 )
{
vPortStoreTaskMPUSettings( &( pxNewTCB->xMPUSettings ), xRegions, pxNewTCB->pxStack, uxStackDepth );
}
#else
{
/* Avoid compiler warning about unreferenced parameter. */
( void ) xRegions;
}
#endif
#if ( configUSE_C_RUNTIME_TLS_SUPPORT == 1 )
{
/* Allocate and initialize memory for the task's TLS Block. */
configINIT_TLS_BLOCK( pxNewTCB->xTLSBlock, pxTopOfStack );
}
#endif
/* Initialize the TCB stack to look as if the task was already running,
* but had been interrupted by the scheduler. The return address is set
* to the start of the task function. Once the stack has been initialised
* the top of stack variable is updated. */
#if ( portUSING_MPU_WRAPPERS == 1 )
{
/* If the port has capability to detect stack overflow,
* pass the stack end address to the stack initialization
* function as well. */
#if ( portHAS_STACK_OVERFLOW_CHECKING == 1 )
{
#if ( portSTACK_GROWTH < 0 )
{
pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxNewTCB->pxStack, pxTaskCode, pvParameters, xRunPrivileged, &( pxNewTCB->xMPUSettings ) );
}
#else /* portSTACK_GROWTH */
{
pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxNewTCB->pxEndOfStack, pxTaskCode, pvParameters, xRunPrivileged, &( pxNewTCB->xMPUSettings ) );
}
#endif /* portSTACK_GROWTH */
}
#else /* portHAS_STACK_OVERFLOW_CHECKING */
{
pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged, &( pxNewTCB->xMPUSettings ) );
}
#endif /* portHAS_STACK_OVERFLOW_CHECKING */
}
#else /* portUSING_MPU_WRAPPERS */
{
/* If the port has capability to detect stack overflow,
* pass the stack end address to the stack initialization
* function as well. */
#if ( portHAS_STACK_OVERFLOW_CHECKING == 1 )
{
#if ( portSTACK_GROWTH < 0 )
{
pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxNewTCB->pxStack, pxTaskCode, pvParameters );
}
#else /* portSTACK_GROWTH */
{
pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxNewTCB->pxEndOfStack, pxTaskCode, pvParameters );
}
#endif /* portSTACK_GROWTH */
}
#else /* portHAS_STACK_OVERFLOW_CHECKING */
{
pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );
}
#endif /* portHAS_STACK_OVERFLOW_CHECKING */
}
#endif /* portUSING_MPU_WRAPPERS */
/* Initialize task state and task attributes. */
#if ( configNUMBER_OF_CORES > 1 )
{
pxNewTCB->xTaskRunState = taskTASK_NOT_RUNNING;
/* Is this an idle task? */
if( ( ( TaskFunction_t ) pxTaskCode == ( TaskFunction_t ) prvIdleTask ) || ( ( TaskFunction_t ) pxTaskCode == ( TaskFunction_t ) prvPassiveIdleTask ) )
{
pxNewTCB->uxTaskAttributes |= taskATTRIBUTE_IS_IDLE;
}
}
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
if( pxCreatedTask != NULL )
{
/* Pass the handle out in an anonymous way. The handle can be used to
* change the created task's priority, delete the created task, etc.*/
*pxCreatedTask = ( TaskHandle_t ) pxNewTCB;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
3.4 prvAddNewTaskToReadyList
该函数的实现需要考虑core的数量,分别core 0的处理和多核的处理。
单核的处理流程:
- uxCurrentNumberOfTasks = ( UBaseType_t ) ( uxCurrentNumberOfTasks + 1U ); 将当前任务的数量加1
- 记录当前任务的TCB:对于单核,
pxCurrentTCB = pxNewTCB;
- 如果当前的任务是链表的第一个任务,则调用prvInitialiseTaskLists();做链表的初始化工作。
- uxTaskNumber++;
- prvAddTaskToReadyList( pxNewTCB ); 将当前任务的TCB插入到pxReadyTasksLists链表中。
多核的处理流程:
- uxCurrentNumberOfTasks++;
- 如果当前创建的这个任务是链表的第一个任务,则调用prvInitialiseTaskLists();做链表的初始化工作。
- uxTaskNumber++;
- prvAddTaskToReadyList( pxNewTCB ); 将当前任务的TCB插入到pxReadyTasksLists链表中。
#if ( configNUMBER_OF_CORES == 1 )
static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB )
{
/* Ensure interrupts don't access the task lists while the lists are being
* updated. */
taskENTER_CRITICAL();
{
uxCurrentNumberOfTasks = ( UBaseType_t ) ( uxCurrentNumberOfTasks + 1U );
if( pxCurrentTCB == NULL )
{
/* There are no other tasks, or all the other tasks are in
* the suspended state - make this the current task. */
pxCurrentTCB = pxNewTCB;
if( uxCurrentNumberOfTasks == ( UBaseType_t ) 1 )
{
/* This is the first task to be created so do the preliminary
* initialisation required. We will not recover if this call
* fails, but we will report the failure. */
prvInitialiseTaskLists();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
/* If the scheduler is not already running, make this task the
* current task if it is the highest priority task to be created
* so far. */
if( xSchedulerRunning == pdFALSE )
{
if( pxCurrentTCB->uxPriority <= pxNewTCB->uxPriority )
{
pxCurrentTCB = pxNewTCB;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
uxTaskNumber++;
#if ( configUSE_TRACE_FACILITY == 1 )
{
/* Add a counter into the TCB for tracing only. */
pxNewTCB->uxTCBNumber = uxTaskNumber;
}
#endif /* configUSE_TRACE_FACILITY */
traceTASK_CREATE( pxNewTCB );
prvAddTaskToReadyList( pxNewTCB );
portSETUP_TCB( pxNewTCB );
}
taskEXIT_CRITICAL();
if( xSchedulerRunning != pdFALSE )
{
/* If the created task is of a higher priority than the current task
* then it should run now. */
taskYIELD_ANY_CORE_IF_USING_PREEMPTION( pxNewTCB );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB )
{
/* Ensure interrupts don't access the task lists while the lists are being
* updated. */
taskENTER_CRITICAL();
{
uxCurrentNumberOfTasks++;
if( xSchedulerRunning == pdFALSE )
{
if( uxCurrentNumberOfTasks == ( UBaseType_t ) 1 )
{
/* This is the first task to be created so do the preliminary
* initialisation required. We will not recover if this call
* fails, but we will report the failure. */
prvInitialiseTaskLists();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* All the cores start with idle tasks before the SMP scheduler
* is running. Idle tasks are assigned to cores when they are
* created in prvCreateIdleTasks(). */
}
uxTaskNumber++;
#if ( configUSE_TRACE_FACILITY == 1 )
{
/* Add a counter into the TCB for tracing only. */
pxNewTCB->uxTCBNumber = uxTaskNumber;
}
#endif /* configUSE_TRACE_FACILITY */
traceTASK_CREATE( pxNewTCB );
prvAddTaskToReadyList( pxNewTCB );
portSETUP_TCB( pxNewTCB );
if( xSchedulerRunning != pdFALSE )
{
/* If the created task is of a higher priority than another
* currently running task and preemption is on then it should
* run now. */
taskYIELD_ANY_CORE_IF_USING_PREEMPTION( pxNewTCB );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
taskEXIT_CRITICAL();
}
#endif
3.5 prvInitialiseTaskLists
在prvInitialiseTaskLists
函数中分别会初始化pxReadyTasksLists、xDelayedTaskList1、xDelayedTaskList2 、xPendingReadyList 、xTasksWaitingTermination 以及xSuspendedTaskList等链表。
- vListInitialise
void vListInitialise( List_t * const pxList )
{
traceENTER_vListInitialise( pxList );
/* The list structure contains a list item which is used to mark the
* end of the list. To initialise the list the list end is inserted
* as the only list entry. */
pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd );
listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( &( pxList->xListEnd ) );
/* The list end value is the highest possible value in the list to
* ensure it remains at the end of the list. */
pxList->xListEnd.xItemValue = portMAX_DELAY;
/* The list end next and previous pointers point to itself so we know
* when the list is empty. */
pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd );
pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd );
/* Initialize the remaining fields of xListEnd when it is a proper ListItem_t */
#if ( configUSE_MINI_LIST_ITEM == 0 )
{
pxList->xListEnd.pvOwner = NULL;
pxList->xListEnd.pxContainer = NULL;
listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( &( pxList->xListEnd ) );
}
#endif
pxList->uxNumberOfItems = ( UBaseType_t ) 0U;
/* Write known values into the list if
* configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList );
listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList );
traceRETURN_vListInitialise();
}
static void prvInitialiseTaskLists( void )
{
UBaseType_t uxPriority;
for( uxPriority = ( UBaseType_t ) 0U; uxPriority < ( UBaseType_t ) configMAX_PRIORITIES; uxPriority++ )
{
vListInitialise( &( pxReadyTasksLists[ uxPriority ] ) );
}
vListInitialise( &xDelayedTaskList1 );
vListInitialise( &xDelayedTaskList2 );
vListInitialise( &xPendingReadyList );
#if ( INCLUDE_vTaskDelete == 1 )
{
vListInitialise( &xTasksWaitingTermination );
}
#endif /* INCLUDE_vTaskDelete */
#if ( INCLUDE_vTaskSuspend == 1 )
{
vListInitialise( &xSuspendedTaskList );
}
#endif /* INCLUDE_vTaskSuspend */
/* Start with pxDelayedTaskList using list1 and the pxOverflowDelayedTaskList
* using list2. */
pxDelayedTaskList = &xDelayedTaskList1;
pxOverflowDelayedTaskList = &xDelayedTaskList2;
}
3.6 prvAddTaskToReadyList
- listINSERT_END( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xStateListItem ) ); 将当前任务的TCB插入到pxReadyTasksLists对应优先级的链表中,
#define prvAddTaskToReadyList( pxTCB ) \
do { \
traceMOVED_TASK_TO_READY_STATE( pxTCB ); \
taskRECORD_READY_PRIORITY( ( pxTCB )->uxPriority ); \
listINSERT_END( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xStateListItem ) ); \
tracePOST_MOVED_TASK_TO_READY_STATE( pxTCB ); \
} while( 0 )
3.7 listINSERT_END
- ( pxNewListItem )->pxContainer = ( pxList ); 该处理便于通过任务的TCB找到对应优先级的链表头。
#define listINSERT_END( pxList, pxNewListItem ) \
do { \
ListItem_t * const pxIndex = ( pxList )->pxIndex; \
\
/* Only effective when configASSERT() is also defined, these tests may catch \
* the list data structures being overwritten in memory. They will not catch \
* data errors caused by incorrect configuration or use of FreeRTOS. */ \
listTEST_LIST_INTEGRITY( ( pxList ) ); \
listTEST_LIST_ITEM_INTEGRITY( ( pxNewListItem ) ); \
\
/* Insert a new list item into ( pxList ), but rather than sort the list, \
* makes the new list item the last item to be removed by a call to \
* listGET_OWNER_OF_NEXT_ENTRY(). */ \
( pxNewListItem )->pxNext = pxIndex; \
( pxNewListItem )->pxPrevious = pxIndex->pxPrevious; \
\
pxIndex->pxPrevious->pxNext = ( pxNewListItem ); \
pxIndex->pxPrevious = ( pxNewListItem ); \
\
/* Remember which list the item is in. */ \
( pxNewListItem )->pxContainer = ( pxList ); \
\
( ( pxList )->uxNumberOfItems ) = ( UBaseType_t ) ( ( ( pxList )->uxNumberOfItems ) + 1U ); \
} while( 0 )
原文地址:https://blog.csdn.net/u014100559/article/details/143956642
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!