采用双内核机制基于uClinux的实时操作系统分析与实现
引言:本文提出了一种基于uClinux的实时操作系统,在对于资源要求苛刻而应用场合多变的嵌入式领域很有优势。该系统采用了双内核机制、借助实时硬件抽象层(RTHAL)概念、利用模块动态加载,对普通uClinux进行了实时性改进,实验表明完全满足实时系统的时限约束。
%A
%A
%A [ 相关贴图 ]
%A
%A
%A 图1:嵌入式实时uClinux的体系结构图。
%A
%A
%A [ 相关贴图 ]
%A
%A
%A 图3:普通uClinux的中断处理示意图。
%A
%A
%A
%A [ 相关贴图 ]
%A
%A
%A
%A 图5:SamSung4510b时钟示意图。
%A
%A 基于uClinux的实时方案分析
%A
%A 1.uClinux实时性缺陷
%A
%A uClinux虽然符合POSIX1003.1b关于实时扩展部分的标准,例如支持SCHED_FIFO和SCHED_RR实时调度策略、实时信号等实时功能,但由于其最初的设计目标为通用分时操作系统,因此在实时性支持方面,uClinux仍存在如下缺陷:
%A
%A a.非抢占式内核。uClinux有用户态和核心态两种模式,当进程运行在用户态时,可以被优先级更高的进程抢占;在内核中,一个进程可以通过schedule()函数自愿地启动一次调度。除此之外,非自愿的强制调度只能发生在每次从系统调用返回前,或每次从中断或异常处理返回到用户空间前。
%A
%A B.公平的调度算法。普通uClinux作为一个分时系统,其调度算法的目标是提供一种公平的调度机制,平衡系统响应时间和吞吐量,这与实时应用要求的低延迟和高度的可预测性相矛盾。实时操作系统必须保证目前运行的任务的优先级是可运行任务中最高的。
%A
%A C.频繁地关中断操作。uClinux为了保证核心数据的完整性,在对关键数据结构进行修改前,通常采用"关中断"的方式。而非周期实时任务大多是由中断作出响应,周期性实时任务也需要调度模块来调度运行,而调度模块的执行也要由时钟中断触发。所以,频繁的关中断会导致实时任务不能被及时调度执行。
%A
%A D.时钟粒度粗糙。时钟管理是操作系统的脉搏,是进程调度的重要依据。普通uClinux的时钟粒度被设置为10ms,而实时应用一般都需要微秒级的响应精度。
%A
%A 2. uClinux实时解决方案
%A
%A uClinux支持硬实时性的策略有以下两种:
%A
%A a. 直接修改内核法
%A
%A 将内核中的进程调度、中断处理、时钟等部分遵循POSIX标准进行改写,在源代码级的基础上使uClinux变成一个实时操作系统。这种策略虽然可以获得高的执行效率,但实现难度大、周期比较长,而且对原有内核太强的依赖性使得升级工作繁重而不方便。
%A
%A b. 双内核方法
%A
%A 在同一硬件平台上采用了两个相互配合、共同工作的系统内核,一个内核提供精确的实时多任务管理,另一个内核提供复杂的非实时通用功能。由于uClinux支持内核模块动态加载,因此实时内核可在需要时以模块的形式载入。双内核机制避免了大规模结构改造,以较小的代价提供了强实时性,新系统可使用几乎所有常规uClinux操作系统提供的功能。
%A
%A 本文提出的嵌入式实时操作系统采用双内核的设计思想,在普通uClinux基础上,通过增加一个实时内核实现了调度的可抢占性,同时在系统中实现了硬件抽象层RTHAL,避免了频繁关中断所导致的实时任务不能被及时调度执行的缺陷。最后,对系统时钟进行了改进,满足了实时应用微秒级的响应精度。
%A
%A 基于uClinux的实时操作系统设计
%A
%A 1. 抢占式实时内核
%A
%A 实时内核完全掌握了硬件层,而把非实时内核作为一个优先级最低的普通任务运行于自己之上。实时内核采用了抢占式调度算法,非实时内核也通过RTHAL获得实时内核所用的替代函数,这就为应用双内核机制实现可抢占式内核奠定了基础。
%A
%A 实时内核将各种功能以模块形式实现,在系统运行时可以方便地加载、卸载,从而大大减少核心代码的规模,节省内核空间并方便进行动态配置。图1是双内核结构的嵌入式实时uClinux的体系结构图。可以看出,在RTHAL架构下实时内核主要由中断分发器和实时调度器构成,这是实时内核最基本的功能。同时还将实时SHM、实时FIFO、RTCOM和SFLIB设计成模块的形式,可以灵活地根据应用需求进行加载。
%A
%A 实时SHM和实时FIFO是实时内核任务和非实时内核任务之间的通信桥梁。SFLIB是浮点运算软件模拟的功能模块,为了解决处理器不支持内核浮点运算而设计的。RTCOM则可以提供实时串口通信功能。
%A
%A
%A
%A
%A
%A 嵌入式Linux以代码开放、价格低廉、功能强大又易于移植的特性正在被广泛应用,为嵌入式操作系统提供了一个极具吸引力的选择。uClinux是专门针对无存储器管理单元(MMU)处理器设计的嵌入式Linux,非常适合中低端嵌入式系统的需求,在工业控制领域有着广阔的应用前景。
%A
%A 但许多实际应用要求对外部事件在限定的时间内做出反应,而普通uClinux并不是一种实时操作系统,所以本文提出了一种基于uClinux的实时性解决方案,经测试可以严格满足实时应用的时限约束,有良好的应用价值。
%A
%A
%A
%A [ 相关贴图 ]
%A
%A 图2:实时调度处理流程图。
%A
%A
%A
%A 抢占式内核提供多种实时调度策略,包括FIFO、RR、RM、EDF算法,同时还允许使用者根据应用需要编写自己的调度算法。任务调度的时机有两种,一种是主动调度,即在程序中主动调用rt_schedule()函数来让出运行权;另一种是被动调度,即在时钟中断处理函数rt_timer_handler()中进行调度。以上两个函数的算法基本相同,故仅给出rt_schedule()的流程图(图2)。
%A
%A 2.RTHAL
%A
%A 从Linux2.1版开始提出了实时硬件抽象层(RTHAL)的概念,而uClinux本身并不具有RTHAL。这里借鉴RTHAL的思想,对uClinux核心进行改动,将其与中断控制器隔离,核心中的所有中断操作指令都被替换成相应的宏。可以简单地理解为,这时的开中断、关中断指令实际上仅仅变更一个中断状态标志的值,并不真正改变中断状态。通过RTHAL这一机制,避免了频繁关中断所导致的实时任务不能被及时调度执行的缺陷。
%A
%A 1.RTHAL数据结构
%A
%A 将所有需要的内部数据及函数的指针集成为一个结构体RTHAL,这样就能方便地捕获全部与实时应用紧密相关的内核函数。当需要响应硬实时事件时,实时内核可以动态地把这些函数切换到相应的软件模拟函数上。
%A
%A 2.RTHAL作用
%A
%A 为了更好地说明RTHAL的作用,下面详细说明实时模块加载前后内核所发生的变化。
%A
%A A.实时模块加载前
%A
%A 首先解释一下硬件支撑层(HSL)的概念:在linux代码树中HSL一般是由汇编语言编写的与底层硬件密切相关的部分,它的作用是在中断发生时保存现场并跳转到内核中相应的中断处理函数入口,在中断返回时恢复现场,同时还起着进程切换的作用。
%A
%A 如图3所示,改动前uClinux内核可以通过开/关中断操作直接打开或关闭所有中断,也可以通过屏蔽/解屏蔽操作关闭和打开特定的中断。由于中断处理、系统调用和异常处理需要经常关闭中断,频繁的关中断会导致实时任务不能被及时调度执行,从而使系统响应时间增长,实时性降低。
%A
%A 这时uClinux直接与硬件层打交道,例如关中断指令cli的宏定义为:
%A
%A #define __cli() __asm__ __volatile__("cli": : :"memory")
%A
%A 即uClinux内核直接通过cli汇编指令控制硬件。
%A
%A B.实时内核加载后
%A
%A 当系统实现了RTHAL后,如图4所示,uClinux的开/关中断操作被分别指向RTHAL的disint( )和enint( )函数。disint( )指向实时模块的_linux _cli( )函数,作用是设置中断标志位为关中断状态;enint( )函数指向实时模块的_linux_sti( )函数,作用是设置中断标志位为开中断状态,并处理挂起的uClinux中断请求;而屏蔽/解屏蔽操作被分别指向实时模块的linux_irq_mask( )函数和linux_irq_unmask()函数。
%A
%A 当中断通过HSL调用RTHAL中的do_IRQ( )函数,这个函数指向实时模块的dispatch_irq( )函数。其作用是判断当前中断是否是实时中断,如果是实时中断,则实时模块处理这个中断;如果是非实时的,则将这个中断挂到uClinux中断请求队列中,由uClinux内核的来处理非实时中断。
%A
%A 例如,linux_cli()函数在加载实时内核后被改写为:
%A
%A static void linux_cli(void)
%A
%A {
%A
%A processor[hard_cpu_id()].intr_flag = 0;
%A
%A }
%A
%A 即当uClinux要关中断时,实时模块的处理只是仅仅设置了中断标志位,并没有真正的去关硬件中断。由此,实时模块实现了对硬件层的接管,而把非实时内核作为一个优先级最低的普通任务运行,这样就可以充分保证实时中断的及时响应,从而保证了系统的实时性。
%A
%A 3. 细粒度时钟的实现
%A
%A 对于时钟机制的改造,可以通过提高系统时钟精度来增强系统的实时性,特别是对外部中断的响应。在系统中引入两种定时器模式:Periodic(周期性)和Oneshot(一次性)。
%A
%A A.Periodic模式
%A
%A 对于周期性实时任务应用这种模式,只需要在初始化时对定时器进行设置,保证了处理效率。
%A
%A B.Oneshot模式
%A
%A 对于非周期实时任务应用这种模式。在任何时刻,时钟的下一次中断间隔由所有定时器中到期最早的一个来决定。一旦定时器到期,内核便能够立刻响应,因此内核的响应开销只由中断服务的时间所决定,大约只有几个微秒。
%A
%A [ 相关贴图 ]
%A
%A 图4:实时模块加载后中断处理示意图。
%A
%A
%A
%A 在i386体系结构中,有TSC(时间标签计数器)计数器,这个计数器是64位的寄存器,可以精确到1/主频。在s3c4510b处理器上没有这个寄存器,但精确计时又是必要的,为了解决这一问题,可以采用计时器2(timer1)来模拟TSC的功能。每来一个时钟脉冲,timer1的TCNT1寄存器减1,减到零后产生时钟中断,再从TDATA1中读TCNT1的值,往复运行。由于TCNT1寄存器仅32位,s3c4510b的主频为50MHz,置TDATA的值为0xffffffff时,仅运行8分多钟就溢出了。于是设置一个32位全局变量tsc.hltsc,timer1每次中断到来时将这个全局变量加1,为了使系统更精确,必须将timer1中断设置为最高优先级,这样就可以模拟64位的TSC寄存器。
%A
%A 实验结果及结论
%A
%A 该系统平台为:以ARM7TDMI为核心的Samsung4510B处理器、2M闪存和16M RAM,处理器运行频率为50MHz。经验证,未加载实时内核前,中断延迟虽大多数在30us(1500个时钟脉冲@50MHz)以下,但是并不十分稳定,有时超过200us(10000时钟脉冲@50MHz),最高的甚至达到430us(21525个时钟脉冲@50MHz)。实时系统以最大中断延迟作为衡量指标,因此这对于实时应用来讲是不能忍受的。加载了实时模块后,中断延迟时间大约为10us~30us,而且结果十分稳定,完全满足实时系统的相关要求。
%A
%A 本文小结
%A
%A 本文提出的嵌入式实时操作系统采用双内核机制、实现了RTHAL的概念,使得直接修改内核的部分减至最小。同时实时内核充分利用模块动态加载机制,在系统运行时方便地加添加、删除各个功能模块,从而大大减少核心代码的规模、节省内核空间、方便进行动态配置,对于资源要求苛刻而应用场合多变的嵌入式领域很有优势。
%A
%A 参考文献:
%A
%A [1] Anon. Embedded Linux gains high-availability framework [J]. Electronic Design, 2001,49(21):36.
%A
%A [2] Bollinger. Survey of Linux applications [J]. IEEE Software,1999,16(1): 72~79.
%A
%A [3] Ludwick, Scott. Linux for data acquisition [J]. EE: Evaluation Engineering, 2002,41(2): 12~14.
%A
%A [4] 王济勇,林涛.一种嵌入式系统实时性能分析的融合机制[J].计算机科学,2004,31(1):157~161.
%A
%A [5] 屈浩然,李凤华.一种嵌入式实时Linux系统设计与实现[J].计算机工程与应用,2004:119~120.
%A
%A [6] Barabanov M,Yodaiken V. Introducing real-time Linux. Linux Journal[J], 1997, (34):19~23.
%A
%A [7] Lui S, Rajkumar R, Lehoczky J. Priority inheritance protocols: An approach to real-time synchronization. IEEE Transactions on Computers[J], 1990,39(9):1175~1185.
%A
%A 作者:崔珂, EMAIL: ck_summersun@163.com
%A
%A%A
%A
*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。