所谓实时,就是一个特定任务的执行时间必须是确定的,可预测的,并且在任何情况下都能保证任务的时限(最大执行时间限制)。实时又分软实时和硬实时,所谓软实时,就是对任务执行时限的要求不那么严苛,即使在一些情况下不能满足时限要求,也不会对系统本身产生致命影响,例如,媒体播放系统就是软实时的,它需要系统能够在1秒钟播放24帧,但是即使在一些严重负载的情况下不能在1秒钟内处理24帧,也是可以接受的。所谓硬实时,就是对任务的执行时限的要求非常严格,无论在什么情况下,任务的执行实现必须得到绝对保证,否则将产生灾难性后果,例如,飞行器自动驾驶和导航系统就是硬实时的,它必须要求系统能在限定的时限内完成特定的任务,否则将导致重大事故,如碰撞或爆炸等。
回页首
二、衡量实时性的指标
那么,如何判断一个系统是否是实时的呢?主要有以下两个指标:
1. 中断延迟
中断延迟就是从一个外部事件发生到相应的中断处理函数的第一条指令开始执行所需要的时间。很多实时任务是靠中断驱动的,而且中断事件必须在限定的时限内处理,否则将产生灾难性后果,因此中断延迟对于实时系统来说,是一个非常重要的指标。
2. 抢占延迟
有时也称调度延迟,抢占延迟就是从一个外部事件发生到相应的处理该事件的任务的第一条命令开始执行的时间。大多数实时系统都是处理一些周期性的或非周期性的重复事件,事件产生的频度就确定了任务的执行时限,因此每次事件发生时,相应的处理任务必须及时响应处理,否则将无法满足时限。抢占延迟就反映了系统的响应及时程度。
如果以上两个指标是确定的,可预测的,那么就可以说系统是实时的。
回页首
三、影响系统实时性的因素
对系统实时性的影响因素既有硬件方面的,也有软件方面的。
现代的高性能的硬件都使用了cache技术来弥补CPU和内存间的性能差距,但是cache却严重地影响着实时性,指令或数据在cache中的执行时间和指令或数据不在cache中的执行时间差距是非常巨大的,可能差几个数量级,因此为了保证执行时间的确定性和可预测性,来满足实时需要,一些系统就失效了cache或使用没有cache的CPU。
另一个硬件方面的影响因素就是虚存管理,对于多用户多任务的操作系统,它确实非常有用,它使得系统能够执行比物理内存更大的任务,而且各任务互不影响,完全有自己的独立的地址空间。但是虚存管理的缺页机制严重地影响了任务执行时间的可预测性和确定性,任务执行时使用缺页机制调入访问的指令或数据和被执行的指令和数据已经在内存中需要的执行时间的差距是非常大的。因此一些实时系统就不使用虚存技术,例如 Wind River的VxWorks。
在软件方面,影响因素包括关中断、不可抢占、一些O(n)的算法。
前面已经提到,中断延迟是衡量系统实时性的一个重要指标。关中断就导致了中断无法被响应,增加了中断延迟。
前面提到的抢占延迟也是衡量系统实时性的重要指标。如果发生实时事件时系统是不可抢占的,抢占延迟就会增加。
还有就是一些时间复杂度为O(n)的算法也影响了执行时间的不确定性,例如任务调度算法,要想执行实时任务必须进行调度,如果调度算法的执行时间取决于当前系统运行的任务数,那么调度实时任务所花费的时间就是不确定的,因为它是与系统运行的任务数呈线性关系的函数,运行的任务越多,时间就越长。
回页首
四、嵌入式系统需要实时Linux
Linux在设计之初没有对实时性进行任何考虑,因此非实时性绝非偶然。Linus考虑的是资源共享,吞吐率最大化。但是随着Linux的快速发展,它的应用已经远远超出了Linus自己的想象。Linux的开放性已经对很多种架构的支持使得它在嵌入式系统中得到了广泛的应用,但是许多嵌入式系统的实时性要求使得Linux在嵌入式领域的应用受到了一定的障碍,因此人们要求Linux需要实时性的呼声越来越高。
Linux的开放性和低成本是实时Linux发展的优势,越来越多的研究机构和商业团体开展了实时Linux的研究与开发,其中最著名的就是FSMLab的Rtlinux和TimeSys Linux。还有一个就是Ingo's RT patch。
回页首
五、标准Linux内核制约实时性的因素
标准Linux有几个机制严重地影响了实时性。
1.内核不可抢占
在Linux 2.4和以前的版本,内核是不可抢占的,也就是说,如果当前任务运行在内核态,即使当前有更紧急的任务需要运行,当前任务也不能被抢占。因此那个紧急任务必须等到当前任务执行完内核态的操作返回用户态后或当前任务因需要等待某些条件满足而主动让出CPU才能被考虑执行,这很明显严重影响抢占延迟。
在Linux 2.6中,内核已经可以抢占,因而实时性得到了加强。但是内核中仍有大量的不可抢占区域, 如由自旋锁 (spinlock)保护的临界区,以及一些显式使用preempt_disable失效抢占的临界区。
2.中断关闭
Linux在一些同步操作中使用了中断关闭指令,中断关闭将增大中断延迟,降低系统的实时性。
3.自旋锁(spinlock)
自旋锁是在可抢占内核和SMP情况下对共享资源的一种同步机制,一般地一个任务对共享资源的访问是非常短暂的,如果两个任务竞争一个共享的资源时,没有得到资源的任务将自旋以等待另一个任务使用完该共享资源。这种锁机制是非常高效的,但是在保持自旋锁期间将失效抢占,这意味着抢占延迟将增加。在2.6内核中,自旋锁的使用非常普遍,有的甚至对整个一个数组或链表的便历过程都使用自旋锁。因此抢占延迟非常不确定。
4.大内核锁
由于历史原因,内核一直保留有几个大内核锁,大内核锁实质上也是一种自旋锁,但是它与一般的自旋锁的区别是,它是用于同步整个内核的,而且一般该锁的保持时间较长,也即抢占失效时间长,因此它的使用将严重地影响抢占延迟。
5.中断总是最高优先级的
在Linux中,中断(包括软中断)是最高优先级的,不论在任何时刻,只要产生中断事件,内核将立即执行相应的中断处理函数以及软中断,等到所有挂起的中断和软中断处理完毕有才执行正常的任务。因此在标准的Linux系统上,实时任务根本不可能得到实时性保证。例如,假设在一个标准Linux系统上运行了一个实时任务(即使用了SCHED_FIFO调度策略并且设定了最高的实时优先级),但是该系统有非常繁重的网络负载和I/O负载,那么系统可能一直处在中断处理状态而没有机会运行任何任务,这样实时任务将永远无法运行,抢占延迟将是无穷大。因此,如果这种机制不改,实时Linux将永远无法实现。
6.调度算法和调度点
在Linux 2.4和以前的版本,调度器的时间复杂度是O(n)的,而且在SMP的情况下性能低,因为所有的CPU共享一个任务链表,任何时刻只能有一个调度器运行。因此,抢占延迟很大程度上以来于当前系统的任务数,具有非常大的不确定性和不可预测性。
在2.6内核中引入的O(1)调度器很好地解决了这些问题。
此外,即使内核是可抢占的,也不是在任何地方可以发生调度,例如在中断上下文,一个中断处理函数可能唤醒了某一高优先级进程,但是该进程并不能立即运行,因为在中断上下文不能发生调度,中断处理完了之后内核还要执行挂起的软中断,等它们处理完之后才有机会调度刚才唤醒的进程。在标准Linux内核中,调度点(有意安排的执行任务调度的点)并不多,对2.4和2.6内核测试的结果表明,缺乏调度点是影响Linux实时性的一个因素。
回页首
六、现存的Linux实时技术
现有的著名的实时Linux实现包括RTLinux、RTAI和TimeSys。
1. RTLinux
RTLinux是著名的研究机构FSMLab研发的一款实时Linux,既有GPL和Free版本,又有商业版本。它使用的实现方式是子内核方法,即把Linux内核作为一个新实现的子内核的闲暇任务,子内核位于Linux内核和硬件抽象层之间,实时任务运行于子内核之上,只有当没有实时任务需要运行时,Linux内核才有机会运行。
特别是对中断的管理,它采用了一种软件的方式来处理Linux内的中断关闭,当Linux内核关闭中断后,并不是真正地屏蔽了硬件中断,相反,它使用了一个变量来保存Linux内核的中断标志位,Linux内核的开关中断只是影响了该变量,硬件的中断由子内核来接管,当Linux内核关闭了中断,子内核仍然可以响应任何中断,只是如果子内核不需要处理的中断才交给Linux内核来处理,如果Linux内核关闭了中断,子内核将记录该中断并在Linux内核打开中断后提交它处理。
在RTLinux里,每一个实时任务都是内核线程,运行在内核空间,RTLinux提供了一套专门的机制来在实时任务和普通的Linux任务之间进行进程间通信。
这种子内核的实现提供了非常好的实时性,完全是一个硬实时的Linux。
2.TimeSys Linux
Timesys很早就发布了实时Linux的商业版以及GPL版,它采用了与RTLinux完全不同的实现方式。前面已经提到了标准Linux内核的实时限制,TimeSys Linux就是通过消除这些限制来达到实时性的。它把中断(IRQ)和软中断(softIRQ)全部线程化并赋予不同的优先级,实时任务可以有比中断线程更高的优先级,它使用Mutex替代spinlock来使得自旋锁完全可抢占。它也对调度器做了优化使它是O(1)的(注:因为使用2.4内核)。由于中断已经线程化了,很多中断关闭就没必要了,因而消除了很多中断关闭区域。它还实现了对CPU和网络资源的预定来改善实时性。后面将说的Ingo's RT patch就是借鉴这些思路来实现实时性的。
这种实现方式保持了全部的Linux应用编程模式,实时应用和普通的应用采用同样的编程方式,使用同样的API,只是实时任务需要明确指定自己的优先级与调度策略。但是这种实现方式也有弊病,那就是它满足硬实时性有一定的困难,因为即使中断关闭和不可抢占区大为减少,但是还是存在,一些中断还是无法线程化,如时钟中断等。
3. Ingo's RT patch
Ingo's RT patch是又一个Linux实时实现,它采用了与TimeSys完全相同的技术路线,而且有一些实现是基于TimeSys的源代码的,如IRQ和softirq线程化。但是它与前面提到的两个实时实现不同的地方是,它可能并入到标准Linux内核(作者预见,可能并入到2.6.13或以后的某个版本中)。在最新的标准内核Linux 2.6.11中,已经出现了这个补丁曾经包含的部分代码,如IRQ子系统,那是IRQ和softirq线程化的基础,已经隐含了一些线程化的代码,如自愿抢占代码,那是2.4的低延迟补丁(low latency patch)和Ingo的一些自愿抢占代码以及Robert Love的锁分解补丁的集合,还有可抢占的大内核锁。
本系列第 2 部分将专门对Ingo's RT patch进行详细的解读。