开发QNX的主要目的是提供一个支持开放系统POSIX API,并且系统稳定,易于扩展为各种应用系统:小到资源有限的嵌入式系统,大到高端的分布式计算环境。QNX支持多个处理器家族,包括X86 ARM和powerPC。
对于实时性要求高的应用系统,架构健壮也是基本要求,OS可以灵活的完全控制MMU硬件。
当然,简单的设定这些目标并不能保证预期的结果。我们请你通读System Architecture 指南,这样可以对QNX实现方法,达到这些目标所采用的设计权衡。这样,当你完成本指南,相信你会认可QNX Neutrino是第一个真正符合开放系统标准,可扩展,高度稳定的OS产品。
如果按照当前最流行的做法来构建一个POSIX操作系统,你将会发现操作系统是UNIX,而UNIX对于嵌入式系统来说太庞大,有时并不适合。
实际POSIX并不等同于UNIX,尽管POSIX标准生根于UNIX,POSIX工作组把这个标准定义为:接口,而非实现。因此我们可以认为POSIX是一个实现标准,而UNIX OS是POSIX标准的一个实现。
感谢POSIX标准中的精确描述以及POSIX测试套,使得不采用传统UNIX内核的操作系统也可以提供POSIX API,比如Linux,QNX。比较这些POSIX操作系统,我们会发现他们在外表上非常相似,有同样的接口函数,工具集。但是当我们深窥这些系统的内部实现,性能以及稳定性,有可能千差万别,这都归于内部架构的不同。
尽管QNX采用non-UNIX架构,QNX实现了标准的POSIX API。通过采用微内核架构,OS发布API的方式也变得非常灵活,可以根据需求增加和删减API。
在微内核OS基础上,可以通过包含或者排除提供功能的特定进程,定制需要的实时系统。
产品开发通常采用创建Product line的形式,一个包含全功能的OS,而不是对产品的每一个操作系统版本进行定制,开发者使用微内核可以很容易按需定制系统:增加文件系统,网络,图形用户接口以及其他技术。
这种扩展方法的优点包括:
可移植的应用代码
公用工具可用来开发整个产品线
开发团队经验技术可项目复用
减少上市时间
实时应用开发面临的一个问题:大多数实时操作系统倾向于提供私有API。由于缺乏产业标准,使用私有API反而是一个常见现象,对实时系统市场的调查显示存在很多小作坊式私有操作系统。而POSIX提供了整合这个市场的良机。
在POSIX标准中,大部分嵌入式系统开发者感兴趣的是如下标准:
1003.1 定义了进程管理API,设备I/O,文件系统I/O以及基本IPC。这个标准包含了一个UNIX OS的基本功能,对于大部分应用,这是最有用的标准。从C语言开发的角度来看,ANSI X3J11 C可以看做基本点,而进程管理,文件,tty设备等方便则不在ANSI C描述之内。
Realtime Extensions - 在1003.1标准基础上,定义了一组实时扩展。这些扩展包括信号量,进程调度优先级,信号实时扩展,高分辨率timer控制,增强IPCL原语,同步和异步I/O,以及实时连续文件支持建议。
Threads - 进一步扩展了POSIX环境,包括:给定地址空间内,多线程的创建和管理。
Additional Realtime Extensions - 进一步定义了实现标准。诸如attaching interrupt handlers得到了描述。
Application Environment Profiles - 定义了几个POSIX环境AEPs (Realtime AEP, Embedded Systems AEP等等),适用不同的嵌入式应用场景。这些profiles定义了嵌入式OSs拥有的能力。
采用产业标准,除了赶潮流的动机,在嵌入式实时领域采用POSIX标准还有几个特定好处:
Multiple OS sources
硬件制造商不愿意选择单一来源的硬件部件,因为这种部件可能有断货的可能。同样的道理,制造商不愿使用封闭的私有OS,因为这会导致他们的应用源码无法移植到其他平台。
而对于符合POSIX标准的应用,开发者可以受用来自多个厂商的OS,开发者可以轻易把应用移植到遵守POSIX的操作系统之上。
Portability of development staff
在嵌入式开发过程中,使用通用API,编程人员的一个实时系统经验可以运用到其他项目中,即便使用不同的处理器和操作系统。此外,有UNIX和POSIX经验的程序员可以很容易转到嵌入式实时系统,因为他们对实时系统API的非实时部分已经非常熟悉了。
Development environment
即便在交叉编译环境中,API也和嵌入式系统保持一致。无论host使用什么操作系统(linux, Windows, ...)或者target是什么平台(x86, ARM),程序员不需要担心平台特定的endian,对齐和IO问题。
操作系统的主要责任是管理计算机资源,系统中的所有活动:调度应用程序,写文件到磁盘,发送数据到网络等,都应尽可能无缝的和透明的执行。
某些环境下要求严格的资源管理和调度请求。比如实时应用场景,需要操作系统能够处理多个事件,并且确保操作系统能够在指定时间内对事件作出响应。OS响应越好,留给应用在deadlines时间越多。
QNX Neutrino实时系统对于嵌入式实时应用是一个理想选择。QNX可以被裁剪到很小的尺寸,并且提供多任务,线程,优先级驱动的抢占式调度,以及快速的上下文切换 – 其拥有实时操作系统必备的特质。此外,OS用标准POSIX API提供这些能力,并没有为了达到一个小系统而放弃POSIX标准。
QNX Neutrino也非常灵活。开发者很容易定制OS满足他们的应用。从几乎空架子的微内核配置加几个小模块,到全功能的网络系统服务数百个用户,自由的定制系统,仅使用哪些需要的功能
QNX Neutrino通过两个基本原则,达到了独一无二的有效,模块和简洁。
微内核构架
基于消息的进程键通信
时髦词通常从流行到不流行,开发商热衷于使用时下的时髦词来命名他们的产品,而不管这个词是否适合产品。
术语microkernel已经变得很流行,尽管很多新操作系统声称是"microkernels"(甚至号称nanokernels),这个术语光从字面并不算是很清晰的定义。
让我们尝试定义下microkernel。一个microkernel OS是一个小的内核,提供了最小集和的服务,最小服务集被一些可选的进程使用。可选进程提供的更高级别的OS功能。microkernel本身并不包含文件系统和其他传统OS包含的服务;QNX通过可选进程提供这些服务。
设计一个microkernel OS并不是简单的让OS变小。一个microkernel OS应该包含OS方法调用的变化。模块化是关键特点,尺寸反而不重要,如果仅仅因为一个kernel尺寸比较小就称之为microkernel,显然不复合这个特点。
microkernel提供的IPC服务用来把OS粘合在一起,这些服务的性能和灵活性决定了OS整体的性能。除了这些IPC服务,microkernel几乎是实时执行的,不管是提供的服务还是他们的实时性能。
microkernel把一个执行划分为IPC services和服务提供进程。OS是由一组microkernel管理的线程实现的,用户程序可以作为普通应用程序,也可以是OS的功能扩展,供其他应用程序使用。OS本身就变得开放可扩展的。此外,用户实现的OS扩展并不会影响core OS的稳定性。
某些实时系统在实现POSIX 1003.1标准遇到一个困难是,这些实时系统使用单进程,多线程模型,线程之间没有内存保护机制。这样的实时系统仅仅是POSIX多进程模型的一个子集,不能支持fork()函数调用。而QNX neutrino则完全利用MMU,完整的实现了POSIX进程模型。
下图显示了一个真正的microkernel提供的完全内存保护,不仅仅是用户态应用,而且包括了OS components(device drivers, filesystems等)。
QNX neutrino RTOS包含了一个microkernel,以及被microkernel管理的一组合作进程。
像下图所示,OS结构看起来更像一个team,而不是hierarchy,
QNX Nentrino做为一个软件总线,使得用户可以动态加载和移除 OS模块。
内核是操作系统的心脏。在某些系统中,kernel包含了很多功能,几乎就是整个操作系统的实现。
但是我们的微内核是一个真正的内核,首先像一个实时执行kernel,尺寸非常小;其次,它仅仅包含非常少的基本功能:
thread services – 通过POSIX 线程创建
signal services – 通过POSIX signal实现
message-passing services - 处理整个系统中所有系统间的message
synchronization services – 通过POSIX thread-synchronization实现
scheduling services - microkernel使用各种POSIX实时调度算法,调度线程执行。
timer services - microkernel提供了丰富的POSIX timer服务
process management services – 微内核和进程管理器组成一个单元(称为procnto)。进程管理器部分负责管理进程,内存和路径名空间。
和进程不同,Microkernel本身从来不会调度执行。当一个kernel调用,异常或者硬件中断发生时,处理器执行微内核代码。
所有的OS服务(除了由microkernel/process manager module),是通过standard processes处理的。
一个配置较全的系统可以包括如下系统进程:
filesystem managers
character device managers
native network manager
TCP/IP
系统进程本质上很难和用户程序区分,他们使用相同的public API和kernel 服务。
正是这个架构给了QNX空前的可扩展性。因为大部分OS services是以标准系统进程的方式提供,所以只需写新程序即可提供新的OS服务。
实时上,操作系统和应用程序的边界已经变得非常模糊,系统服务和应用程序之间唯一真正的区别是OS服务管理客户端的资源。
比如你写了一个database server, 那么如何划分这个database server呢?
如同filesystem接收open read write(via message)请求一样,database server从客户端接收到数据库访问请求。filesystem和database server都向客户端提供了访问资源API。并且都是独立的进程,可以由客户端用户实现,以及按需启动和停止。
因此,一个database server可以被看做一个system process,也可以被看做一个application。不过真的无所谓了!重要的是OS允许修改OS标准部件前提下,实现该进程。对于定制嵌入式系统的开发者来说,可以不访问OS源码,就能扩展OS的功能给他们的特定应用。
设备驱动程序允许OS和应用程序以通用方式(例如,磁盘驱动器,网络接口)使用底层硬件。虽然大多数操作系统要求设备驱动程序紧密绑定到操作系统本身,但QNX Neutrino的设备驱动程序可以作为标准进程启动和停止。 因此,添加设备驱动程序不会影响操作系统的任何其他部分 - 驱动程序可以像任何其他应用程序一样进行开发和调试。
当多个线程同时运行时(如在典型的实时多任务环境中),操作系统必须提供允许它们相互通信的机制。
进程间通信(IPC)是将应用程序设计为一组协作进程的关键,其中每个进程处理一个明确定义的整体部分。
OS提供简单 强大的一组IPC能力,可以简化应用的协同进程的开发工作。
QNX Neutrino是第一个利用消息传递作为IPC基本手段的商业操作系统。 操作系统的大部分功能,简洁性和优雅性使其在整个系统中完全集成了消息传递方法。
在QNX Neutrino,消息是从一个进程传送到另一个进程的bytes。OS本身并没有赋予消息任何特定的含义,只有消息的发送者和接收者理解消息中数据的含义。
消息传递不仅允许进程间传送数据,而且也提供了进程执行的一种同步方式。当进程发送,接收和响应消息时,进程经历了各种状态变化,这影响了进程何时运行,以及运行多久。知道他们的状态和优先级,microkernel可以有效的调度所有进程,充分利用CPU资源。信息传递这个简单,一致性的方法因此持续的影响整个系统运行。
实时和其他关键任务应用,通常需要一个可信赖的IPC,因为构成这些应用的进程是强相关的。
QNX Neutrino消息传递施加的规则使得应用程序更可靠。
最简单的形式,本地局域网为几个内部互联计算机,提供了共享文件和外设的机制。QNX Neutrino远不止这个简单概念,它集成整个网络到一个单一的,同质资源集合。
网络中任意机器的任意线程可以直接使用其他任何机器的任何资源。从应用程序的角度,本地和远程资源并没有区别。因此应用程序也不需要特别处理来使用远程资源。
用户可以在网络上任意位置访问文件,使用任意的设备,在网络上任意机器上运行应用程序。处理器可以使用一致的方法和网络中的设备通信。OS中无处不在的消息传递是由IPC机制保证流畅,透明的网络。
QNX Neutrino从头开始设计为网络操作系统。
在某些方面,原生QNX Neutrino网络感觉更像是一台大型计算机而不是一组单独的微型计算机。用户只需知道可供任何应用程序使用的大量资源。但与大型机不同,QNX Neutrino提供了高度响应的环境,因为每个节点都可以提供适当的计算能力,以满足每个用户的需求。
例如,在任务关键型环境中,控制实时I / O设备的应用程序可能需要比其他不太关键的应用程序(如Web浏览器)更高的性能。该网络的响应能力足以同时支持这两种类型的应用程序 - 操作系统可让您在需要时随时随地将计算能力集中在硬实时系统中的设备上,而不会牺牲与桌面的并发连接。此外,实时计算的关键方面(如优先级继承)可在QNX Neutrino网络中无缝运行,无论采用何种物理介质(交换结构,串行等)。
QNX Neutrino网络可以使用各种硬件和行业标准协议组合在一起。 由于这些对应用程序和用户完全透明,因此可以随时引入新的网络架构而不会干扰操作系统。
为网络中的每个节点分配一个唯一名称,该名称将成为其标识符。此名称是确定操作系统是作为网络运行还是作为独立操作系统运行的唯一可见方法。
这种透明度是QNX Neutrino消息传递架构独特能力的又一个例子。 在许多系统中,诸如网络,IPC甚至消息传递等重要功能都建立在操作系统之上,而不是直接集成到其核心中。 结果通常是一个笨拙,低效的“双标准”接口,因此进程之间的通信是一回事,而穿透神秘单片内核的私有接口则是另一回事。
与单片系统相比,QNX Neutrino的基础是有效通信是有效运行的关键。 消息传递因此构成了我们的微内核架构的基石,并提高了整个系统中所有进程之间所有事务的效率,无论是跨越PC背板还是跨越一英里的双绞线。
源文件:《The Philosophy of the QNX Neutrino RTOS》