VxWorks和Linux内核实时性

通用的分时操作系统面向多用户的不同任务,意在追求系统整体运行的效率和资源的均衡利用,软件的执行在时间上要求并不严格。
实时操作系统不同于分时操作系统,它主要是对任务进行实时的处理,要求任务的运行具有可确定性和可预测性,提供即时响应和高可靠性。
由此导致通用分时系统和实时操作系统的内核在任务调度机制方面的不同。
下面主要以内核架构,系统的实时性,以及对系统的实时性改进三点为核心简要分析VxWorks和Linux内核实时性并予以对比。

一、内核架构

1.1 Linux宏内核架构

Linux采用宏内核架构。宏内核(Monolithic kernel)又称单内核,其特征是操作系统内核的所有模块(包括进程调度、内存管理、文件系统、设备驱动等)均运行在内核态,具备直接操作硬件的能力,大部分设备驱动是以可加载模块的形式存在的,与内核其他模块解耦,使驱动开发与驱动加载更加方便、灵活。
Linux 是通用操作系统,不是实时操作系统,所以设计初是宏内核,本着公平的原则,虽然用户可以设计任务优先级,但操作系统会根据每个任务的运行时间,自动调整每个任务占用CPU的时间,这样使每个任务都能公平的占用CPU。

1.2 VxWorks 微内核架构

VxWorks实时操作系统核心的是高性能的微内核Wind。这个微内核支持所有的实时特征:快速任务切换、中断支持、抢占式和时间片轮转调度等。微内核设计减少了系统开销,从而保证了对外部事件的快速、确定的反应。
运行环境也提供了有效的任务间通信机制,允许独立的任务在实时系统中与其行动相协调。开发者在开发应用程序时可以使用多种方法:用于简单数据共享的共享内存、用于单CPU的多任务间信息交换的消息队列和管道、套接口、用于网络通信的远程过程调用、用于处理异常事件的信号等。为了控制关键的系统资源,提供了三种信号灯:二进制、计数、有优先级继承特性的互斥信号灯。

二、实时性

实时性主要体现在软件层次的保证在规定时间完成任务。而不是由硬件性能决定的速度快。实时进程不会影响自己在执行环境中的调度,反而是环境影响实时应用程序的调度。也就是说,实时进程通常和某个物理事件相关联,比如外围设备的中断。那么显然,影响实时的原因在于中断响应延时,在Linux系统中可细分为中断延时、中断处理、调度延时。一般来说,针对用户对超出时间限制所造成的影响的可接受程度,实时又可分为软实时和硬实时。
大多观点认为软实时意味着操作有时间限制,硬实时的特点是错过时限会造成严重结果,从内核层面分析来说,标准的Linux是一个软实时系统,VxWorks采用的Wind内核是一种强实时操作系统内核,但和当前其它成熟的操作系统一样,并不是“硬实时”的操作系统。

2.1 VxWorks的实时性的分析

VxWorks 没有使用基于时间限(deadline)的调度算法,也就是不接受任何作业提交的时间要求。为了提高实时性,目前采用的方法都是优先级抢占式调度,使得高优先级的任务的到优先执行。说VxWorks内核是一种硬实时内核,这是不够准确的。准确的说VxWorks系统是实时系统,但是它的实时性是在一定计算资源前提下,通过恰当的任务划分和设定任务优先级来实现的。

2.1.1 VxWorks内核结构与其实时性

VxWorks的内核态的本质是保护内核数据结构,以防止多处代码对内核数据结构同时进行访问,所以其不同于通用操作系统内核态的概念。进入内核态只需要简单的将全局变量kernelState置为TRUE,从这一点开始所有的内核数据将会被保护,而避免竞争。
kernelState在设置之前总是会被检查是否已经被置位。这就是互斥机制的精髓,VxWorks内核使用将工作延迟来作为互斥机制实现方式的技术,当kernelState为TRUE的时候,要做的工作不会立即执行,而是作为一个延迟的Job放到延时工作队列中。内核延时工作队列只能在恢复前一个将要执行的任务上下文之前,被WindExit()清空(或者当中断ISR首先进入内核态的条件下的,intExit()清空)。在内核态即将结束的时刻关中断,WindExit()会检查工作队列是否为空,并进入一个被选择的任务上下文。
内核态(kernelState=1)是一种强有力的互斥工具,处于内核态的时间内,抢占是被禁止的。高的抢占时延破坏了实时系统的响应时延的快速性,因此必须非常保守的使用这种机制。

