目录
1 任务的句柄(结构体)
2 创建任务主要工作
2.1 创建任务初始化源码分析
2.2 任务添加到就绪列表源码分析
2.3任务堆栈的初始化源码分析
问:R0为什么要入栈保存?因为作为函数的第一个传入参数,必须也要保存。
问:为什么要入栈异常返回值?
1 任务的句柄(结构体)
/********结构体指针*******/
typedef struct tskTaskControlBlock
{
 volatile StackType_t *pxTopOfStack;          //任务栈顶
 ListItem_t   xStateListItem;                 //状态列表
 ListItem_t   xEventListItem;                 //事件列表
 UBaseType_t uxPriority;                      //任务优先级
 StackType_t *pxStack;                        //任务栈地址
 char pcTaskName[ configMAX_TASK_NAME_LEN ];  //任务名称
} tskTCB; 
2 创建任务主要工作
任务栈分配内存、控制块分配内存,把任务添加到就绪列表。
补充一个知识:M4权威指南4.4.3栈存储


2.1 创建任务初始化源码分析
具体工作,把栈空间的高地址分配给栈顶,任务分配的优先级,任务控制块
 链接到任务状态表中,任务控制块连接到事件表中,任务堆栈初始化,之后返回任务栈顶。
/*********创建任务********/
//任务创建函数,其中osThreadCreate是CMSIS封装接口
Key_TaskHandle = osThreadCreate(osThread(Key_Task), NULL);
/**
 * @description: osThreadCreate内部是xTaskCreate,创建一个任务线程,任务栈分配内存、控制块分配内存,把任务添加到就绪列表,初始化
 * @param {TaskFunction_t}pxTaskCode 函数指针(函数名)
 * @param {const char *}pcName 任务名称(字符串)
 * @param {const uint16_t} usStackDepth  任务堆栈大小,单位为字
 * @param {void *} const pvParameters 任务传入参数
 * @param {UBaseType_t} uxPriority 任务优先级
 * @param {TaskHandle_t *} const pxCreatedTask 任务句柄
 * @return {const char *}pxTaskCode
 */
BaseType_t xTaskCreate(	TaskFunction_t pxTaskCode,
						const char * const pcName,
						const uint16_t usStackDepth,
						void * const pvParameters,
						UBaseType_t uxPriority,
						TaskHandle_t * const pxCreatedTask ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
{
    TCB_t *pxNewTCB;
    BaseType_t xReturn;
	//硬件平台栈增长方式:M4是满减栈,portSTACK_GROWTH = -1
#if( portSTACK_GROWTH > 0 )
	{
		//略
	}
#else /* portSTACK_GROWTH */
	{
	    StackType_t *pxStack;
		/* 任务栈内存分配*/
		pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) );
		if( pxStack != NULL )
		{
			/* 任务控制块内存分配 */
			pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); /*lint !e961 MISRA exception as the casts are only redundant for some paths. */
			if( pxNewTCB != NULL )  
			{
				/* 赋值栈地址 */
				pxNewTCB->pxStack = pxStack;
			}
			else
			{
				/* 释放栈空间 */
				vPortFree( pxStack );
			}
		}
		else
		{
			pxNewTCB = NULL;
		}
	}
