本帖最后由 杨为民 于 2024-3-1 19:08 编辑
每次移植,移植者都要精心构造范例,不断进行测试研究,不但要保证移植的正确性,有时甚至要补上被移植程序中原来就存在的漏洞。 本文通过对原uC/OS-II临界区保护不配对漏洞的研究,介绍临界区保护的方法和效果。
一、临界区保护不配对的影响 (1)uC/OS-II测试程序正常运行时,通过逻辑分析仪监测的效果见下图: 关于图的含义见笔者系列篇的前文“STC单片机uC/OS-II移植记(5):纠正原移植程序中将“RETI”与“RET”混用产生的错误”
(2)uC/OS-II原程序中存在临界区保护不配对的错误,比如对于中断任务切换程序“OSIntExit”,见下图: 其中第672行与第689行是临界区保护配对语句。如果单片机中断有嵌套,第676行条件不成立,第689行得以执行,临界区保护是配对的。但是如果,第676行条件成立,程序在685行调用后不再返回,第689行得不到执行,临界区保护是不配对的。 不过原始被移植程序是在PC机DOS环境下运行的,8086特殊的中断机制掩盖了这个不配对的错误。
(3)在移植程序中,移植者已经在“OSIntCtxSw”函数中对这个错误进行了改正,见下图: 其中第384行的EA=1就是与进入临界区保护EA=0配对的退出临界区保护语句。
(4)如果注释掉该行,就可以看到中断任务切换时临界区保护不配对的运行情况,见下图: 上图中第0通道是定时器3的10KHz中断信号,第1通道是定时器0系统中断的50Hz信号,第2通道是任务A的信号,每一个上下沿都对应任务A获得一次执行权。 上图中第0和1通道的缺口说明在缺口期间中断被临界区进入是的EA=0停止了,同时由系统中断驱动的任务A也被停止了。从图中也可以看出中断任务切换的临界区保护不配套产生的异常是不规律的。 虽然中断停止了,但是任务B和任务C之间的非中断任务切换仍然在进行,同时非中断任务切换的临界区保护是配对的,因此每次任务B和任务C切换时,中断都会被激活,所以图中大部分时间中断和任务A都是正常运行的。
(5)如果继续把非中断任务切换的临界区退出语句EA=1也注释掉,运行效果见下图: 从图中可以看到每次“OSIntCtxSw()”和“OSCtxSw”函数调用时中断都会被停止,而碰到其他系统函数中的临界区保护退出语句EA=1时,中断再次恢复。 由于这些系统函数只在任务B和任务C切换时发生,因此中断、任务A都只能在任务B和C切换时发生,它们的发生周期也变得任务B和任务C的切换同步了。 二、临界区保护方法的影响
(6)uC/OS-II提供了三种临界区保护方法,移植者也移植了过来,见下图: 第一种方法是直接关开总中断,第二种是干脆不保护,第三种是利用局部变量保存和恢复中断状态。
(7)上一节临界区保护不配对产生的异常是由于进入临界区关闭总中断引起的,下面是采用第二种方法进入临界区不做任何保护的运行效果: 1)上图左部8路通道同时的三个负脉冲是开机的LOGO。 2)由于没有任何关闭中断的语句,所以第0通道和第1通道中断一直没有停。 3)由于没有临界区保护,依赖系统中断进行的任务A(第2通道)首先停止运行了。然后任务C也停止了,只剩任务B在运行。 4)笔者认为产生这个现象的原因是任务调度程序在对临界区资源TCB处理时产生了嵌套处理,嵌套处理退出时的链表状态没有恢复产生的,使得任务A和任务C永远处于未就绪状态。
(8)采用第三种保护方法的效果见下图: 由图可见,任务B和任务C从一开始就得不到执行,原因难以追查。 三、结论
对于将uC/OS-II移植到STC8H裸机上,在原版提供的3种临界区保护方法中就只有一种最适合:方法一,直接关闭/打开总中断。
|