2.1.2 VxWorks内核设计与其实时性

Wind内核的一个重要的设计特性是最小的抢占延时。
基于Wind内核的VxWorks系统具有诸多优秀的特性,但作为实时系统而言,其实时内核所具备的重要尺度无非是上下文切换,同步开销,中断延时。
1.快速的任务上下文切换----由于实时系统的多任务的特性,系统能够快速地从一个任务切换到另一个任务是很重要的。在分时系统中,上下文切换是在ms级。Wind内核执行原始上下文切换用us级来衡量。
2.最小的同步开销----因为同步是实现资源互斥访问的基本方法,这些操作所引起的开销最小化是很重要的。在VxWorks中,请求和释放二值信号量也是用us级来衡量。
3.最小的中断延时----因为外部世界来的事件通常以中断的形式到来,操作系统快速的处理这些中断是很重要的。内核在操作一些临界数据结构的时候必须禁止中断。为了减小中断延时,必须使这些时间最小化。Wind内核的中断延时也是us级别。
VxWorks系统在Wind内核之上提供了大量的功能。但这些通讯,网络等模块都不是运行在内核级,所以不会禁止中断或任务抢占。

2.2制约标准Linux操作系统实时性的因素

虽然Linux系统功能强大、实用性强、易于软件的二次开发,并且提供编程人员熟悉的标准API。但是由于Linux系统一开始就被设计成GPOS(通用操作系统),它的目的是构建一个完整、稳定的开源操作系统,尽量缩短系统的平均响应时间,提高吞吐量,注重操作系统的整体功能需求,达到更好地平均性能。
因此在设计Linux的进程调度算法时主要考虑的是公平性,也就是说,调度器尽可能将可用的资源平均分配给所有需要处理器的进程,并保证每个进程都得以运行。但这个设计目标是和实时进程的需求背道而驰的,所以标准Linux并不提供强实时性。

2.2.1 进程调度

Linux系统提供符合POSIX标准的调度策略,包括FIFO调度策略(SCHED_FIFO)、带时间片轮转的实时调度策略(SCHED_RR)和静态优先级抢占式调度策略(SCHED_OTHER)。
Linux进程默认的调度策略为SCHED_OTHER,这种调度方式虽然可以让进程公平地使用CPU和其它资源,但是并不能保证对时间要求严格或者高优先级的进程将先于低优先级的执行,这将严重影响系统实时性。那么,将实时进程的调度策略设置为SCHED_FIFO 或SCHED_RR ,似乎使得Linux系统具备根据进程优先级进行实时调度的能力,但问题在于,Linux系统在用户态支持可抢占调度策略,而在内核态却不完全支持抢占式调度策略。这样运行在Linux内核态的任务(包括系统调用和中断处理)是不能被其它优先级更高的任务所抢占的,由此引起优先级逆转问题。

2.2.2内核抢占机制

Linux的系统进程运行分为用户态和内核态两种模式。当进程运行在用户态时,具有高的优先级的进程可以抢占进程,可以较好地完成任务;但是当进程运行在内核态时,即使其他高优先级进程也不能抢占该进程。当进程通过系统调用进入内核态运行时,实时任务必须等待系统调用返回后才能获得系统资源。这和实时系统所要求的高优先级任务运行是相互矛盾的。
Linux2.6版本后的内核的3种抢占模式:
PREEMPT_NONE——没有强制性的抢占。整体的平均延时较低,它最适合那些以整体吞吐率为首要设计准则的应用。
PREEMPT_VOLUNTARY——降低延时的第一阶段。它会在内核代码的一些关键位置上放置额外的显示抢占点,以降低延时。
PREEMPT/PREEMPT_DESKTOP——这种模式使内核在任何地方都是可抢占的,临界区除外。这也是以牺牲整体吞吐率为代价的。

2.2.3中断屏蔽

Linux在进行中断处理时都会关闭中断,这样可以更快、更安全地完成自己的任务,但是在此期间,即使有更高优先级的实时进程发生中断,系统也无法响应,必须等到当前中断任务处理完毕。这种状况下会导致中断延时和调度延时增大,降低Linux系统的实时性。

