QNX system architecture 11 - Character I/O

来源:互联网 发布:mac屏保设置不生效 编辑:程序博客网 时间:2024/06/04 01:15

实时操作系统的一个关键性需求是高性能字符!/O

字符设备和块设备的一个重要区别:字符设备包含了字节流序列,串行传输;不同于块设备数据永久存在于介质上,此外字符设备的数据是临时生成的。

在POSIX和UNIX传统上,这些字符设备位于OS目录空间/dev/下。比如一个modem或者终端串口设备存在于

/dev/ser1

PC机上的典型硬件设备包括:

  • serial ports
  • parallel ports
  • text-mode consoles
  • pseudo terminal(ptys)

程序使用标准的open(), close(), read()和write() API函数访问字符设备。字符设备的其他功能,比如波特率,校验位,流控等使用其他的函数操作。

因为系统内存在多个字符设备,所以这些设备使用类似的驱动,库io-char用来最大化代码复用。

Figure 45: The io-char module is implemented as a library

如图中所示,io-char实现为一个库。io-char模块包含了所有支持POSIX语义代码。同时还包含大量非POSIX但是实时系统需要的功能。因为这些代码是公共的库函数,所有的驱动程序都继承了库函数中的功能。

驱动是调用io-char库的执行进程。操作时,驱动首先调用io-char。驱动本身和其他QNX进程类似,可以运行在不同的优先级上,进程优先级是由被控制的硬件以及client请求服务所决定的。

一旦字符设备运行,增加额外设备消耗的内存是很小的,因为仅仅实现新驱动数据结构是新加的。


Driver/io-char communication

io-char库管理应用和设备驱动之间的数据流。io-char和驱动间的数据流通过一组内存队列关联到每一个字符设备上。

每个设备有三个队列,每个队列实现机制为FIFO。

Figure 46: Device I/O in the QNX RTOS


接收的数据被驱动放在raw输入队列中,仅当应用程序请求数据时,io-char消耗input队列中的数据。

驱动的中断处理函数调用io-char中的一个函数把数据添加到队列中,这确保连续的数据输入规则并且最小化驱动的职责。

io-char模块放置输出数据到设备的output队列,驱动程序处理这些数据并传送到设备。每次增加新数据,模块调用驱动一个可信程序以便驱使驱动操作。因为使用输出队列,io-char为所有字符设备实现了延迟写。仅当输出buffer为满时,io-char才会促使当前进程阻塞在写操作上。

规范化序列完全由io-char管理,用来处理编辑模式的input数据,这个对立的尺寸决定特定设备可被编辑的最大字符数。

这些队列的大小是可以用命令行参数配置的。缺省值通常大于硬件最大可处理配置,但是你可以调整这些值:减少系统内存需求;适应不寻常的硬件需求,或者处理不寻常的协议请求。

设备驱动简单的增加接收数据到raw 输入队列,或者消耗和传输output队列数据。io-char模块决定输出传输何时挂起,接收的数据如何响应等。

Device control

低级设备控制使用devctl()调用实现。

POSIX终端控制函数通过调用devctl()实现:

  • tcgetattr()
  • tcsetattr()
  • tcgetpgrp()
  • tcsetpgrp()
  • tcsendbreak()
  • tcflow()

QNX Neutrino extensions

QNX扩展的终端控制API如下所示:

  • tcdropline()
  • tcinject()

io-char模块直接使用大部分驱动支持的devctl命令,应用程序通过io-char发送设备特定的devctl()给驱动。

Input modes

每一个设备可以在raw或者edited输入模式。

Raw input mode

在raw模式,io-char不会对收到的字符进行编辑。这减少了每个字符的处理工作,提供了读数据的最高性能接口。

全屏程序和串口通信程序是使用字符设备raw模式的例子。

在raw模式,中断处理函数把接收的字符存入raw input buffer。当一个应用从设备请求数据,它可以标识什么条件下输入请求被满足。直到条件满足,中断处理不会通知驱动运行,驱动也不会返回任何数据给应用程序。正常情况下,读应用阻塞直到至少一个字符可用。

下图演示了可用条件全集:

Figure 47: Conditions for satisfying an input request

当指定了多个条件,那么只需条件之一满足,读操作即满足。

  • MIN

当应用程序知道它所期望的字符数时,可以使用MIN。

如果知道每帧数据包含的字符数目,那么可以使用MIN来等待整帧数据的到达。这明显的减少了IPC和进程调度。MIN通常和TIME或TIMEOUT一起使用。MIN是POSIX标准的一部分。

  • TIME

条件TIME用于接收流数据,当应用接收流数据并且希望在数据停止和暂停时获得通知。暂停时间为1/10ths秒。TIME是POSIX标准的一部分。

  • TIMEOUT

条件TIMEOUT,当应用直到在接收数据超时前需要等待多久时使用。timeout单位是1/10ths秒

任何协议知道期望就收的每帧数据字符数,可以使用TIMEOUT。根据帧大小和波特率可以推算出数据何时到达。TIMEOUT可以用来检测字符丢失,也可以用在交互式程序中,如果在给定的时间内没有收到用户输入的响应。

TIMEOUT不是POSIX标准的一部分,是一个QNX扩展。

  • FORWARD

