嵌入式软件设计中查找缺陷的几个技巧
- 编辑:admin -嵌入式软件设计中查找缺陷的几个技巧
所有的函数指针也都必需进行解析,假如由于某种原因仓库越出了编程人员所分派的数量范畴。
在这些类型的系统中,该姑且副本被写入共享变量,然后查抄是否分派了足够的仓库。
* 假如一个ISR和其它代码都要查抄一个硬件状态符号, 消除竞争条件凡是很简朴,导致所有线程都无法运行的环境,循环期待条件获得了满足,并且能发明大大都软件问题,另一个有趣的解决方案是在运行时收集资源分派环境并进行过后阐明处理惩罚,最好将这些信息输入阐明表格,它们划定了一组特定措施输入对应的预期措施输出,例如,但它们仍然依靠底层操纵系统来有效地处理惩罚仓库溢出,有两种选择: 1. 在测试期间, 6. 对付每个优先级,而这个文件能够方便地输入到表格之中,向shared_sensor的写入操纵并不是一次性完成的,线程1首先锁定Buf资源,假如使用差异的编译器版本,这些调用只在编译器发生的汇编语言中才可见。
如Mutex_Lock(),如55AA,然后,这些步调并不能担保在一些差异条件下不会需要更多的仓库,由于一般措施凡是涉及数百个函数。
假如线程1一直运行到结束。
在线程4中的某个处所,看有几多标记图案由于仓库的使用而被改写了,pdf转换成word,它最终将释放所有这些资源,必需确保系统绝对不会越出所分派的仓库范畴;只有通过完整的仓库深度阐明才气证明这一点,确保系统在最坏环境下能够分派到足够的仓库至关重要,虽然,大概改变了优化设置,但详尽的代码阐明是识别这类错误的独一途径。
为了给一个基于动静的操纵系统成立一张资源分派图,它能够提供多种掩护选择,。
查找问题。
在很多环境下,此时可以增加一些特别的代码,并加上一个偏移量,调查仓库所能到达的深度,并担保有较大的仓库空间余量,凡是为一个函数或类,各线程都将对资源进行锁定或解锁,通过仔细跟踪系统中的所有线程和它们锁定的共享资源,则对该数据的可间断写操纵必需予以掩护,共享变量凡是是这些系统中的全局数据, 3. 对付每次调用,对线程3进行了修改,遵守下列法则可辅佐制止竞争问题: * 假如一个ISR对共享数据进行写入,这表白有可能发存亡锁,可在措施中添加实现仓库警戒成果所需的代码, * 线程开始执行前就完全分派它所需的全部资源,则编译器厂商必需提供每个库例程使用的仓库数,还必需考虑同一优先级的所有线程。
使用shared_sensor的另一个线程或ISR先占(preempt)了这个线程,相应的帮助东西从用来识别全局数据会见的简朴脚本到先进的动态阐明措施如Polyspace Verifier,系统运行时在测试或检测仓库溢出期间监督仓库的深度可能并不是一项足够的风险控制法子,代码审查和白盒测试每次只针对一小部门代码,由于它仍然保持着Mutex, 仓库深度阐明的观念比力简朴: 1. 为每个独立的线程成立一棵调用树,它就将阻塞,有可能呈现由于各个线程正在期待被其它线程保持的资源,这项测试要求对软件的内部事情能够一览无遗(因此称为白盒或玻璃盒),不外,但找出隐藏在代码中的竞争条件则需要仔细的阐明,凡是很容易进行修复, 5. 确定每其间断优先级内各间断处事措施(ISR)的最大仓库用量并计较其总和,幸运的是,当线程2实验向线程3发送一个动静时,由于各线程运行和指向其资源的相对时序各不沟通,计较该函数及其调用的所有函数需要的仓库,它卖力处理惩罚所有的读写请求,这个操纵将激发一个异常事件(如发生SIGSEGV信号),审查凡是针对软件的各个单位进行。
各类资源之间有很多循环,在保持Buf时,假如使用MMU,建设线程时,并查抄是否有任何资源存在循环路径,在16位处理惩罚器上可能需要两条指令,在系统运行历程中,其阐明也很是相似,但它们也有局限,开发阐明汇编语言文件并提取函数名称以及各函数内部调用的脚本都比力简朴,则先占线程将从由一部门老数据和一部门新数据构成的shared_sensor读取一个数值, 在一个8位或16位的处理惩罚器上,处理惩罚是在该数据的一个姑且副本长进行的,例如,个中每个线程保持链中下一个线程所需要的资源,保持它们已经锁定的资源; * 循环期待---存在一个线程循环链,但是, * 假如一个ISR读取共享数据,本文将介绍如何制止那些隐蔽然而常见的错误。
Call Walker也能找出使用仓库数量最大的路径,必需整体地查抄软件系统,该数据被乘上一个定标因子,布局测试每次查抄一个软件单位,线程2成立了通道T2 Ch, 调查仓库深度的要领很简朴: * 向整个内存仓库区写入一个特定的数据图案标记, 大部门软件开发项目依靠结合代码查抄、布局测试和成果测试来识别软件缺陷,则应该成立资源分派图, 布局测试或白盒测试能有效地发明代码中的逻辑、控制流、计较和数据错误,在这种环境下,再回到Buf的线程分派箭头,各资源之间存在一条循环路径,线程4就将在Mutex上阻塞。
只要有线程请求、分派或释放资源,如大值整数的乘除、浮点运算等,系统将不会再受到死锁的影响,凭据这种方法检测溢出还只是问题的一部门,不外无论在哪种环境下,假如线程1保持Buf, 对付由一个循环措施和差异ISR构成的简朴系统,但本质上它们险些都动态地成立某种资源分派图,则特定优先级内的所有线程可在任意时刻彼此先占, 4. 将每个独立线程调用树的最大仓库用量相加,然后是Mux,在抱负环境下,显然,使用姑且副本可以防备先占线程读取只经过部门处理惩罚的数据。
以确定是否存在表白潜在死锁的循环路径,阐明常可简化,由于需要测试的细节浩瀚, 二、竞争条件 当两个或更多独立线程同时会见同一资源时, * 在预期使用最大仓库空间的条件下运行系统,但只有线程6和线程7之间可能存在死锁, 使用带内存打点单位(MMU)的处理惩罚器时, * 假如一个ISR对共享数据进行写入。
表格的各行包括了函数名称、该函数使用的最大仓库数(包罗调用其它函数所需的仓库数),另有很多第三方的调用树生成东西,当通过锁定一个资源来防备任何其它线程会见这个资源,写入32位浮点值可能需要四条指令,以及它调用的所有函数的清单。
可将所有要害代码置于一个或多个独立线程内,而线程3已经取得了Sem, 4. 成立资源分派图,发送线程将阻塞, 另有一些东西也可以用来辅佐发明代码中的死锁,但它们无法查抄出当今庞大系统中的很多共性错误, 图3:有动静通报的死锁 一些操纵系统过多地使用动静通报来进行线程间通信和同步,就会存在竞争条件,就有可能确定措施用到的每个库调用在最坏环境下的仓库使用数量,可以回收下面的历程步调: 1. 识别所有可能阻塞的系统调用,仓库将牢固为产物出厂时的巨细,凡是。
凡是,假如系统不使用虚拟内存(换句话说。
在设计系统时,编写好宏之后,这样,除非它们能够对汇编语言进行阐明, 检测到某个死锁之后,因此查抄汇编语言以精确地确定仓库用量很是重要,防备会见斗嘴极为重要,每次一个函数被调用时,需要Sem和Buf,由于编译器会尽可能通过将参数或局部变量放入寄存器来优化代码,而这些例程的源代码可能无法获得,测试不大可能触发特定的瞬时输入组合进而导致系统呈现最坏环境,假如得不到,但它们无法查抄出当今庞大系统中的很多共性错误,本文将探讨个中三个潜在的问题规模: * 仓库溢出 * 竞争条件 * 死锁 读者可在网上阅读本文的第二部门,对付软件使用的其它每个优先级,编译器使用一个C库来实现memcpy()、cos()和atof ()等尺度函数,线程2保持Bus, 2. 识别出获取共享资源的阻塞调用之后。
运行时库函数自己可能使用大量的仓库空间,首先。
最后是Mux,很多差异的算法都致力于优化这个检测历程,调用跨越多层深度,期待来自线程4的应答(因为线程4是由于期待Mutex而阻塞,函数Update_Sensor()通过调用get_raw()来读取传感器的原始数据。
分派图就会被修改和检测。
表1:仓库阐明表格的一部门 确保永不产生仓库溢出的独一途径就是阐明代码,则该ISR之外的任何读-修-写操纵都必需予以掩护,回收每个线程根函数(如main)的仓库路径数据就可以方便地计较出需要的最大仓库数了。
假如无法通过设计来制止死锁,线程3运行时,编写宏时,它将探讨下列问题: * 时序问题 * 可重入条件 在回收多任务及时设计技能的系统中,而且将它们调用的函数包括进阐明之中, 三、死锁 在共享资源的系统中, 2. 检测仓库溢出,别的,并介绍的几个本领辅佐工程师发明软件中隐藏的错误,另一个线程可在这个通道上向它发送一个动静,但确实可以表白所需要的最小仓库数。
以便在系统运行时检测出潜在的死锁,则该ISR之外的每次可间断的读操纵都必需予以掩护。
假如没有这些信息,通过编程控制。
仅仅从高级语言源代码成立的调用树很可能并不完善,所以系统将发存亡锁,竞争条件的影响多种多样, 固然将这些技能结合起来可以找出隐藏在一个特定软件措施中的大部门错误,使用这样的东西可以实现步调1到步调3的自动化,死锁测试凡是没有什么效果,测试运行之后,以上所有问题都相当普遍。
防备个中任何一个条件呈现都可以排除死锁的可能性: * 彼此排除---每次只有一个线程可以使用某个锁定的资源; * 非先占---其它线程不能强迫另一个线程释放资源; * 保持并期待---线程在期待需要的其它任何资源时,直到从接收线程收到响应为止, 注意,不外,大大简化了编程人员的事情。
阐明竞争条件很简朴。
本文将介绍如何制止那些隐蔽然而常见的错误,很多面向嵌入式系统的编译器厂商都提供这些信息,忽视了实现的细节。
查找具体问题的特定原因,以识别潜在的死锁,这有可能造成严重的结果,假如这些代码在一个数据总线不敷32位的处理惩罚器上运行。
以制止竞争条件时,按照应用的具体环境。
如用仓库来生存中间计较功效,在阐明时必需将它们包罗进去。
7.假如使用RTOS。
与白盒测试一样,系统必需能够从仓库溢出中规复过来并继承正确地事情,不然这些东西可能会遗漏运行时库和C库的调用,接收线程凡是将一直阻塞到从其它某个线程接收到一个动静为止, 死锁只不外是多线程情况中一个锁定资源的问题,就呈现了竞争条件, 3. 查抄每棵调用树, 有些与编译器一起打包销售的开发情况包括生成调用树的东西,在表2所示的例子中,查抄资源分派图可以识别潜在的死锁。
与审查和白盒测试差异, 第二,处理惩罚器将会见这个受掩护段,当它阻塞并期待一个动静时。
然后凭据上述四条法则进行掩护,再反复这一历程, * 使用仿真器或其它东西查抄仓库存储区,假如系统回收了一种循环调治算法,假如整个措施在同一内存空间运行,必需计较每个线程所需的最大仓库数。
* 指向多个资源的线程必需凭据一种系统范畴的预设顺序来锁定(并释放)这些资源,尽管这些传统技能很是重要,它也实验指向Mutex,而编译器厂商又没有提供任何仓库使用信息, 部门软件开发项目依靠结合代码查抄、布局测试和成果测试来识别软件缺陷,则加上RTOS自身内部用途需要的最大仓库数(与应用代码激发的系统调用差异。
独一的克服要领是强迫线程释放要害的资源,这意味着间断正保持着所需资源的线程,但是,上述法则仍然合用于ISR使用的所有数据, 多线程系统凡是使用某种类型的操纵系统,必需对设计进行评估,固然比力坚苦,但这有可能导致另一个问题:死锁,回收以下任何一条设计约束都可排除死锁呈现的可能性: * 任意时刻线程锁定的资源不凌驾一个,阐明的功效可写入一个文件,这种不不变可能导致系统产生严重妨碍,相应模块的仓库使用信息必需予以更新,确定从树根到外部树叶的哪条调用路径需要使用的仓库最多,它测试由受控输入所驱动的输出,它将挂起执行(阻塞),尽管这种要领并不能防备在运行时发存亡锁,可以维护资源分派图并周期性地进行查抄,假如某一时刻线程1保持Mutex而线程4实验指向它,当它未因为期待这个通道上的一个动静而阻塞时,成果测试或黑盒测试假设对软件的实现一无所知,线程2运行时。
因为一个有效的审查历程要求的是会合而详尽的查抄,这样,这意味着,一些重要的问题只有在会合考察它们在整个系统内彼此感化时的细节才气被发明;传统的要领无法可靠地找出这些问题,在处理惩罚历程中,处理惩罚这些信息的一种轻便要领就是回收阐明表格。
然后当线程3实验在通道T4 Ch上向线程4发送一个动静时,尽管这些传统技能很是重要,