当前位置: 首页 > news >正文

RTOS:初始化新任务(含源码复杂点解读)

文章目录

  • 前言
  • 一、任务初始化
  • 二、详细逻辑分析
    • 2.1、特权模式检查
    • 2.2、堆栈初始化
    • 2.3、计算堆栈顶部地址
    • 2.4、任务名称存储
    • 2.5、优先级检查
    • 2.6、设置任务优先级
    • 2.7、初始化列表项
    • 2.8、设置列表项所有者
    • 2.9、设置事件列表项值
    • 2.10、MPU设置
    • 2.11、TLS支持
    • 2.12、堆栈初始化
    • 2.13、任务状态和属性初始化
    • 2.14 任务句柄设置
  • 三、源码复杂点解读
    • 3.1、vListInitialiseItem
    • 3.2、listSET_LIST_ITEM_OWNER
    • 3.3、listSET_LIST_ITEM_VALUE
    • 3.4、vPortStoreTaskMPUSettings
    • 3.5、pxPortInitialiseStack


前言

操作系统,在入行嵌入式j接触它之前,感觉那是多么高深、神圣的技术,感觉它是高不可攀的。曾经也幻想过它有多么的复杂,在裸机编程时无数次想去应用这个技术,但无奈,无人指引,以致于每每都会望而却步。如今,也在多种OS的基础上做过各行各业的软件开发,所以想在闲暇之时,将使用过的OS内核软件逐行阅读,以提升自我编程能力、去了解更多软件编程思想。写此专栏文章的目的也仅仅是为了让这个过程留痕。

本文所有代码源于RTOS-Keenel

一、任务初始化

上源码
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();}
}

二、详细逻辑分析

用于初始化新任务。函数的主要任务是设置任务的各种属性,包括任务名称、任务优先级、任务状态、任务堆栈等。

2.1、特权模式检查

如果 portUSING_MPU_WRAPPERS 为1,则检查任务是否应创建在特权模式下。如果是,则将 xRunPrivileged 设置为 pdTRUE 否则设置为 pdFALSE。同时将 uxPriority 的特权为清除。

2.2、堆栈初始化

如果 tskSET_NEW_STACKS_TO_KNOWN_VALUE 设置为 1,则使用 memset 函数将任务堆栈填充为 0xa5。

2.3、计算堆栈顶部地址

根据 portSTACK_GROWTH 值 ,计算堆栈顶部地址。如果堆栈从高地址向低地址增长,则将 pxTopOfStack 设置为 pxNewTCB->pxStack[uxStackDepth - 1]。如果堆栈从低地址向高地址增长,则将 pxTopOfStack 设置为 pxNewTCB->pxStack ,同时,确保堆栈顶部地址对齐。

2.4、任务名称存储

如果 pcName 不为 NULL,则将任务名称存储在 pxNewTCB->pcTaskName 中。同时,确保任务名称字符串以空字符结尾。

2.5、优先级检查

确保 uxPriority 不大于 configMAX_PRIORITIES。如果大于,则将其设置为 configMAX_PRIORITIES-1。

2.6、设置任务优先级

将 pxNewTCB->uxPriority 设置为 uxPriority。如果 configUSE_MUTEXES 为1,则将 pxNewTCB->uxBasePriority 设置为 uxPriority。
此处的目的是由于互斥锁会解决优先级翻转问题,其原理就是提升相关任务的优先级,所以会记录当前任务的初始设置的优先级,以便恢复优先级。

2.7、初始化列表项

使用 vListInitialiseItem 函数初始化 pxNewTCB->xStateListItem 和 pxNewTCB->xEventListItem。

2.8、设置列表项所有者

使用 listSET_LIST_ITEM_OWNER 函数将 pxNewTCB 设置为 pxNewTCB->xStateListItem 和 pxNewTCB->xEventListItem 的所有者。

2.9、设置事件列表项值

使用 listSET_LIST_ITEM_VALUE 函数将 pxNewTCB->xEventListItem 的值设置为 configMAX_PRIORITIES - uxPriority。总是按照优先级顺序排列。