条件FORWARD在协议通过特殊帧字符分割时使用。比如,串口链路上的TCP/IP协议PPP使用帧字符作为起始和终结字符。如果和TIMEOUT一起使用,FORWARD可以极大的改善协议实现。协议处理收到的是整帧数据而不是一个个字符。对于丢失帧字符的情况,TIMEOUT和TIME可以用来快速恢复。

这极大的减小了IPC工作负载,导致给定的TCP/IP数据率下,更低的处理器利用率。如果没有FORWARD字符,实现只能每次读一个字符。

FORWARD是一个QNX扩展,并不是POSIX标准。

把应用通知推到OS服务提供部件,减少用户机处理发生的频率。这最小化系统中IPC通信量以及应用处理占用的CPU时间。此外如果应用实现的协议在不同的网络节点上执行,那么网络传输的数目也可以最小化。


Edited input mode

在edited模式,io-char在每一个接收字符上执行编辑操作。仅仅当一整行完全输入后(通常是收到一个回车符),行数据才会给应用处理。这个操作模式通常canonical,有时也称为cooked模式。

大部分非全屏应用运行在edited模式,因为这允许应用应用每次处理一行数据,而不是检查每个接收到的字符,直到扫描一个行结束符。

在编辑模式,每个字符被中断处理函数接收到raw input buffer。不像raw 模式驱动在某些输入条件满足时才调度驱动,编辑模式下,每接收到一个字符中断处理函数都会调度驱动。

这样做是有两个原因的。首先,edited模式很少用在高性能通信协议下。第二编辑工作很繁重,并不适合在中断处理函数中执行。

当驱动运行,io-char中的代码将检查字符然后保存到canonical buffer中,来构造一行数据。当一个数据完成并且应用请求输入,行数据从canonical buffer传输到应用程序,传输是直接从canonical buffer复制到应用buffer,并没有经过任何中转复制。

编辑模式代码可以正确处理canonical buffer中多个待定的输入行。并且允许部分行被读取。如果应用程序仅请求一个字符而实际有10字符的行存在。在这种情况下,下一次读操作将从上一次留下的数据开始读取。

io-char模块提供了提供了一组丰富的编辑能力,包括支持cursor键的移动,和修改,插入,删除字符等

Device subsystem performance

当设备在raw模式下,设备子系统的事件流被设计为最小化负载,最大化吞吐量。为了达到这个目标,需要使用如下规则:

  • 中断处理函数把接收到的数据直接放到内存队列中,仅当有读操作阻塞并且读操作可以满足,中断处理函数调度驱动运行。在其他情况下,中断仅仅直接返回。此外,如果io-char已经运行了,那么不需要有调度发生,因为可以观察到数据已经可用,无需进一步的通知。
  • 当一个读操作被满足,驱动从raw input buffer中复制数据到接收buffer中,来直接应答应用进程。最终是数据仅被复制一次。

这些规则,加上OS内部很小的中断和调度延迟,构成了非常简洁的模型,符合POSIX并且适合实时需求


Console devices

系统consoles(VGA兼容图形芯片在文本模式下)通过devc-con或者devc-con-hid驱动管理。video显示卡以及系统键盘合在一起作为物理console。

devc-con或者devc-con-hid驱动允许多个线程并行执行在物理console上,也就是虚拟consoles。devc-con console驱动进程典型的管理超过一组I/O队列到io-char,他们表现为一组字符设备/dev/con1, /dev/con2。从应用程序的角度看,有多个consoles可用。

当然,实际上只有一个物理console,在某个时间,仅有一个虚拟console可以显示,键盘被关联到当前可见的console

Serial devices

串口通信通道被devc-ser*驱动进程家族管理。这些驱动可以管理多个服务通道并且提供如下字符设备/dev/ser1, /dev/ser2

当devc-ser*被启动,命令行参数可以标识哪一个以及多少串口被安装,在PC兼容系统中,一般会有两个标准的串行端口:com1和com2。devc-ser*驱动直接支持大部分多端口串口卡。

QNX包括各种串口驱动(比如devc-ser8250)。更多的细节,参考参考手册中的dev-ser*

dev-ser*驱动支持硬件流控

Parallel devices

并行打印端口由devc-par驱动管理。当devc-par被启动时,命令行参数可以表示哪个并行端口被安装。

devc-par驱动是一个输出驱动,所以它没有raw input或者canonical input队列。output buffer的尺寸可以通过命令行控制。如果配置了一个较大的尺寸,就相当于软件print buffer的效果。

pseudo terminal devices(ptys)

pseudo终端是由devc-pty驱动管理的。

devc-pty命令行参数标识了要创建的pseudo terminal数目

伪终端pty是一对字符设备:主设备和从设备。从设备提供的接口是POSIX定义的tty设备接口。当然tty设备代表了硬件设备,pty从设备被另外一个线程通过伪终端的master部分控制它。也就是说,任何写到master设备的数据被作为从设备的输入。反之亦然。实际上所有从终端设备的输入都来自于伪终端主设备上的用户进程。

 Ptys一般用来创建伪终端接口程序,比如telent使用TCP/IP提供一个终端会话到远程系统。

0 0
原创粉丝点击