UCOS 堆栈大小 计算 (堆栈的决定性因素)
决定栈空间的大小,不仅需要计算任务本身的需求(局部变量、函数调用等),还要计算最多中断嵌套层数(保存寄存器、中断服务程序中局部变量等)
堆栈作用的就是用来保存局部变量,从实质上讲也就是将CPU寄存器的值保存到RAM中。在uCOS中,每一个任务都有一个独立的任务堆栈。为了深入理解任务堆栈的作用,不妨分析任务从“出生”到“消亡”的整个过程,具体就是分析任务的建立,运行,挂起几种状态中任务堆栈的变化情况。
目前假设系统运行着一个由用户创建的用以完成打印工作的任务TPrint。TPrint最初通过OSTaskCreate()函数创建,在该函数中与任务堆栈有关的第一段代码是大家比较熟悉的函数OSTaskStkInit(),这个函数是在uCOS移植过程中必须实现的,其作用是“初始化堆栈”,其实就是预先在RAM中的一块区域中把任务将来运行开始时CPU寄存器应处的状态(正确值)准备好,之后,任务第一次被内核调度器调度运行时,将这些准备好的数据(寄存器的值)推到CPU的寄存器中,如果数据设计的合理,CPU便会按照我们预先设计好的思路运行。所以,“初始化堆栈”实际上是做了一个“未雨绸缪”的工作。这个过程中有两点是必须慎重考虑的,一是PC该如何定位,二是CPU的其它寄存器(除PC之外)该怎么处理。先说第一点,因为任务是第一次运行,而任务从实质上将就是一段代码,所以PC指针应该定位到这段代码的第一行处,即所谓的入口地址(Entry Point)处,这个地址由任务指针保存着,所以把该指针值赋给PC即可。第二,这段代码还未被履行过,所以代码中的变量与CPU的其它寄存器一点关系也没有,因此R0-R12,R14可随便给值,或者不赋值也可,让这些寄存器保持原来的值,显然后者更为简单。最后再给CPSR赋值,用户可以根据实际需要使系统运行于系统模式或管理模式。经过入栈和出栈,此时SP指向任务堆栈的最底端(就是已经定义好的任务堆栈数组的最后一个元素)。
之后任务代码开始正式运行,因为CPU的寄存器是有限的,所以在运行时不可避免地要把一些临时变量暂时保存到堆栈中。具体应保存到哪个地址呢,不用担心,SP知道(任务第一次运行时,这个地址就是任务堆栈数组的最后一个元素的地址)。任务堆栈的大小和任务代码中临时变量的数目有关,如果这段代码临变量分外多,堆栈就应设计的大一些。
然后,TPrint任务由于某种理由将要被挂起,所以应把任务的运行现场放到堆栈里保护起来,TPrint任务再次运行时再把这个现场还原,任务就能从上次断点处紧接着运行。那么,这个现场是什么呢?从本质上讲,TPrint任务的运行过程就是CPU在履行一段特定的代码,所以这个现场就是CPU的现场,也就是寄存器的值。这些寄存器的值包含了代码履行时的所有消息,包括当前运行到了这段代码的哪个位置处(由PC值指明)。因此,把CPU的寄存器的值推入堆栈,然后记住栈顶指针的位置(SP由OSTCBCur->OSTCBStkPtr保存),当任务再次将要运行前,从SP指向的地址处依次把先前保存的CPU寄存器的值放到CPU的寄存器中,任务就可以从上次中断的地方准确无误地履行。这个过程就像突然把任务冻结了,与任务有关的任何东西都不能动了,一段时间之后又把任务解冻,与它有关的东西又变得可用,于是任务又可以活蹦乱跳地跑起来了。
从以上分析可以看出,任务堆栈至始至终伴随着任务,与之生死与共,它的作用可以概括为两点:第一,当任务运行时,它用来保存一些局部变量;第二,当任务挂起时,它负责保存任务的运行现场,也就是CPU寄存器的值。有些良友正是忽视了第一点,产生了“任务堆栈大小应是固定值的疑问”。我感觉,这也许与对函数OSTaskStkInit()的理解有关,我们都称之为堆栈初始化函数,但此处的“初始化”与我们理解的初始化不太一样,平时讲的(变量的)初始化似乎指的是将变量的所有成员都一一初始化。而此处的堆栈的初始化仅仅是初始化了很大一个堆栈的一小部分,因为当前只有这部分是有用的,而剩余的大部分用不到,所以不用初始化,就像有些变量不用初始化一样(有默认值或随机值)。更深入一点考虑,当任务挂起时,任务堆栈中保存任务挂起前CPU寄存器的这一连续的区域确定在整个堆栈的最上面;当任务重新开始运行时,SP弹出寄存器的值,这段区域变成空白的区域。而且,任务每次挂起前用来保存当前CPU寄存器这一连续区域在整个任务堆栈空间中是浮动的。
UCOS 堆栈大小 计算 (堆栈的决定性因素)的更多相关文章
- VC++中出现stack overflow错误时修改VC++的默认堆栈大小
VC++中,在栈空间上申请存储的结构体或者类对象的数组空间时,如果数组长度过大,造成申请的栈空间超过或者逼近1MB时,程序可以编译通过,但是不能够执行起来.打到调试模式时会弹出如下图所示的栈空间越界错 ...
- VC++堆栈大小设置
VC++堆栈默认大小是1M,如果你分配大于1M的堆,一般会出异常,这里你要把堆调大些,下面是VC++6.0与VC++2010的设置方法 VC++6.0: 工程==>设置==>“连接”界面, ...
- 线程堆栈大小 pthread_attr_setstacksize 的使用
pthread_create 创建线程时,若不指定分配堆栈大小,系统会分配默认值,查看默认值方法如下: # ulimit -s8192# 上述表示为8M:单位为KB. 也可以通过# ulimit -a ...
- C++类所占内存大小计算
C++类所占内存大小计算 说明:笔者的操作系统是32位的. class A {}; sizeof( A ) = ? sizeof( A ) = 1明明是空类,为什么编译器说它是1呢? 空类同样可以实例 ...
- linux信号机制 - 用户堆栈和内核堆栈的变化【转】
转自:http://itindex.net/detail/16418-linux-%E4%BF%A1%E5%8F%B7-%E5%A0%86%E6%A0%88 此文只简单分析发送信号给用户程序后,用户堆 ...
- Java对象的内存布局以及对象所需内存大小计算详解
1. 内存布局 在HotSpot虚拟机中,对象的内存布局可以分为三部分:对象头(Header). 实例数据(Instance Data)和对齐填充(Padding). 1) 对象头(Header): ...
- (一一七)基本文件操作 -SDWebImage清除缓存 -文件夹的大小计算
在iOS的App沙盒中,Documents和Library/Preferences都会被备份到iCloud,因此只适合放置一些记录文件,例如plist.数据库文件.缓存一般放置到Library/Cac ...
- TensorFlow与caffe中卷积层feature map大小计算
刚刚接触Tensorflow,由于是做图像处理,因此接触比较多的还是卷及神经网络,其中会涉及到在经过卷积层或者pooling层之后,图像Feature map的大小计算,之前一直以为是与caffe相同 ...
- C++类的大小计算汇总
C++中类涉及到虚函数成员.静态成员.虚继承.多继承.空类等. 类,作为一种类型定义,是没有大小可言的. 类的大小,指的是类的对象所占的大小.因此,用sizeof对一个类型名操作,得到的是具有该类型实 ...
随机推荐
- (2015年郑州轻工业学院ACM校赛题) C 数列
在我们做完B题之后就去看C题了, 发现很多人都已经做出来了, 并且一血还是我们学弟拿的, 感觉这题不难, 我们举了几个例子之后发现全是Alice 然后我们就决定意淫一下,试试看! 没想到就A了 - . ...
- 【转】linux 原子整数操作详解
原文网址:http://blog.csdn.net/hunanchenxingyu/article/details/8994379 printk(“%d\n”,atomic_read(&v)) ...
- Application之图书馆
前两天小编讲的都是些比较隐私的东西,为啥隐私?因为它俩(cookie和session)都只有用户自已才能使用和访问,今天小编来介绍个比较开放点的东西给大家. 小编虽已脱下学生服装多年,但如今忆起当年校 ...
- cppunit学习笔记
下载cppunit 链接:http://www.cnblogs.com/duxiuxing/p/4303809.html cppunit官方文档浅析 链接:http://www.cnblogs.com ...
- WAD Forwarder版USB Loader的安装和运行
背景知识 我使用Wad Manager来安装WAD版软件,所以需要先在Wii上面把Wad Manager准备好.详情可以参考我写的另外一篇文章<Wad Manager的下载和运行>(链接: ...
- java笔记13之成员变量与局部变量
成员变量和局部变量的区别 1在类中的位置不同 局部变量:类的方法体内 成员变量:类的方法之外 2内存的不同位置 局部变量:在栈内存中 成员位置:在堆内存 3生命周期不同 局部变量:随着方法的调用而存在 ...
- Linux操作系统Centos7.2版本搭建Apache+PHP+Mysql环境
对于在校大学生来说腾讯云1元主机很划算,所以就申请了一台,打算在上面学习下linux,使用版本为centos7.2版本.在服务器上比较推荐centos,此版本生命周期较长,而且网上有关centos的教 ...
- 微信小程序简易教程
刚接触到微信小程序开发,这里做一个简单的教程: 1. 获取微信小程序的 AppID 登录 https://mp.weixin.qq.com ,就可以在网站的"设置"-"开 ...
- [Angular 2] Using a Value from the Store in a Reducer
RxJS allows you to combine streams in various ways. This lesson shows you how to take a click stream ...
- 使用MFC读写Excel
_Application m_ExlApp; //组件服务器的各个classes _Workbook m_ExlBook; Workbooks m_ExlBooks; _W ...