文献标识码: A
DOI:10.16157/j.issn.0258-7998.172506
中文引用格式: 李亚爽,姬希娜,王振,等. Nucleus PLUS自旋锁测试方法研究[J].电子技术应用,2018,44(1):37-40.
英文引用格式: Li Yashuang,Ji Xina,Wang Zhen,et al. Study on spin lock test in Nucleus PLUS[J]. Application of Electronic Technique,2018,44(1):37-40.
0 引言
Nucleus PLUS是美国源代码操作系统商品ATI公司推出的新一代抢先式多任务嵌入式操作系统,具有高移植性,并能够支持大多数类型的处理器[1]。对称多处理器是指一个计算机上有多个处理器,各处理器共享内存子系统以及总线结构[2]。与传统操作系统不同的是,嵌入式操作系统对系统响应时间的实时性要求非常高。在对称多处理器环境下,同步、互斥、中断都非常重要,为解决资源的竞争、共享问题,提出了典型自旋锁等机制来保证同步问题。
在电力设备产品中使用的操作系统大多是Nucleus嵌入式操作系统,在产品运行过程中出现过产品死锁现象,经过问题查找发现是自旋锁的使用不当造成的死锁。因此针对自旋锁的使用展开了重点测试。
通过详细分析自旋锁代码及实现机制,对自旋锁如何进行测试提供了详细的测试思路及测试方法。
1 Nucleus PLUS内核简介
Nucleus PLUS内核是操作系统的核心,主要负责管理实时任务之间的竞争运行、系统内存的分配以及如何回收等,同时对外部事件必须保持快速响应,以实现其实时性,保证系统的性能和稳定性。Nucleus PLUS的系统结构如图1所示。
线程控制部件用来管理实时任务和高级中断服务的执行,它是Nucleus嵌入式实时操作系统最核心的部分。在系统任务控制方面,根据优先级及时间片共享处理器。通过任务之间的同步和互斥来选择不同的通信机制。内存机制采用了两种方法:动态内存和分区内存。Nucleus PLUS将这些组件称为软件组件,并提供了很多系统调用方法。
2 Nucleus PLUS自旋锁机制
2.1 自旋锁简介
对于单处理器来说,防止中断处理中的并发可简单采用关闭中断的方式,即在标志寄存器中关闭/打开中断标志位,不需要自旋锁。而对于多处理器环境下,为了解决同一时刻多任务同时访问内核和其他资源,保证内核、进程及其他资源有秩序、正确地执行,引入新的一种锁的机制,即“自旋锁”。自旋锁是专为防止多处理器并发而引入的一种锁,它在内核中大量应用于中断处理,以及解决多处理器环境下不同处理器之间存在的同步与互斥问题。
2.2 自旋锁与信号量对比
自旋锁和信号量都是解决互斥问题的基本手段,属于不同层次的互斥手段。自旋锁与信号量相似,都用于互斥访问临界资源,但是自旋锁不会引起调用者睡眠,不需要进入等待队列。如果自旋锁已经被别的任务所持有,调用者就一直循环检测直至自旋锁的持有者释放该自旋锁,节省了任务从睡眠状态到唤醒之间内核会产生的消耗,在加锁时间短暂的情况下会大大提高处理器的使用效率。表1列出了两者之间的不同点。
自旋锁在使用中,无论自旋锁还是信号量,任何时刻最多只能有一个持有者。自旋锁提供的是一种低开销加锁选择,避免了信号量中任务阻塞或唤醒时任务情景切换而产生的开销,更适用于中断服务处理和任务之间共享同一资源的情况。
3 Nucleus PLUS自旋锁测试
3.1 测试环境
测试环境由PC、仿真器、目标系统组成。测试环境构成如图2所示。
编程环境采用Sourcery CodeBench集成开发环境,将编译好的目标文件通过TFTP方式下载到目标机上。PC通过网口或者串口与仿真器连接,实现与目标板卡之间的通信及监测数据。仿真器与目标机通过JTAG接口连接,目标板卡采用双核ARM9处理器。
测试驱动在整个测试过程中很关键,经过对自旋锁机制深刻研究,编写出用于控制测试用例执行的驱动程序,如图3所示。
驱动程序主要包含:测试用例数据结构设计,如何调用自旋锁相关代码的接口,返回自旋锁相关函数的返回值,各种全局变量信息以及输出信息数据结构的打印。测试用例数据结构设计的好坏将直接影响测试用例的执行效率。输出的数据结构信息可以在用例执行过程中实时观察数据变化信息,帮助记录任务执行某个运行节点下的内核对象状态,便于监测测试结果的正确性,从而快速地对问题进行准确定位及回归测试。
3.2 测试思路
在Nucleus PLUS中,自旋锁是一个互斥设备,只有加锁和解锁两个状态。任务或中断处理程序请求自旋锁时,如果该锁为解锁状态,则尝试将该自旋锁置为加锁状态,如果加锁成功,代码继续进入临界区。如果该锁为加锁状态,则代码进入忙循环,此状态不是休眠,并重复检查这个锁,直到该锁可用为止。即使多个任务在某时间内自旋,也只有一个任务能够获取该锁[3]。
在设计测试用例时,主要就是如何设计任务和中断之间在不同优先级、不同时间段申请和释放自旋锁。下面设计了几种综合的用例场景,要注意任务、中断在不同的执行顺序下结果是不同的。
(1)用例场景1:当多任务同时申请自旋锁,无中断任务申请自旋锁情况下,每个任务执行顺序如图4所示。这种情况下在任务1申请自旋锁成功后可重复申请此自旋锁,也只有在任务1重复释放此自旋锁后,其他任务才可以申请自旋锁成功。
(2)用例场景2:当任务采用试探性try方式申请自旋锁,并且此自旋锁处于加锁状态,那么任务不再忙等。执行过程如图5所示。
当任务采用可被中断方式申请自旋锁时,根据任务和中断是否在同一个处理器上,所产生的结果是不同的。
(3)用例场景3:当任务和中断在不同CPU上,采用可被中断方式申请自旋锁时,中断申请自旋锁成功。如图6所示。
(4)用例场景4:当任务和中断在同一CPU上,采用可被中断方式申请自旋锁时,由于任务无法释放自旋锁,中断一直忙等,最终产生死锁现象。如图7所示。
当任务采用“关中断”方式申请自旋锁时,就会在申请自旋锁前先把中断关闭,不会产生死锁现象。
对自旋锁的测试可以按照这种用例设计场景的方式,将自旋锁的所有函数的正常、异常及边界功能测试完整。
3.3 测试用例设计
整个测试过程采用单元测试、集成测试相结合的方法进行,采用最常用的等价类划分、边界值等方法对自旋锁进行白盒测试。随着自旋锁的创建、申请、释放、删除等操作的发生,自旋锁的状态也在不断变化。也可采用有限状态机对自旋锁建立模型,提取路径设计用例,充分地对自旋锁的实现机制进行测试。同时也要对接口的一些异常输入或者边界环境条件下能保持正常工作的情况进行测试,从而保证对接口能够进行全面化的测试。
在设计测试用例过程中,首先要设计正常功能的测试用例,然后设计异常测试用例,观察函数内部是否进行了异常判断,最后集成几个接口配合进行整体功能测试,检查接口之间的相互操作是否正确。下面列出对自旋锁相关接口设计的测试用例。
(1)自旋锁创建及删除接口。
正常创建自旋锁,创建一个已经创建的自旋锁,异常创建。
(2)自旋锁申请及释放接口。
分多种用例场景进行测试,主要考虑表2所示几个方面。
(3)自旋锁“关中断”方式申请、释放与自旋锁的申请、释放功能类似,测试过程中除了要把功能相似的用例执行一遍,还要把功能不同点重点测试。不同之处表现在以下几点:
①在获取锁之前关中断,释放锁后将中断状态恢复至原来状态。
②不支持同一任务多次加锁同一个锁。
③线程在被自旋锁保护的临界区不会被打断,避免了死锁。
(4)试探性自旋锁的申请、释放与自旋锁不同的是,申请加锁时如果锁的状态时是“加锁”,则不再忙等。
(5)“关中断”试探性自旋锁的申请、释放与试探性自旋锁不同的是,申请锁时会保存中断状态,如果请求失败,会恢复原来的中断状态。
(6)返回自旋锁创建个数函数、自旋锁信息函数、返回自旋锁指针函数:
①创建多个自旋锁,查看返回自旋锁个数、自旋锁的信息及自旋锁指针的正确性。
②删除某个自旋锁后,查看返回自旋锁个数、自旋锁的信息及自旋锁指针的正确性。
③创建0个自旋锁、无效自旋锁等异常测试用例设计。
3.4 自旋锁测试效果
使用上述测试策略对自旋锁所有接口函数进行了白盒测试,测试效果很显著,不仅对自旋锁的基本功能进行了验证,还对异常、死锁情况进行分析,实现了功能、代码语句全覆盖。
测试过程中也发现一些问题,以及某些接口在使用过程需要注意的事项,避免因使用不当产生死锁等问题,造成应用平台功能不可用。下面列出了几条自旋锁使用中的注意事项。
(1)自旋锁申请、释放函数接口的使用是不安全的,容易导致死锁[3]。由于这个接口在使用时是不关闭中断,使用时应注意以下几点:使用自旋锁进行同步的多个任务不要绑定到一个处理器上,临界区尽可能小,临界区不要睡眠,任务的优先级不宜有差别。
(2)使用关中断的自旋锁在释放时,传入的中断状态应设置为申请自旋锁之前的中断状态,而不应简单通过传入0值去开中断。否则在嵌套使用自旋锁时会导致死锁。申请自旋锁时,关中断仅仅关闭了本处理器的中断,另一个处理器上的中断仍然产生。
(3)试探性方式申请自旋锁时,应根据返回值来做相应的处理。当返回值为此自旋锁已被占用时,不能访问被保护的临界资源。
4 结论
本文重点研究了在Nucleus PLUS对称多处理机嵌入式操作系统的环境下,运用多种测试方法设计全面测试用例,对自旋锁组件进行白盒测试。在测试过程中发现了在何种情况下自旋锁会发生死锁现象,同时详细介绍了自旋锁组件在使用过程中的注意事项。整体测试效果良好,对操作系统其他组件的测试有着较高的借鉴价值。
参考文献
[1] 魏振华.嵌入式实时操作系统Nucleus中线程控制部件的实现方法[J].计算机应用研究,2003(4):97-100.
[2] 彭正文.基于SMP的Linux内核自旋锁分析[J].江西教育学院学报(综合),2005,26(3):23-28.
[3] 张文盛.一种Linux内核自旋锁死锁监测机制的设计与实现[J].合肥学院学报,2012,22(2):31-35.
[4] 徐宇柘.Nucleus实时操作系统在继电保护系统中的实时性研究[J].电脑知识与技术,2007(13):3-5.
[5] 吴雨俊.实时操作系统Nucleus的中断处理机制研究[J].福建电脑,2012(3):95-96.
[6] 王继刚.嵌入式操作系统异常处理框架设计与实现[J].电子技术应用,2017,43(5):60-63,66.
[7] 李建军.国产化嵌入式操作系统软件测试方法研究[J].微型机与应用,2016(24):22-24.