uCOSIII学习笔记之任务堆栈的初始化
来源:互联网 发布:广州数据库开发工程师 编辑:程序博客网 时间:2024/05/22 09:06
任务栈的初始化在任务创建的时候完成,由函数 OS_Task_Create() 或者 OSTaskCreateExt() 调用函数 OSTaskStkInit() 来完成。任务栈的初始化过程跟具体的CPU有很大的关联。 (本文的所参考的初始化过程基于Cortex-M3内核)
栈有四种类型:
注:
如果有表达式 a = i++ 它等价于 a = i ; i = i + 1;(先使用值,后增加)
如果有表达式 a = ++i 它等价于 i = i + 1; a = i;(先自加,后使用值)
满增栈
PUSH R0 ;*(++SP) = R0POP R0 ;R0 = *(SP--)
满减栈
PUSH R0 ;*(--SP) = R0POP R0 ;R0 = *(SP++)
空增栈
PUSH R0 ;*(SP++) = R0POP R0 ;R0 = *(--SP)
空减栈
PUSH R0 ;*(SP--) = R0POP R0 ;R0 = *(++SP)
在ARM中,使用的是满减栈!
- 在OS_Task_Create() 函数执行的时候,我们传入了三个关于栈的参数,分别是:
CPU_STK *p_stk_baseCPU_STK_SIZE stk_limitCPU_STK_SIZE stk_size
第一个参数是栈的基地址,基地址总是栈空间的低地址;第二个参数是任务栈的深度标记,该参数的数值代表了栈溢出警告之前栈内应该剩余的空间大小;第三个参数是实际分配的任务栈的大小。
#if (CPU_CFG_STK_GROWTH == CPU_STK_GROWTH_HI_TO_LO) p_stk_limit = p_stk_base + stk_limit;#else p_stk_limit = p_stk_base + (stk_size - 1u) - stk_limit;#endif
通过在cpu.h这个文件中的宏定义设置堆栈的增长方向,根据不同的增长方向,给p_stk_limit设置相应的值,当栈指针到达这个地址时,说明栈的使用已经达到了预警值,再继续使用栈会有栈溢出的危险。在调用函数OS_Task_Create()时,我们给出了stk_limit和stk_size两个参数,正常使用的情况下,stk_limit < stk_size , stk_limit 的值越大说明栈的使用达到预警值时,栈空间实际留有的裕量越多。例如:stk_limit = stk_size/10 , 则当栈空间使用超过90%时,就达到了栈空间的极限深度。
在函数OSTaskStkInit()中,栈的初始化过程如下:
CPU_STK *OSTaskStkInit (OS_TASK_PTR p_task, void *p_arg, CPU_STK *p_stk_base, CPU_STK *p_stk_limit, CPU_STK_SIZE stk_size, OS_OPT opt){ CPU_STK *p_stk; (void)opt; /* Prevent compiler warning */ p_stk = &p_stk_base[stk_size]; /* Load stack pointer */ /* Registers stacked as if auto-saved on exception */ *--p_stk = (CPU_STK)0x01000000u; /* xPSR */ *--p_stk = (CPU_STK)p_task; /* Entry Point */ *--p_stk = (CPU_STK)OS_TaskReturn; /* R14 (LR) */ *--p_stk = (CPU_STK)0x12121212u; /* R12 */ *--p_stk = (CPU_STK)0x03030303u; /* R3 */ *--p_stk = (CPU_STK)0x02020202u; /* R2 */ *--p_stk = (CPU_STK)p_stk_limit; /* R1 */ *--p_stk = (CPU_STK)p_arg; /* R0 : argument */ /* Remaining registers saved on process stack */ *--p_stk = (CPU_STK)0x11111111u; /* R11 */ *--p_stk = (CPU_STK)0x10101010u; /* R10 */ *--p_stk = (CPU_STK)0x09090909u; /* R9 */ *--p_stk = (CPU_STK)0x08080808u; /* R8 */ *--p_stk = (CPU_STK)0x07070707u; /* R7 */ *--p_stk = (CPU_STK)0x06060606u; /* R6 */ *--p_stk = (CPU_STK)0x05050505u; /* R5 */ *--p_stk = (CPU_STK)0x04040404u; /* R4 */ return (p_stk);}
在函数的一开始就执行了语句:
p_stk = &p_stk_base[stk_size];
栈指针最初应该指向最高地址,实际分配的任务栈的最高地址是:&p_stk_base[stk_size - 1],但由于在ARM中,使用的是满减栈,如果p_stk = &p_stk_base[stk_size - 1]; 则任务栈第一个元素并没有使用,实际执行的语句虽然貌似数组越界了,但是地址“&p_stk_base[stk_size]”从未解引用,所以并没有造成数组使用越界。
在执行异常服务程序之前,PSR、返回地址、LR、R12、R3、R2、R1、R0这些寄存器是自动保存的,在执行PendSV异常服务进行任务切换时,不需要保存这些寄存器的值。程序初始化栈时,这些寄存器在栈中顺序与自动保存的顺序完全一样,在异常发生时,自动的保存的顺序就是PSR……R0. 初始化时,其中返回地址就是任务函数的入口地址;在任务函数开始执行时,我们传入了参数(void *p_arg),所以在创建任务,初始化堆栈时,将参数赋值给R0寄存器。剩下的R11-R4寄存器依次放入初始化栈。
返回当前的栈顶指针,至此,任务栈的初始化完成。
疑问:
*--p_stk = (CPU_STK)p_stk_limit; /* R1 */
执行了这句语句后,在此任务开始执行时,p_stk_limit的值将被赋值到寄存器R1,我还没弄明白这句代码的作用。
- uCOSIII学习笔记之任务堆栈的初始化
- uCOSIII学习笔记之OSCtrSW( )
- activity的任务堆栈学习笔记二
- uC/OS-II 学习笔记之:任务堆栈
- UCOSIII学习之UCOSIII系统移植
- OSTaskStkInit():任务堆栈结构的初始化
- OSTaskStkInit():任务堆栈结构的初始化
- OSTaskStkInit():任务堆栈结构的初始化
- Activity的任务堆栈学习笔记(一)
- STM32-UCOSIII学习笔记3
- uC/OS-II 学习笔记:任务堆栈
- LiteOS学习第六篇——任务堆栈初始化
- 深入学习android之任务与堆栈
- ucosIII 系统任务占用的优先级
- 数据结构学习笔记之堆栈
- linux中0号任务的创建以及堆栈初始化
- ucosIII学习
- 安卓学习笔记---Intent的使用,如何改变Activity在当前任务堆栈中的顺序
- POJ 3977(枚举+二分)
- 点分治模板 (例题:树中点对距离) 待更新【坑】
- Codeforces Round #316 (Div. 2) D. Tree Requests
- 使用传统hbase的api创建hbase表(scala)
- 波浪线
- uCOSIII学习笔记之任务堆栈的初始化
- C# Lazy<T>实现单例模式
- 利用cookie保存用户登录信息初步
- 解释器模式——我最懂你
- JavaScript对象介绍
- WebView笔记
- 2017 京东校招编程题 进制转换
- Ubuntu 14.04利用byzanz制作gif格式动画
- k均值聚类,密度聚类,层次聚类