2.2.4时钟粒度粗糙

时钟系统是计算机的重要组成部分,相当于整个操作系统的脉搏。系统所能提供的最小时间间隔称为时钟粒度,时钟粒度与进程响应的延迟性是正比关系,即粒度越粗糙,延迟性越长。但时钟粒度并不是越小越好,就同等硬件环境而言,较小的时间粒度会导致系统开销增大,降低整体吞吐率。在Linux2.6内核中,时钟中断发生频率范围是50~1200Hz,周期不小于0.8ms,对于需要几十微秒的响应精度的应用来说显然不满足要求。而在嵌入式Linux系统中,为了提高整体吞吐率,时钟频率一般设置为100HZ或250HZ。
另外,系统时钟负责软定时,当软定时器逐渐增多时会引起定时器冲突,增加系统负荷。

三、实时Linux改进

根据实时性系统要求以及Linux的特点和性能分析,对标准Linux实时性的改造存在多种方法,较为合理的方法有:直接修改内核源码,双内核法、独立核方法、资源核方法,下面以直接修改内核源码为例简单分析Linux系统实时性的改进。

3.1 直接修改源码

对Linux内核代码进行细微修改并不对内核作大规模的变动,在遵循GPL协议的情况下,直接修改内核源代码将Linux改造成一个完全可抢占的实时系统。核心修改面向局部,不会从根本上改变Linux内核,并且一些改动还可以通过Linux的模块加载来完成,即系统需要处理实时任务时加载该功能模块,不需要时动态卸载该模块。
目前kernel.org发布的主线内核版本还不支持硬实时。为了开启硬实时的功能,必须对代码打补丁。实时补丁在Linux内核中添加了几个重要特性,包括使用可抢占的互斥量来替代自旋锁;除了使用preempt_disable()保护的区域以外,内核中的所有地方都开启了非自愿式抢占(involuntary preemption)功能。这种模式能够显著降低抖动(延时的变化),并且使那些对延时要求很高的实时应用具有可预测的较低延时。
这种方法存在的问题是:很难百分之百保证,在任何情况下,GPOS程序代码绝不会阻碍RTOS的实时行为。也就是说,通过修改Linux内核,难以保证实时进程的执行不会遭到非实时进程所进行的不可预测活动的干扰。

对比VxWorks与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系统,确实具有了实时性,成为一个实时系统。但是具体的改进还是要根据需求的。毕竟经改进后,有些会造成系统的整体处理能力和吞吐量降低,或者降低系统的兼容性,系统膨胀等问题。事有取舍,系统功能也一样。

参考文章

