通用的分时操作系统面向多用户的不同任务,意在追求系统整体运行的效率和资源的均衡利用,软件的执行在时间上要求并不严格。
实时操作系统不同于分时操作系统,它主要是对任务进行实时的处理,要求任务的运行具有可确定性和可预测性,提供即时响应和高可靠性。
由此导致通用分时系统和实时操作系统的内核在任务调度机制方面的不同。
下面主要以内核架构,系统的实时性,以及对系统的实时性改进三点为核心简要分析VxWorks和Linux内核实时性并予以对比。
Linux采用宏内核架构。宏内核(Monolithic kernel)又称单内核,其特征是操作系统内核的所有模块(包括进程调度、内存管理、文件系统、设备驱动等)均运行在内核态,具备直接操作硬件的能力,大部分设备驱动是以可加载模块的形式存在的,与内核其他模块解耦,使驱动开发与驱动加载更加方便、灵活。
Linux 是通用操作系统,不是实时操作系统,所以设计初是宏内核,本着公平的原则,虽然用户可以设计任务优先级,但操作系统会根据每个任务的运行时间,自动调整每个任务占用CPU的时间,这样使每个任务都能公平的占用CPU。
VxWorks实时操作系统核心的是高性能的微内核Wind。这个微内核支持所有的实时特征:快速任务切换、中断支持、抢占式和时间片轮转调度等。微内核设计减少了系统开销,从而保证了对外部事件的快速、确定的反应。
运行环境也提供了有效的任务间通信机制,允许独立的任务在实时系统中与其行动相协调。开发者在开发应用程序时可以使用多种方法:用于简单数据共享的共享内存、用于单CPU的多任务间信息交换的消息队列和管道、套接口、用于网络通信的远程过程调用、用于处理异常事件的信号等。为了控制关键的系统资源,提供了三种信号灯:二进制、计数、有优先级继承特性的互斥信号灯。
实时性主要体现在软件层次的保证在规定时间完成任务。而不是由硬件性能决定的速度快。实时进程不会影响自己在执行环境中的调度,反而是环境影响实时应用程序的调度。也就是说,实时进程通常和某个物理事件相关联,比如外围设备的中断。那么显然,影响实时的原因在于中断响应延时,在Linux系统中可细分为中断延时、中断处理、调度延时。一般来说,针对用户对超出时间限制所造成的影响的可接受程度,实时又可分为软实时和硬实时。
大多观点认为软实时意味着操作有时间限制,硬实时的特点是错过时限会造成严重结果,从内核层面分析来说,标准的Linux是一个软实时系统,VxWorks采用的Wind内核是一种强实时操作系统内核,但和当前其它成熟的操作系统一样,并不是“硬实时”的操作系统。
VxWorks 没有使用基于时间限(deadline)的调度算法,也就是不接受任何作业提交的时间要求。为了提高实时性,目前采用的方法都是优先级抢占式调度,使得高优先级的任务的到优先执行。说VxWorks内核是一种硬实时内核,这是不够准确的。准确的说VxWorks系统是实时系统,但是它的实时性是在一定计算资源前提下,通过恰当的任务划分和设定任务优先级来实现的。
VxWorks的内核态的本质是保护内核数据结构,以防止多处代码对内核数据结构同时进行访问,所以其不同于通用操作系统内核态的概念。进入内核态只需要简单的将全局变量kernelState置为TRUE,从这一点开始所有的内核数据将会被保护,而避免竞争。
kernelState在设置之前总是会被检查是否已经被置位。这就是互斥机制的精髓,VxWorks内核使用将工作延迟来作为互斥机制实现方式的技术,当kernelState为TRUE的时候,要做的工作不会立即执行,而是作为一个延迟的Job放到延时工作队列中。内核延时工作队列只能在恢复前一个将要执行的任务上下文之前,被WindExit()清空(或者当中断ISR首先进入内核态的条件下的,intExit()清空)。在内核态即将结束的时刻关中断,WindExit()会检查工作队列是否为空,并进入一个被选择的任务上下文。
内核态(kernelState=1)是一种强有力的互斥工具,处于内核态的时间内,抢占是被禁止的。高的抢占时延破坏了实时系统的响应时延的快速性,因此必须非常保守的使用这种机制。
Wind内核的一个重要的设计特性是最小的抢占延时。
基于Wind内核的VxWorks系统具有诸多优秀的特性,但作为实时系统而言,其实时内核所具备的重要尺度无非是上下文切换,同步开销,中断延时。
1.快速的任务上下文切换----由于实时系统的多任务的特性,系统能够快速地从一个任务切换到另一个任务是很重要的。在分时系统中,上下文切换是在ms级。Wind内核执行原始上下文切换用us级来衡量。
2.最小的同步开销----因为同步是实现资源互斥访问的基本方法,这些操作所引起的开销最小化是很重要的。在VxWorks中,请求和释放二值信号量也是用us级来衡量。
3.最小的中断延时----因为外部世界来的事件通常以中断的形式到来,操作系统快速的处理这些中断是很重要的。内核在操作一些临界数据结构的时候必须禁止中断。为了减小中断延时,必须使这些时间最小化。Wind内核的中断延时也是us级别。
VxWorks系统在Wind内核之上提供了大量的功能。但这些通讯,网络等模块都不是运行在内核级,所以不会禁止中断或任务抢占。
虽然Linux系统功能强大、实用性强、易于软件的二次开发,并且提供编程人员熟悉的标准API。但是由于Linux系统一开始就被设计成GPOS(通用操作系统),它的目的是构建一个完整、稳定的开源操作系统,尽量缩短系统的平均响应时间,提高吞吐量,注重操作系统的整体功能需求,达到更好地平均性能。
因此在设计Linux的进程调度算法时主要考虑的是公平性,也就是说,调度器尽可能将可用的资源平均分配给所有需要处理器的进程,并保证每个进程都得以运行。但这个设计目标是和实时进程的需求背道而驰的,所以标准Linux并不提供强实时性。
Linux系统提供符合POSIX标准的调度策略,包括FIFO调度策略(SCHED_FIFO)、带时间片轮转的实时调度策略(SCHED_RR)和静态优先级抢占式调度策略(SCHED_OTHER)。
Linux进程默认的调度策略为SCHED_OTHER,这种调度方式虽然可以让进程公平地使用CPU和其它资源,但是并不能保证对时间要求严格或者高优先级的进程将先于低优先级的执行,这将严重影响系统实时性。那么,将实时进程的调度策略设置为SCHED_FIFO 或SCHED_RR ,似乎使得Linux系统具备根据进程优先级进行实时调度的能力,但问题在于,Linux系统在用户态支持可抢占调度策略,而在内核态却不完全支持抢占式调度策略。这样运行在Linux内核态的任务(包括系统调用和中断处理)是不能被其它优先级更高的任务所抢占的,由此引起优先级逆转问题。
Linux的系统进程运行分为用户态和内核态两种模式。当进程运行在用户态时,具有高的优先级的进程可以抢占进程,可以较好地完成任务;但是当进程运行在内核态时,即使其他高优先级进程也不能抢占该进程。当进程通过系统调用进入内核态运行时,实时任务必须等待系统调用返回后才能获得系统资源。这和实时系统所要求的高优先级任务运行是相互矛盾的。
Linux2.6版本后的内核的3种抢占模式:
PREEMPT_NONE——没有强制性的抢占。整体的平均延时较低,它最适合那些以整体吞吐率为首要设计准则的应用。
PREEMPT_VOLUNTARY——降低延时的第一阶段。它会在内核代码的一些关键位置上放置额外的显示抢占点,以降低延时。
PREEMPT/PREEMPT_DESKTOP——这种模式使内核在任何地方都是可抢占的,临界区除外。这也是以牺牲整体吞吐率为代价的。
Linux在进行中断处理时都会关闭中断,这样可以更快、更安全地完成自己的任务,但是在此期间,即使有更高优先级的实时进程发生中断,系统也无法响应,必须等到当前中断任务处理完毕。这种状况下会导致中断延时和调度延时增大,降低Linux系统的实时性。
时钟系统是计算机的重要组成部分,相当于整个操作系统的脉搏。系统所能提供的最小时间间隔称为时钟粒度,时钟粒度与进程响应的延迟性是正比关系,即粒度越粗糙,延迟性越长。但时钟粒度并不是越小越好,就同等硬件环境而言,较小的时间粒度会导致系统开销增大,降低整体吞吐率。在Linux2.6内核中,时钟中断发生频率范围是50~1200Hz,周期不小于0.8ms,对于需要几十微秒的响应精度的应用来说显然不满足要求。而在嵌入式Linux系统中,为了提高整体吞吐率,时钟频率一般设置为100HZ或250HZ。
另外,系统时钟负责软定时,当软定时器逐渐增多时会引起定时器冲突,增加系统负荷。
根据实时性系统要求以及Linux的特点和性能分析,对标准Linux实时性的改造存在多种方法,较为合理的方法有:直接修改内核源码,双内核法、独立核方法、资源核方法,下面以直接修改内核源码为例简单分析Linux系统实时性的改进。
对Linux内核代码进行细微修改并不对内核作大规模的变动,在遵循GPL协议的情况下,直接修改内核源代码将Linux改造成一个完全可抢占的实时系统。核心修改面向局部,不会从根本上改变Linux内核,并且一些改动还可以通过Linux的模块加载来完成,即系统需要处理实时任务时加载该功能模块,不需要时动态卸载该模块。
目前kernel.org发布的主线内核版本还不支持硬实时。为了开启硬实时的功能,必须对代码打补丁。实时补丁在Linux内核中添加了几个重要特性,包括使用可抢占的互斥量来替代自旋锁;除了使用preempt_disable()保护的区域以外,内核中的所有地方都开启了非自愿式抢占(involuntary preemption)功能。这种模式能够显著降低抖动(延时的变化),并且使那些对延时要求很高的实时应用具有可预测的较低延时。
这种方法存在的问题是:很难百分之百保证,在任何情况下,GPOS程序代码绝不会阻碍RTOS的实时行为。也就是说,通过修改Linux内核,难以保证实时进程的执行不会遭到非实时进程所进行的不可预测活动的干扰。
1.经过上面的阐述与分析,可以得出VxWorks本身就是具有实时性的操作系统,而Linux作为通用的操作系统,并不具备实时性,必须通过一定的内核改进才可以是实现实时性,然而多数的改进都会牺牲部分Linux本身的优势。改进的方向集中在抢占式机制或者中断机制的修改,包括任务的抢占性改进或者增加抢占点。
2.作为实时系统的VxWorks系统,Wind内核是基于优先级的抢占调度的,256个优先级高优先级可抢占,外部中断等级高于任何任务。任务是否可以进入内核态,只需检测kernelState是TRUE或者FALSE,进入内核态后只有中断服务程序可以请求内核服务,既可以保证内核态安全运行,又可以保证高等级的实时任务抢占内核态。所有任务所在的共享地址空间,也使得任务能够使用共享数据结构的指针自由地通信。
3.Linux相比于VxWorks不能实现实时性的因素是由内核态却不完全支持抢占式的进程调度、内核态时,即使其他高优先级进程也不能抢占该进程的内核抢占机制、中断处理时都会关闭中断的中断屏蔽策略、时钟粒度粗糙等问题,当然虚拟内存管理造成的频繁页面进出,共享资源的互斥访问差异也是很重要的原因。
4.常见的Linux实时系统如RT Linux系统,Linux内核和硬件中断的地方加上了一个RT Linux内核的控制,Linux的控制信号都要先交给RT Linux内核进行处理。中断处理全部由RT Linux实时核心处理,在优先级调度策略之下,实时中断具有更高等级的优先级,来保证实时任务的迅速调度。但是频繁的向RT Linux发送信号进行上下文切换,势必导致效率上不如VxWorks。且开发总是面对小的实时核心,实时任务是运行在系统核心层的,这就意味着这些实时任务可以运行在没有内存保护的级别之上,一旦发生错误,将威胁到整个系统。
改进后的Linux系统,确实具有了实时性,成为一个实时系统。但是具体的改进还是要根据需求的。毕竟经改进后,有些会造成系统的整体处理能力和吞吐量降低,或者降低系统的兼容性,系统膨胀等问题。事有取舍,系统功能也一样。
参考文章