2.1 创建任务

创建任务

// 静态创建任务的实现
TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode,	// 函数名称,空指针类型地址,标记函数入口
   							const char * const pcName,	// 任务名称,主要用于调试用
   							const uint32_t ulStackDepth,// 任务堆栈,需先指定数组,单位为4 Byte
   							void * const pvParameters,	// 任务形参
   							UBaseType_t uxPriority,		// 任务优先级
   							StackType_t * const puxStackBuffer, // 任务栈起始地址,数组的首地址
   							TCB_t * const pxTaskBuffer )// 任务句柄,其实是任务控制块TCB
{	
   TCB_t *pxNewTCB;		// 定义中间任务控制块
   TaskHandle_t xReturn;	// 定义最终返回的任务句柄

   if ( ( pxTaskBuffer != NULL ) && ( puxStackBuffer != NULL ) )	// 任务控制块与栈都分配空间
   {
   	pxNewTCB = ( TCB_t * ) pxTaskBuffer;						// 定义任务控制块 进行读写操作
   	pxNewTCB->pxStack = ( StackType_t * ) puxStackBuffer;		// 设置控制块的堆栈起始地址

   	prvInitialiseNewTask(	pxTaskCode,							// 任务入口
   							pcName,								// 任务名称,字符串形式
   							ulStackDepth,						// 任务栈大小,单位为字
   							pvParameters,						// 任务形参
   							uxPriority,							// 任务优先级
   							&xReturn,							// 任务句柄,任务控制块地址存入 句柄 中
   							pxNewTCB);							// 控制块
       prvAddNewTaskToReadyList( pxNewTCB );						// 将任务添加到 就绪列表中
   }
   else
   {
   	xReturn = NULL;												// 如果没有定义控制块,也没有分配栈空间,创建任务失败
   }

   return xReturn; 
}

// 设置任务控制块的栈顶指针,指针8字节对齐,写入函数名称,初始化任务栈,返回任务控制块句柄
static void prvInitialiseNewTask(	TaskFunction_t pxTaskCode,		// 任务入口
   								const char * const pcName,		// 任务名称,字符串形式
   								const uint32_t ulStackDepth,	// 任务栈大小,单位为字
   								void * const pvParameters,		// 任务形参
   								uxPriority,						// 任务优先级
   								TaskHandle_t * const pxCreatedTask,// 任务句柄
   								TCB_t pxNewTCB )				// 任务栈起始地址
{
   StackType_t *pxTopOfStack;										// 栈顶指针,
   UBaseType_t x;
   																// 栈顶指针 = 栈起始地址 + 栈大小 - 1,入栈自减
   pxTopOfStack = pxNewTCB->pxStack + ( ulStackDepth - ( uint32_t ) 1 );
   																// 栈顶指针 8 字节对齐,( ~( ( uint32_t ) 0x0007 ) ) ) = 0xFFFF FFF8
   pxTopOfStack = ( StackType_t * ) ( ( ( uint32_t ) pxTopOfStack ) & ( ~( ( uint32_t ) 0x0007 ) ) );
   																// 将任务的名称存储在 TCB 中,长度不得超过 configMAX_TASK_NAME_LEN
   for ( x = ( UBaseType_t ) 0; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ )
   {
   	pxNewTCB->pcTaskName[ x ] = pcName[ x ];
   	if ( pcName[ x ] == 0x00 )									// 任务名结束的条件是 '/0',或长度大于 configMAX_TASK_NAME_LEN
   		 break;
   }
   pxNewTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1 ] = '\0';		// 如果超过则直接截断,末尾 = '/0'
   																// 初始化栈内存,将一些数据压栈
   pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );
   if ( ( void * ) pxCreatedTask != NULL )							// 任务句柄 赋值为 任务控制块
   {
   	*pxCreatedTask = ( TaskHandle_t ) pxNewTCB;					// 返回任务句柄,本质 任务控制块地址(强转使用)
   }																// 地址存入 (*pxCreatedTask),pxCreatedTask为句柄地址
}

StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
{
   pxTopOfStack--;							// 开始压栈,栈顶存放xPSR
   *pxTopOfStack = portINITIAL_XPSR;		// 最先入栈 0x01000000,也就是xPSR,标识当前ARM、状态或者Thumb状态
   pxTopOfStack--;
   *pxTopOfStack = ( StackType_t ) pxCode;	// 入栈函数入口地址,出栈到PC直接执行函数
   pxTopOfStack--;
   *pxTopOfStack = ( StackType_t ) prvTaskExitError;	// 压栈LR指针,任务不许返回,返回就跳转执行无限循环
   pxTopOfStack -= 5;									// R12, R3, R2 and R1 默认初始化为0
   *pxTopOfStack = ( StackType_t ) pvParameters;		// 压栈R0,R0一般保存函数参数
   pxTopOfStack -= 8;									// 默认初始化为0,异常发生时自动压栈,R11..R4

   return pxTopOfStack;								// 最终返回可用栈指针
   //传入的栈顶指针是个地址,比如栈顶 0x0200 0000 是栈顶,0x01FF FFF8 存储 函数入口地址
}

就绪列表

就绪列表,是一个列表数组,数组大小由最大任务优先级来指定

在就绪列表数组中,数组下标表示任务的优先级,优先级一致的任务会将列表项插入同一下表的列表

