|
摘 要:linux作为嵌入式操作系统在嵌入式系统中应用越来越普及。linux若是作为一个实时操作系统,它无法满足实时系统严格的实时性要求。rtlinux是在linux内核的下层实现所得的一个简单的硬实时内核,但是rtlinux也存在一个很大的缺陷,那就是实时任务无法使用linux提供的服务,特别是它无法使用linux中的tcp/ip的网络功能,在此介绍的iwip是一个可以运行在rtlinux并能被实时任务使用的嵌入式的轻量级tcp/ip协议栈。iwip还可以使实时任务与远程实时任务或linux用户进程通讯。根据这些特性,我们通过将linux,iwip和rtlinux3者合理的结合在一起,从而构成一个全新的实时系统框架。
关键词:嵌入式系统;rtlinux;iwip;设备驱动程序
引 言 linux或经过简单改进的linux都是不能运行实时任务,这是因为linux的“公平”时间分配的调度算法要保证分配给每一个用户程序占用cpu时间,然而实时任务对执行时间要求很严格,如每隔200ns从传感器取样的实时任务。linux系统的虚拟内存的内存管理使得任何用户进程的页面在任何时刻都能被交换到硬盘或外存储器中,这样在linux中将需要的页面返回到ram中也需要花费一段不确定的时间。另外,对任务执行的时间和任务完成时间都是没有精确的可预知性的。linux操作系统的“天生”缺陷使得linux无法满足实时嵌入式系统的实时系统要求。在本文中我们主要讨论实时操作系统rtlinux和linux有机集成在一起,构成了一个全新的实时系统。
rtlinux的实现机理
rtlinux是美国新墨西哥州大学计算机科学系victoryodaiken和micae brannanov开发的。它在linux内核的下层实现了一个简单的实时内核,而linux本身作为这个实时内核的优先级最低的任务,所有的实时任务的优先级都高于linux系统本身的以及linux系统下的一般任务。rtlinux的体系结构如图1所示。

rtlinux的设计思想是:应用硬件的实时约束将实时程序分割成短小简单的部分,较大部分承担较复杂的任务。根据这一原则,将应用程序分为硬实时和程序2个部分。硬件实时部分被作为实时任务来执行,并从外部设备拷贝数据到一个叫做实时有名管道(rtfifo)的特殊i/o端口;程序主要部分作为标准linux进程来执行。它将从rtfifo中读取数据,然后显示并存储到文件中,实时部分将被写入内核。设计实时有名管道是为了使实时任务在读和写数据时不被阻塞。图2所示的是实时有名管道结构图。