[编辑本段]Turbo C2.0    介绍      Turbo C2.0不仅是一个快捷、高效的编译程序,同时还有一个易学、易用的集成开发环境。使用Turbo C2.0无需独立地编辑、编译和连接程序,就能建立并运行C语言程序。因为这些功能都组合在Turbo 2.0的集成开发环境内,并且可以通过一个简单的主屏幕使用这些功能。    基本配置要求   Turbo C 2.0可运行于IBM-PC系列微机,包括XT,AT及IBM 兼容机。此时要求DOS2.0或更高版本支持,并至少需要448K的RAM,可在任何彩、单色80列监视器上运行。支持数学协处理器芯片,也可进行浮点仿真,这将加快程序的执行。 [编辑本段]Turbo C 2.0的主要文件的简单介绍   INSTALL.EXE 安装程序文件   TC.EXE 集成编译   TCINST.EXE 集成开发环境的配置设置程序   TCHELP.TCH 帮助文件   THELP.COM 读取TCHELP.TCH的驻留程序README 关于Turbo C的信息文件   TCCONFIG.EXE 配置文件转换程序MAKE.EXE   项目管理工具TCC.EXE   命令行编译TLINK.EXE   Turbo C系列连接器TLIB.EXE   Turbo C系列库管理工具C0?.OBJ 不   同模式启动代码C?.LIB   不同模式运行库GRAPHICS.LIB   图形库EMU.LIB   8087仿真库FP87.LIB 8087库   *.H Turbo C头文件   *.BGI 不同显示器图形驱动程序   *.C Turbo C例行程序(源文件)   其中:上面的?分别为:T Tiny(微型模式)S Small(小模式)C Compact(紧凑模式)M Medium(中型模式)L Large(大模式)H Huge(巨大模式)    Turbo C++ 3.0   “Turbo C++ 3.0”软件是Borland公司在1992年推出的强大的——C语言程序设计与C++面向对象程序设计 的集成开发工具。它只需要修改一个设置选项,就能够在同一个IDE集成开发环境下设计和编译以标准 C 和 C++ 语法设计的程序文件。 [编辑本段]C 语言   C语言起始于1968年发表的CPL语言,它的许多重要思想都来自于Martin Richards在1969年研制的BCPL语言,以及以BCPL语言为基础的与Ken Thompson在1970年研制的B语言。Ken Thompson用B语言写了第一个UNIX操作系统。M.M.Ritchie1972年在B语言的基础上研制了C语言,并用C语言写成了第一个在PDP-11计算机上研制的UNIX操作系统。1977年出现了独立于极其的C语言编译文本《看移植C语言编译程序》,从而大大简化了把C语言编译程序移植到新环境中所做的工作,这本身也就使UNIX的日益广泛使用,C语言也迅速得到推广。   1983年美国国家标准化协会(ANSI)根据C语言问世以来的各种版本,对C语言的发展和扩充制定了新的标准,成为ANSI C。1987年ANSI又公布了新标准————87ANSI C。   目前在微型计算机上使用的有Microsoft C、Quick C、Turbo C等多种版本。这些不同的C语言版本,基本部分是相同的,但是在有关规定上有略有差异。   C 语言发展如此迅速, 而且成为最受欢迎的语言之一, 主要因为它具有强大的功能。许多著名的系统软件, 如DBASE Ⅲ PLUS、DBASE Ⅳ 都是由C 语言编写的。用C 语言加上一些汇编语言子程序, 就更能显示C 语言的优势了,象PC- DOS ,WORDSTAR等就是用这种方法编写的。归纳起来C 语言具有下列特点:   1. C是中级语言   它把高级语言的基本结构和语句与低级语言的实用性结合起来。C 语言可以象汇编语言一样对位、字节和地址进行操作, 而这三者是计算机最基本的工作单元。   2. C是结构式语言   结构式语言的显著特点是代码及数据的分隔化, 即程序的各个部分除了必要的信息交流外彼此独立。这种结构化方式可使程序层次清晰, 便于使用、维护以及调试。C 语言是以函数形式提供给用户的, 这些函数可方便的调用, 并具有多种循环、条件语句控制程序流向, 从而使程序完全结构化。   3. C语言功能齐全   C 语言具有各种各样的数据类型, 并引入了指针概念, 可使程序效率更高。另外C 语言也具有强大的图形功能, 支持多种显示器和驱动器。而且计算功能、逻辑判断功能也比较强大, 可以实现决策目的。   4. C语言适用范围大   C 语言还有一个突出的优点就是适合于多种操作系统, 如DOS、UNIX,也适用于多种机型。   C语言的优点很多,但是也存在一些缺点,如运算优先级太多,运算能力方面不像其它高级语言那样强,语法定义不严格等。但是这些都不能阻止C语言成为一门广受欢迎的计算机编程语言
Turbo C2.0 介绍   Turbo C2.0不仅是一个快捷、高效的编译程序,同时还有一个易学、易用的集成开发环境。使用Turbo C2.0无需独立地编辑、编译和连接程序,就能建立并运行C语言程序。因为这些功能都组合在Turbo 2.0的集成开发环境内,并且可以通过一个简单的主屏幕使用这些功能。 基本配置要求   Turbo C 2.0可运行于IBM-PC系列微机,包括XT,AT及IBM 兼容机。此时要求DOS2.0或更高版本支持,并至少需要448K的RAM,可在任何彩、单色80列监视器上运行。支持数学协处理器芯片,也可进行浮点仿真,这将加快程序的执行。 主要文件的简单介绍   INSTALL.EXE 安装程序文件   TC.EXE 集成编译   TCINST.EXE 集成开发环境的配置设置程序   TCHELP.TCH 帮助文件   THELP.COM 读取TCHELP.TCH的驻留程序README 关于Turbo C的信息文件   TCCONFIG.EXE 配置文件转换程序MAKE.EXE   项目管理工具TCC.EXE   命令行编译TLINK.EXE   Turbo C系列连接器TLIB.EXE   Turbo C系列库管理工具C0?.OBJ 不   同模式启动代码C?.LIB   不同模式运行库GRAPHICS.LIB   图形库EMU.LIB   8087仿真库FP87.LIB 8087库   *.H Turbo C头文件   *.BGI 不同显示器图形驱动程序   *.C Turbo C例行程序(源文件)   其中:上面的?分别为:T Tiny(微型模式)S Small(小模式)C Compact(紧凑模式)M Medium(中型模式)L Large(大模式)H Huge(巨大模式)
### 回答1: 在 TURBO C 2.0 中,您可以使用 biosdisk() 函数来格式化软盘。 下面是一段代码示例: ``` #include <stdio.h> #include <dos.h> int main() { // 定义扇区的大小 unsigned int sector_size[3] = {512, 512, 1024}; // 定义填充字节 unsigned char fill_char[3] = {0xF6, 0xF6, 0x48}; // 格式化磁道 700 的前三个扇区 for (int i = 0; i < 3; i++) { int result = biosdisk(2, 0, 70, 0, i + 1, 1, sector_size[i], fill_char[i]); if (result != 0) { printf("格式化扇区 %d 失败,返回码: %d\n", i + 1, result); } } return 0; } ``` 请注意,在使用 biosdisk() 函数之前,需要包含 dos.h 头文件。 希望这能帮到您! ### 回答2使用TURBO C 2.0语言,可以通过以下代码格式化软盘的70磁道0面,并分别格式化3个扇区,大小分别为512字节、512字节和1024字节。其中,前两个扇区使用F6填充,第三个扇区使用48填充。 ```c #include<stdlib.h> #include<stdio.h> #include<dos.h> void formatFloppyDisk(){ union REGS regs; regs.h.ah = 0x0;// To format a floppy disk, we set AH=0 regs.h.dl = 0;// Drive number (0=A, 1=B, etc.) regs.x.cx = 0;// Track number to format regs.h.dh = 0;// Head number regs.h.al = 0;// Sector size (0=default, 1=512 bytes, 2=1024 bytes, 3=2048 bytes etc.) int FILL_BYTE = 0;// The byte value to fill the sectors with during formatting int NUM_SECTORS = 3;// Number of sectors to format // To format 70th track 0th head regs.x.ax = 0x1301; // 0x13 = Reset disk system, 01H = Reset only specified drive int86(0x13, &regs, &regs); // BIOS interrupt to reset disk system for (int i=0; i<NUM_SECTORS; i++){ regs.x.ax = 0x3101; // 0x31 = Write Format, 01H = Format only current track regs.x.bx = 0x0001; // 0x00 = Drive A:, 01H = Head 1, 0 = Generate ID Field depending on the disk in the drive 1 = Keep the ID Field all zeros regs.x.cx = 0x0170; // Track number=70(0-79 range) regs.h.dh = 0x00; // Head number=0 or 1 regs.h.al = 0x02; // Control byte=always zero regs.x.dx = i+1; // Sector number starting from 1 regs.x.si = 0x0000; // segment and offset of read/write buffer regs.x.di = 0x0000; // segment and offset of result if(i == 2){ FILL_BYTE = 0x48; // Fill the third sector with 48 regs.x.ax = 0x3102; // 0x31 = Write Format, 02H = Format sequential tracks immediately following the one being formatted }else{ FILL_BYTE = 0xF6; // Fill the first two sectors with F6 } regs.h.ah = FILL_BYTE; // Fill the sector with specified byte int86(0x13, &regs, &regs); // BIOS interrupt to format the specified sector } } int main(){ formatFloppyDisk(); return 0; } ``` 上述代码使用了INT 0x13,即BIOS中断服务例程,来执行软盘格式化操作。通过设置寄存器的不同参数,可以指定要格式化的磁道、面、扇区大小和填充字节。在这个例子中,我们格式化了软盘70磁道0面的3个扇区,前两个扇区使用F6填充,第三个扇区使用48填充。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值