List_t pxReadyTasksLists[ configMAX_PRIORITIES ];
// 创建新任务添加到就绪列表中
static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB )
{
	taskENTER_CRITICAL();				// 进入临界段,确保列表操作不会被中断打断
	{
		uxCurrentNumberOfTasks++;		// 全局任务计数器,标识当前任务数量
		if( pxCurrentTCB == NULL )		// 当前任务控制块指针为空,处于初次创建任务;没有任务在运行
		{
			pxCurrentTCB = pxNewTCB;	// 替换,马上执行就是这个任务
			if( uxCurrentNumberOfTasks == ( UBaseType_t ) 1 )	// 如果是第一次创建任务,任务就绪列表当前为空
			{
				prvInitialiseTaskLists();						// 初始化相关任务列表,就绪,延时,挂起就绪,阻塞,删除等
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		else									// 已经创建任务;当前有任务在运行
		{
			if( xSchedulerRunning == pdFALSE )	// 判断调度器是否开启,是否有任务在运行
			{
				if( pxCurrentTCB->uxPriority <= pxNewTCB->uxPriority )	// 当前任务的优先级 < 新创建任务的优先级
				{
					pxCurrentTCB = pxNewTCB;							// 新创建任务抢占调度器,改变要执行的任务
				}
				else
				{
					mtCOVERAGE_TEST_MARKER();
				}
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
																		// 接下来运行任务为之前执行任务,或新创建任务
		uxTaskNumber++;

		#if ( configUSE_TRACE_FACILITY == 1 )
		{
			pxNewTCB->uxTCBNumber = uxTaskNumber;						// 用于调试追踪任务
		}
		#endif
		traceTASK_CREATE( pxNewTCB );
		prvAddTaskToReadyList( pxNewTCB );								// 将新任务添加到就绪列表中
		portSETUP_TCB( pxNewTCB );										// 设置新建任务的任务控制块,强转为 void *类型
	}
	taskEXIT_CRITICAL();

	if( xSchedulerRunning != pdFALSE )									// 如果调度器在运行
	{
		if( pxCurrentTCB->uxPriority < pxNewTCB->uxPriority )			// 新建任务优先级 高于 在运行任务优先级
		{
			taskYIELD_IF_USING_PREEMPTION();							// 执行任务调度
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}
	}
	else
	{
		mtCOVERAGE_TEST_MARKER();
	}
}


static void prvInitialiseTaskLists( void )
{
	UBaseType_t uxPriority;

	for( uxPriority = ( UBaseType_t ) 0U; uxPriority < ( UBaseType_t ) configMAX_PRIORITIES; uxPriority++ )
	{
		vListInitialise( &( pxReadyTasksLists[ uxPriority ] ) );		// 从优先级0开始,遍历各优先级就绪列表,完成对列表的初始化
	}			// Index指向END,Value为最大值,next指针指向END

	vListInitialise( &xDelayedTaskList1 );								// 初始化延时任务列表,也是阻塞列表
	vListInitialise( &xDelayedTaskList2 );								// 阻塞都会指定阻塞时间,所以使用延时列表作为阻塞列表
	vListInitialise( &xPendingReadyList );								// 仅用于调度器停止,就绪任务放入该列表,而不是就绪列表
																		// 执行中断,调度器也被叫停,也会加入到该列表中
	#if ( INCLUDE_vTaskDelete == 1 )
	{
		vListInitialise( &xTasksWaitingTermination );					// 初始化删除未释放内存列表
	}
	#endif /* INCLUDE_vTaskDelete */

	#if ( INCLUDE_vTaskSuspend == 1 )
	{
		vListInitialise( &xSuspendedTaskList );							// 初始化挂起任务列表
	}
	#endif /* INCLUDE_vTaskSuspend */
	pxDelayedTaskList = &xDelayedTaskList1;								// 延时任务列表赋值,通过指针进行操作
	pxOverflowDelayedTaskList = &xDelayedTaskList2;
}

#define prvAddTaskToReadyList( pxTCB )																				\
	traceMOVED_TASK_TO_READY_STATE( pxTCB );																		\
	taskRECORD_READY_PRIORITY( ( pxTCB )->uxPriority );																\
	vListInsertEnd( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xStateListItem ) );				\
	tracePOST_MOVED_TASK_TO_READY_STATE( pxTCB )// 将任务 状态列表项 挂载指定优先级的就绪列表项下,挂载任务到就绪列表

初始化
void vListInitialise( List_t * const pxList )
{
	pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd );

	pxList->xListEnd.xItemValue = portMAX_DELAY;
	pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd );
	pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd );

	pxList->uxNumberOfItems = ( UBaseType_t ) 0U;

	listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList );
	listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList );
}

在任务控制块中,有一个 xStateListItem 列表项。

每创建成功一个任务,就会将TCB中的这个列表项挂载在对应(优先级)的列表下

// 将阻塞态任务添加到就绪列表中,区别于上面的任务
// 上面的任务名称是 prvAddNewTaskToReadyList,NewTask
#define prvAddTaskToReadyList( pxTCB )																\
	traceMOVED_TASK_TO_READY_STATE( pxTCB );														\
	taskRECORD_READY_PRIORITY( ( pxTCB )->uxPriority );												\
	vListInsertEnd( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xStateListItem ) ); \
	tracePOST_MOVED_TASK_TO_READY_STATE( pxTCB )
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值