rtlinux通过对标准linux内核进行改造,将linux内核工作环境作了一些变化。如图2所示,在linux进程和硬件中断之间,本来由linux内核完全控制,现在在linux内核和硬件中断的地方加上了一个rtlinux内核的控制。linux的控制信号都要先交给rtlinux内核进行处理。在rtlinux内核中实现了一个虚拟中断机制,linux本身永远不能屏蔽中断,它发出的中断屏蔽信号和打开中断信号都修改成向rtlinux发送一个信号。如在linux里面使用“si”和“cli”宏指令,让rtlinux里面的某些标记做了修改。也就是说将所有的中断分成linux中断和实时中断两类。如果rtlinux内核接收到的中断信号是普通linux中断,那就设置一个标志位;如果是实时中断,就继续向硬件发出中断。在rtlinux中执行sti将中断打开之后,那些设置了标志位表示的linux中断就继续执行,因此,cli并不能禁止rtlinux内核的运行,却可以用来中断linux。linux不能中断自己,而rtlinux可以。
这里体现了rtlinux设计过程中的原则:在实时模块中的工作量尽量少,如果能在linux中完成而不影响实时性能的话,就尽量在linux中完成,因此,rtlinux内核可以尽量做得简单。在rtlinux内核中,不应该等待资源,也不需要使用共享旋转锁。实时任务和linux进程之间的通信也是非阻塞的,从来不用等待进队列和出队列的数据。rtlinux将系统和设备的初始化交给了linux 完成,对动态资源的申请和分配也交给了linux。
rtlinux使用静态分配的内存来完成硬件实时任务,因为在没有内存资源的时候,被阻塞的线程是不可能具有实时能力的。
轻量级tcp/ip协议栈iwip向rtlinux的移植
iwip概述 lwip是瑞典计算机科学研究所(sics)的计算机与网络结构实验室(cna)的adamdunkel设计的一个小型的独立的tcp/ip协议栈。lwiptcp/ip协议栈设计的思想是:在保持完整的tcp/ip协议栈的前提下最大限度的降低其所需的资源,以适应只有十几kbytesram和40kbytes左右的rom的嵌入式系统。iwip协议栈包含了ip,ipv6,icmp,udp和tcp等协议。
iwip协议栈不是像tcp/ip网络协议那样分不同层次,每一层分别负责不同的通讯功能。iwip设计的初衷是应用于嵌入式系统,嵌入式系统通常有较强的实时性和内存容量有限等特点,因此iwip在网络协议栈中不是完全遵守网络协议栈的分层体系结构进行设计的。例如应用层为了提高实时性,它并没有遵守“上层调用下层提供的服务,下层向上层提供服务”这个协议分层设计的原则,而是应用层和其下层共享系统内部的缓冲区,从而节省应用程序与下层协议之间的数据复制所需的系统开支。
iwip除了上面提到的tcp/ip协议栈外,它还包含了一些应用支撑模块。这些支撑模块是操作系统抽象层模块(sys_archmodule)、内存管理模块、网络功能接口模块和校验和计算模块。这些模块中,除了操作系统抽象层外,其他模块都是相互独立的。iwip栈向rtlinux上的移植的关键点就是将它新增的对操作系统函数调用和数据结构添加或集成到操作系统抽象层模块中。这样,操作系统抽象层向其他调用它的模块提供统一的api接口,使得系统的移植与具体的硬件系统无关,降低了系统移植的复杂性。操作系统抽象层提供的外部应用接口中包括了诸如线程管理、定时器管理以及中断管理等系统资源管理接口。由于该部分内容在很多书籍和资料中都已经做了很详尽的论述,在此不再做详细阐述了。
rtlinux中的网络驱动程序的设计 网络驱动程序的功能主要是赋予本机网络ip地址、掩码、网关地址和收发网络数据包等。iwip包含有网络接口驱动程序,但是这些驱动程序是针对标准linux系统的,而非rtlinux的,因此我们有要将这些网络接口驱动程序进行适当的改造以适用于rtlinux系统。在rtlinux系统中,我们是利用前面提到的rtfifo对网络接口驱动程序进行功能扩展和性能改进。这样,linux系统和rtlinux系统就像2个独立的系统。
rtlinux中进程之间、内核与进程之间都是通过信号(signal)进行相互通信的。信号是基于pos2ix标准,rtlinux的设备驱动程序也是基于posix标准,它可以调用标准的文件操作函数如open,read,write,close等。但是基于posixb标准的信号存在一个问题,那就是每次进程只能接收一个信号,后续的信号无法被接收,网络驱动程序的这种“串行”处理网络数据包的方式和网络上数据包传输的突发性的特点对嵌入式系统是一个很大的障碍和威胁。因为嵌入式系统的内存是极其有限的资源,上述那种处理方式很容易造成系统缓冲区满负荷从而导致系统内存溢出,更坏的后果可能是导致整个系统的崩溃。在研究了上述问题后,笔者借鉴了标准linux系统中实时信号(linux内核没有利用实时信号)的特点,提出了将数据包接收处理线程注册到网络驱动程序中,当有数据包到达时,网络驱动程序即刻通知该线程去接收抵达的数据包。同时,在添加一个全程变量,用来跟踪记录当前被挂起的信号数目。这样既可以提高系统的处理接收数据包的实时性能,同时又解决了posix标准中信号接收的问题。这个处理机制的代码实现也是很简单的,其部分主要代码如下所示。
do{ read(fd,(void3)&receive,1546); }while(dec_pendent_signals()); 上面那段代码中的dec_pendent_signals函数的功能流程大致如下: intdec_pendent_signals() {…… stop_interrupt(…);关中断 if(pendent_signals==1)retval=0; pendentsignals;接收并处理被挂起的信号对列里的一个信号allow_inerrupt(…); 开中断 ……}
中断处理程序 网络接口中断处理程序也同样存在前面提到的问题,即当驱动程序正在处理一个数据包接收中断时,后续数据包到达时网卡产生的硬件中断都无法被驱动程序接收到。笔者在此提出了一个较为合理的解决方案。在网卡驱动程序初始化时,驱动程序给网卡分配一个指向系统内存的指针,这个指针是个单循环指针链表。此设计的好处在于当有数据包到达时,网卡可以将数据包缓存在这片系统内存中,并将相应的标志位置位。当该数据包被上层应用成功接收后,该标志位也复位。下面这段代码是用直观的程序语言进行描述的。 while(next_upd->uppkstatus&uploaded){ receive_packet();}
代码中的uploaded就是上面提到的标志位。我们可以用更直观的图例描述这个解决方案,如图3所示(图3中的upd表示接收包描述符,即upload packet desc-riptors)。

从图3我们可以看出:系统能否最大限度的降低丢包率,在很大程度上取决于接收数据缓冲区的容量。一方面,嵌入式系统的内存是很宝贵也很有限的资源,另一方面,系统能否正常工作以及性能稳定在很大程度上又决定于内存资源的合理布局与分配。就网络接口而言,考虑到网络中多播和组播数据包的存在,网络接口需要把他们都接收下来,然后判断该数据包是否是发给自己的。由于网络中这样的多播和组播数据包在所有传输的数据包中占有很大部分比例,因此,倘若网络接口没有及时处理收到的数据包,该数据包就可能被后续到达的数据所覆盖。因此,如何从两者中找到一个折衷的方案是在实践过程中,针对具体的系统做不同的设计。
结束语
计算机与通信技术日新月异,尤其在因特网方面,将rtlinux应用在针对实时嵌入式系统的研究与开发也越来越受到人们的关注。本文中我们比较详细的介绍了将iwip移植到rtlinx的过程,并就rtlinux下的网络驱动程序设计作了比较深入的研究与实践。实时嵌入式系统是当前的研究与实践的一个热点,有许多问题亟需解决,本文只是冰山上的一角,希望能抛砖引玉。 |