#endif /* portSTACK_GROWTH */
	if( pxNewTCB != NULL )
	{
		/*创建任务初始化,把栈空间的高地址分配给栈顶,任务分配的优先级,任务控制块
        链接到任务状态表中,任务控制块连接到事件表中,//任务堆栈初始化,之后返回任
        务栈顶*/
		prvInitialiseNewTask( pxTaskCode, pcName, ( uint32_t ) usStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB, NULL );
        //把任务添加到就绪列表中
		prvAddNewTaskToReadyList( pxNewTCB );
		xReturn = pdPASS;
	}
	else
	{
		xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
	}
	return xReturn;
} 
2.2 任务添加到就绪列表源码分析
static void prvInitialiseNewTask( 	TaskFunction_t pxTaskCode,
									const char * const pcName,
									const uint32_t ulStackDepth,
									void * const pvParameters,
									UBaseType_t uxPriority,
									TaskHandle_t * const pxCreatedTask,
									TCB_t *pxNewTCB,
									const MemoryRegion_t * const xRegions ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
{
    StackType_t *pxTopOfStack;
    UBaseType_t x;
	/*计算栈顶的指针*/
	#if( portSTACK_GROWTH < 0 ) //满减栈
	{
        //把栈空间的高地址分配给栈顶
		pxTopOfStack = pxNewTCB->pxStack + ( ulStackDepth - ( uint32_t ) 1 );
        //栈对齐-----栈要8字节对齐
		pxTopOfStack = ( StackType_t * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) ); 
		/*检查是否有错误*/
		configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
	}
	#else /* portSTACK_GROWTH */
	{
		//不是满减栈不需要关注
	}
	#endif /* portSTACK_GROWTH */
	/*存储任务名称,即数组拷贝*/
	for( x = ( UBaseType_t ) 0; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ )
	{
		pxNewTCB->pcTaskName[ x ] = pcName[ x ];
		if( pcName[ x ] == 0x00 )
		{
			break;
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}
	}
	/*补齐字符串*/
	pxNewTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1 ] = '\0';
	/*判断任务分配的优先级是否大于最大值*/
	if( uxPriority >= ( UBaseType_t ) configMAX_PRIORITIES )
	{
		uxPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U;
	}
	else
	{
		mtCOVERAGE_TEST_MARKER();
	}
    //赋值任务优先级
	pxNewTCB->uxPriority = uxPriority;
    //状态表、事件表初始化
	vListInitialiseItem( &( pxNewTCB->xStateListItem ) );
	vListInitialiseItem( &( pxNewTCB->xEventListItem ) );
	/*任务控制块链接到状态表中*/
	listSET_LIST_ITEM_OWNER( &( pxNewTCB->xStateListItem ), pxNewTCB );
	/*任务控制块连接到事件表中 */
	listSET_LIST_ITEM_VALUE( &( pxNewTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
	listSET_LIST_ITEM_OWNER( &( pxNewTCB->xEventListItem ), pxNewTCB );
	
	#if( portUSING_MPU_WRAPPERS == 1 )
	{
		//不执行
	}
	#else /* portUSING_MPU_WRAPPERS */
	{
        //任务堆栈初始化,之后返回任务栈顶
		pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );
	}
	#endif /* portUSING_MPU_WRAPPERS */
    
	if( ( void * ) pxCreatedTask != NULL )
	{
		/*赋值任务的句柄,即任务控制块*/
		*pxCreatedTask = ( TaskHandle_t ) pxNewTCB;
	}
	else
	{
		mtCOVERAGE_TEST_MARKER();
	}
} 
接下来就是分析上面任务堆栈的初始化
2.3任务堆栈的初始化源码分析
补充:资料阅读M4权威指南,第八章节,分析异常处理
为什么分析异常处理?任务调度其实就是通过CPU内核异常处理实现的

 
 
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
{
    //入栈程序状态寄存器
	pxTopOfStack--; 
	*pxTopOfStack = portINITIAL_XPSR;	/* xPSR */
    //入栈PC指针
	pxTopOfStack--;
	*pxTopOfStack = ( ( StackType_t ) pxCode ) & portSTART_ADDRESS_MASK;	/* PC */
    //入栈LR链接寄存器
    pxTopOfStack--;
	*pxTopOfStack = ( StackType_t ) prvTaskExitError;	/* LR */
    //不需要初始化
	pxTopOfStack -= 5;	/* R12, R3, R2 and R1. */
    //R0作为传参入栈
	*pxTopOfStack = ( StackType_t ) pvParameters;	/* R0 */
    //异常返回值入栈,返回值是确定程序使用的栈地址是哪一个?MSP PSP
    pxTopOfStack--;
    pxTopOfStack = portINITIAL_EXEC_RETURN;
    
    //不初始化
	pxTopOfStack -= 8;	/* R11, R10, R9, R8, R7, R6, R5 and R4. */
    //最终返回栈顶
	return pxTopOfStack;
} 
补充知识:栈帧

程序的写法顺序按照下图所示
 
问:R0为什么要入栈保存?因为作为函数的第一个传入参数,必须也要保存。

问:为什么要入栈异常返回值?
返回值是确定程序使用的栈地址是哪一个?MSP PSP。

把任务添加到就绪列表这部分暂未分析,后续会结合其他内容分析
prvAddNewTaskToReadyList( pxNewTCB )

















![学习babylon.js --- [3] 开启https](https://img-blog.csdnimg.cn/de5381c579a1456f981f34e9b42c8a60.png)