2.10、MPU设置

如果 portUSING_MPU_WRAPPERS 为 1,则使用 vPortStoreTaskMPUSettings 函数存储任务的MPU设置。

2.11、TLS支持

如果 configUSE_C_RUNTIME_TLS_SUPPORT 为1,则使用 configINIT_TLS_BLOCK 函数分配和初始化任务的TLS块。

2.12、堆栈初始化

使用 pxPortInitialiseStack 函数初始化任务堆栈,使其看起来像任务已经在运行,但被调度程序中断。返回地址设置为任务函数的开始。一旦对战初始化,堆栈顶部变量将被更新。

2.13、任务状态和属性初始化

如果 configNUMBER_OF_CORES 大于1.则将 pxNewTCB->xTaskRunState 设置为 taskTASK_NOT_RUNNING。如果任务代码是 prvIdleTask 或 prvPassiveIdleTask,则将 pxNewTCB->uxTaskAttributes 设置为 taskATTRIBUTE_IS_IDLE。

2.14 任务句柄设置

如果 pxCreatedTask 不为 NULL,则将 pxNewTCB 的地址赋值给 *pxCreatedTask。

三、源码复杂点解读

3.1、vListInitialiseItem

初始化TCB中的状态列表项和事件列表项

3.2、listSET_LIST_ITEM_OWNER

设置所有者的列表项,pxNewTCB是新的所所有者(任务控制块)

3.3、listSET_LIST_ITEM_VALUE

色湖之所有者的值,用于优先级排序。

3.4、vPortStoreTaskMPUSettings

任务的MPU配置。

3.5、pxPortInitialiseStack

初始化任务堆栈的函数,每个任务都有一个任务控制块(TCB),每个 TCB 都包含一个指向任务堆栈的指针。当创建新任务时,需要初始化任务的堆栈,以便任务可以开始运行。

通常需要完成以下工作:

  1. 将任务的堆栈指针设置为堆栈的顶部或底部,具体取决于堆栈的增长方向(portSTACK_GROWTH)。
  2. 在堆栈中存储任务的初始上下文,包括程序计数器(PC)、堆栈指针(SP)、状态寄存器(xPSR)等。
  3. 如果启用了 MPU 包装器,函数还需要设置任务的 MPU 设置。
    函数的原型通常如下:
StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters);

其中,pxTopOfStack 是指向堆栈顶部的指针,pxCode 是任务函数的入口点,pvParameters 是传递给任务函数的参数。

相关文章:

  • unity UI Canvas“高”性能写法
  • Unity-UI组件详解
  • 【mysql】BIGINT UNSIGNED字段被表示为float科学计数法 丢失精度问题
  • C++初赛的三讲
  • Java详解LeetCode 热题 100(25):LeetCode 141. 环形链表(Linked List Cycle)详解
  • web第八次课后作业--分层解耦
  • PS教程-萌新系统入门课课程视频+素材
  • String 学习总结
  • 力扣刷题 -- 232. 用栈实现队列
  • Android系统进程优先级
  • 组相对策略优化(GRPO):原理及源码解析
  • UE5 2D角色PaperZD插件动画状态机学习笔记
  • 支持TypeScript并打包为ESM/CommonJS/UMD三种格式的脚手架项目
  • 【python】三元图绘制(详细注释)
  • javascript 实战案例 二级联动下拉选框
  • 杭州白塔岭画室怎么样?和燕壹画室哪个好?
  • 6.RV1126-OPENCV 形态学基础膨胀及腐蚀
  • Spring Boot整合Druid与Dynamic-Datasource多数据源配置:从错误到完美解决
  • 1. 引言
  • SQL注入漏洞-上篇
  • 网站建设及安全管理/媒体宣传推广方案
  • 网站等保测评怎么做/网络营销图片
  • 青岛网站设计/注册域名在哪里注册
  • 个人备案的网站可以做什么/客户管理软件crm排名
  • 做网站公司排名电话/百度排行榜小说
  • wordpress插件 漏洞/济南seo网站优化公司