实时操作系统μC/OS-II最大优先级数扩展实现
2018-10-18俞佳敏王成群徐伟强
俞佳敏,王成群,徐伟强
(浙江理工大学 信息学院,浙江 杭州310018)
0 引言
μC/OS-II作为一个开源的嵌入式实时操作系统,包含任务管理与任务调度,具有小巧、实时性强、移植性好[1-4]、基于优先级的多任务可剥夺等优点[5]。在μC/OS-II系统运行过程中,任务管理函数通过中断操作,确保当前处于就绪状态的最高优先级任务最先运行,能够保证任务的实时性。近年来,μC/OS-II已在控制器[6]、数据采集[7]以及物联网[8]等诸多领域取得了诸多应用。
除实际应用之外,近年来也出现了诸多对μC/OS-II性能分析及提升的成果。Lv[9]等采用静态方法分析了μC/OS-II作为实时操作系统的最坏执行时间;朱怡安[10]等基于μC/OS-II提出了一种高可靠性的分区嵌入式操作系统内核,并通过实验进行了验证;隋宇晖[11]等提出了基于FPGA的硬件加速模块,将μC/OS-II中的调度器与定时器进行硬件化,有效地提高了系统的实时性;李岩[12]等提出基于μC/OS-II的混合调度算法对同级任务进行分组调度,并在FPGA中实现了该算法,有效降低了系统的开销并提高了关键任务的实时性;许璐璐[13]等提出采用增量链表的方式对任务延时进行高效管理。然而这些成果都是基于μC/OS-II最大64个优先级任务,随着μC/OS-II在工业等行业运用得越来越广泛,64个优先级任务已无法满足目前的需求。因此,本文研究了μC/OS-II的优先级扩展,实现了最大512个优先级任务。
1 μC/OS-II优先级机制
μC/OS-II给每一个任务分配一个惟一优先级,各优先级用一个正整数表示,优先级大小与该整数值成正比,即0为最大优先级,数值越大,优先级越小。μC/OS-II系统将在当前已处于就绪状态的任务中选择最高优先级的任务进行调度[14]。μC/OS-II最大支持64个任务优先级,即优先级范围为(0~63),其中统计任务以及空闲任务等系统任务占用最低的两个优先级,导致实际可用的任务优先级数减少。
μC/OS-II中定义了一个用于存放任务准备就绪标志的就绪表,就绪表为每次任务切换提供可确定性的时间保证。为了就绪表的正常使用,uCOS-II定义了变量OSRdyGrp和OSRdyTbl[7],以及表格优先级判断表OSUnMapTbl[256][15]。如图1所示,由于μC/OS-II最大支持64个优先级,就绪表由一个8乘8的表格组成,每个格子内为0或1,其中置1则代表该优先级下的任务处于就绪状态。实质上,就绪表被分成8行,即每一行分别为8个优先级,其中OSRdyGrp为8位正整数类型,若第n(0≤n≤7)行中有相应优先级的任务就绪,则该位置1,否则默认为0。
图1 μC/OS-II就绪表
数组OSRdyTbl[7]中每一个数均为8位正整数类型,OSRdyTbl[n](0≤n≤7)中的8位分别代表第n行中8个优先级任务就绪情况,若相对应位置的任务就绪,则置1,否则默认为0。μC/OS-II中优先级prio定义为一个8位正整数类型的变量,最大64个优先级时仅用到前6位,通过规律可以发现,低3位X可以代表该优先级在就绪表某行中位置,3位Y可以确定该优先级具体所在的行数。图2为μC/OS-II提供的优先级判断表OSUnMapTbl[256],优先级判断表由位掩码表转换而来。通过该表以及OSRdyGrp和OSRdyTbl[7]这两个变量,任务调度时能够快速找到目前处于就绪状态的优先级最高的任务。
图2 μC/OS-II优先级判断表
2 μC/OS-II优先级扩展
为了使μC/OS-II最大支持512个优先级任务,首先将变量prio扩展至16位正整数类型,并且采用16乘32的就绪表,即共16行,每行有32个优先级任务是否就绪的标志。相应地,OSRdyGrp扩展至16位正整数类型,OSRdyTbl[7]扩展至OSRdyTbl[15],且其中每个数扩展为32位正整数类型。但是在这种情况下,按照μC/OS-II所提供在优先级判断表基础上采用OSRdyGrp和OSRdyTbl[]计算目前就绪的最高优先级任务的算法不再适用。这是由于当前OSRdyTbl[]中个数为32位正整数类型,无法在16乘16的优先级判断表中进行匹配查找。一种解决该问题的方法是将优先级判断表扩展至16乘32的形式,但这样无疑会大大浪费宝贵的空间资源。为此,本文在扩展优先级过程中采用按位判断的方式实现在原来的优先级判断表中查找当前就绪的最高优先级任务。
具体地,对于16位的优先级变量,通过低5位可以确定该优先级任务在就绪表中某行中的具体位置X,通过第6~9位可以确定具体所在的行数Y。X,Y分别可以表示为:
Y= (prio >> 5) & 0xFF,
X= (prio & 0x1F);
为将计算得到X,Y更新至就绪表中,X,Y需转换为BitX,BitY:
BitX= 1 < BitY= 1 < 随后更新变量OSRdyGrp和OSRdyTbl[]: OSRdyGrp |= BitY, OSRdyTbl[OSTCBY] |=BitX。 通过上述步骤,已经能够成功将0~511之间的优先级变量分解并更新至就绪表中。此外,要实现扩展优先级的另一个重要难点在于如何通过OSRdyGrp和OSRdyTbl[]在μC/OS-II原有的优先级判断表中寻找当前就绪的最高优先级任务。对此,采用分类讨论的方法去寻找就绪的最高优先级任务。 首先,通过OSRdyGrp确定目前就绪的最高优先级任务所在行y,由于优先级判断表输入值在0x00~0xFF之间,所以分为以下2种情况计算y值: if ((OSRdyGrp & 0xFF) != 0) { y= OSUnMapTbl[OSRdyGrp & 0xFF];} else { y= OSUnMapTbl[(OSRdyGrp >> 8) & 0xFF] + 8; }。 然后需要计算的是第y行中最高优先级所在的位置x。在优先级任务扩展为512时,就绪表每行为32个不同优先级,即x取值范围为0~31,而μC/OS-II原有的优先级判断表输出的x最大值为7,显然无法满足此时的需求。因此采用逐级查找的方式确定x值,即首先判断OSRdyTbl[y]的低8位是否为0x00,若为0,则在该行的第0~7个位置对应已就绪的优先级任务不存在;若不为0x00,则代表在第0~7个位置上有对应已就绪的优先级任务,则直接用OSRdyTbl[y]的低8位放入优先级判断表中得到x。当OSRdyTbl[y]的低8位为0时,检查OSRdyTbl[y]的第9~16位是否为0x00,若是,则表示在该行的第8~15个位置对应已就绪的优先级任务不存在;反之则代表在第8~15个位置上有对应已就绪的优先级任务,则直接用OSRdyTbl[y]的低8位放入优先级判断表中,将判断表输出的值加8即为所求x的值,加上数值8是由于优先级判断表只输出该x在第8~15个位置中的相对位置,所以需要再加上未包含进去的数值8。同样地,依次类推,当OSRdyTbl[y]的第1~16位为0x0000时,依次计算第17~24位以及第25~32位的情况,若满足条件,则分别加上数值16或24以得到x。具体关键实现代码如下: ptbl = &OSRdyTbl[y]; if ((*ptbl & 0xFF) != 0) { x= OSUnMapTbl[(*ptbl & 0xFF)];} else{ if (((*ptbl >> 8) & 0xFF) != 0) { x= OSUnMapTbl[((*ptbl >> 8) & 0xFF)] + 8;} else { if (((*ptbl >> 16) & 0xFF) != 0){ x= OSUnMapTbl[((*ptbl >> 16) & 0xFF] +16;} else{ if (((*ptbl >> 24) & 0xFF) != 0){ x= OSUnMapTbl[((*ptbl >> 24) &0xFF)]+ 24;} } } } } 计算得到x,y便可以计算当前就绪的最高优先级任务的优先级数值OSPrioHighRdy,具体如下: OSPrioHighRdy = (y<< 5) +x; 至此,通过上述分类考虑的方法,成功实现了通过OSRdyGrp和OSRdyTbl[]在μC/OS-II原有的优先级判断表中找到当前就绪的最高优先级任务。同时实现了将μC/OS-II支持的最大优先级任务个数从64个提高到512个。 在实验验证中,分别创建优先级为2,14,48,128,255,300,356,454,508的任务,并且上述任务创建后即进入就绪状态。由于两个系统任务统计任务以及空闲任务分别占用了最低的510与511两个优先级,为了体现这一点,设置上述创建的任务分别执行一次就停止,并只运行一次统计任务,这样系统才会开始运行空闲任务。实验结果如图3所示,所有任务被成功创建,且按照优先级顺序从高往低运行,当系统无就绪的用户任务时,空闲任务将一直运行。图3中y与x值分别体现了该任务在就绪表中的位置。同时,统计任务以及空闲任务占据最低的两个优先级,符合实验的预期结果。 图3 实验结果 通过实验结果,验证了本文提出的优先级扩展方法成功地将μC/OS-II支持的最大优先级任务个数提高到了512。 通过研究μC/OS-II的优先级设置机制,在原优先级判断表的基础上,采用分类判断的方式将其支持的最大优先级数扩展到512个。通过实验验证,该方法成功地实现了最大优先级数的扩展,并未增加系统的空间。扩展μC/OS-II支持的最大优先级数能够使其被应用得更加广泛,进一步促进μC/OS-II的发展。3 实验验证及分析
4 结束语