QNX资源管理器
QNX相关历史文章:
1. Introduction
QNX Neutrino允许用户编写进程充当资源管理器,并且可以动态的启动和停止。这样的好处是可以降低系统在运行时的内存需求,并且可以灵活的应对定制化嵌入式系统中的各种设备。
资源管理器通常负责向各类设备提供接口,这些设备可能涉及管理实际的硬件设备(比如串口、并口、网卡或磁盘驱动器)或虚拟设备(比如/dev/null
、网络文件系统、伪ttys等)
在其他操作系统中,这个功能通常与设备驱动程序相关联,与设备驱动程序不同的是资源管理器不需要与内核进行耦合,看起来更像是用户级程序。
2. What is a resource manager?
资源管理器是用户级的服务器程序,它接收来自其他程序的请求服务,并可选的与硬件进行通信。QNX Neutrino强大和灵活的本地IPC机制,可以让资源管理器与内核解耦合。
由于QNX Neutrino是一个分布式微内核操作系统,几乎所有非内核功能都由用户可安装的程序提供,因此客户端程序与资源管理器之间需要一个定义清晰与良好的接口,并对资源管理器的功能进行文档化。
在路径名空间映射中,进程管理器会将路径名和资源管理器进行映射绑定,比如串口可以由资源管理器devc-ser*
管理,但是实际的路径名空间中名称为dev/ser1
,可以通过打开dev/ser1
来获取串口服务。
2.1 Why write a resource manager?
编写一个资源管理器有以下几个原因:
- 客户端使用POSIX接口与资源管理器通信;
- 可以减少接口类型的数量,当有很多服务器进程时,将服务器进程都编写成资源管理器,可以最大化减少客户端需要使用的接口数量;
- 可以使用命令行工具与资源管理器通信,比如
cat /proc/my_status
,也可以使用命令去测试驱动程序;
2.2 The types of resource managers
一般可以将资源管理器分为两类:
- 设备资源管理器
- 文件系统资源管理器
-
设备资源管理器
设备资源管理器只在文件系统中创建单个文件条目,每个条目都向进程管理器注册,每个名称通常代表一个设备。 -
文件系统资源管理器
文件系统资源管理器会向进程管理器注册一个挂载点,挂载点是注册到进程管理器中的路径的一部分。路径的其他部分由文件系统资源管理器管理。比如挂载点是/mount
,路径是/mount/home/thomasf
,由进程管理器来标识/mount
,而由文件系统管理器来标识home/thomasf
。
2.3 Communication via native IPC
当一个资源管理器绑定好对应的路径名后,它便可以收到客户端的请求信息了,比如io_open
、io_read
等。
客户端程序与资源管理器之间的所有通信都是通过本机IPC消息传递完成的,它有许多独特的功能:
- 定义良好的应用程序接口,客户端与资源管理器分工明确;
- 资源管理器的接口简单,与OS交互也是通过本地IPC,不需要担心其他模块的影响;
- 网络传递,底层原生IPC机制本质是网络分布式的,程序可以无缝的访问网络中其他节点的资源;
所有QNX Neutrino的设备驱动程序和文件系统都是作为资源管理器实现的,这意味着“原生”QNX Neutrino设备驱动程序或文件系统能做的一切,用户编写的资源管理器也能做到。
3. Resource manager architecture
资源管理器的核心如下:
initialize the dispatch interface
register the pathname with the process manager
DO forever
receive a message
SWITCH on the type of message
CASE io_open:
perform io_open processing
ENDCASE
CASE io_read:
perform io_read processing
ENDCASE
CASE io_write:
perform io_write processing
ENDCASE
. // etc. handle all other messages
. // that may occur, performing
. // processing as appropriate
ENDSWITCH
ENDDO
资源管理器架构包括三部分:
- 创建一个通道,以便客户端程序可以连接到资源管理器上,并发送消息;
- 资源管理器需要向进程管理器注册路径名,以便能在对该特定的路径名请求打开时,能解析到该资源管理器;
- 接收并处理消息;
每个资源管理器都需要消息处理功能(上文代码中的switch/case
部分),QNX Neutrino提供了一组库函数来方便的处理这个功能,当然也能处理其他关键功能。
3.1 Message types
资源管理器会收到两种类型的消息:
- connect messages,客户端在操作路径名时(比如
io_open
)时会发送连接消息,这可能会涉及到权限检查(客户端是否有打开设备的权限),并为该请求设置上下文; - I/O messages,基于上下文(客户端和资源管理器之间创建的)来发送I/O消息,比如
io_read
;
3.2 The resource manager shared library
QNX Neutrino提供了一下共享库,可以让资源管理器编写变得相对简单一点。
- 自动默认消息处理
当资源管理器不想处理某些消息时,可以使用默认的动作,目前有两个级别的默认动作:
- 给客户端返回
ENOSYS
,表明不支持特定功能; -
iofunc_*()
共享库,允许资源管理器自动处理多种功能;
由于资源管理器接收的大量消息都处理一组公共属性,iofunc_*
共享库允许资源管理器自动处理stat()
、chmod()
、chown()
、lseek()
等函数,无需再编写额外代码。有三个主要的结构需要考虑: - context,保存每次打开时使用的数据,例如文件中的当前位置(
lseek()
偏移量); - attributes structure,保存每个设备的数据,例如设备所有者的用户和组ID、最后修改时间等;
-
mount structure,对于文件系统管理器来说,需要mount structure,包含对整个挂载设备都可全局访问的数据项;
A resource manager is responsible for three data structures
当有多个客户端程序在特定资源上打开多种设备时,数据结构如下图:
Multiple clients opening various devices
iofunc_*()
默认函数的运行假设是:使用了context块和attribute结构的默认定义,这是一个可靠的假设,原因有二:
- 默认的context和attribute结构为大多数应用程序提供了足够的信息;
- 如果默认结构没有包含足够的信息,它们可以封装在自定义的结构中;
在自定义数据结构时,需要把attribute的结构放在前边,以便iofunc_attr_t *()
函数能使用,如下图:
图片.png
-
资源管理器共享库提供了跟踪
open()/dup()/close()
消息的默认处理函数,并且只对最后一个close
执行操作; -
多线程处理
QNX Neutrino提供多线程,可以基于这个来构造资源管理器,多个线程等待消息并同时处理它们。资源管理器共享库不仅可以跟踪创建的线程数量和等待线程的数量,还负责维护最佳的线程数量。 -
dispatch功能
操作系统提供一套`dispatch*函数集,可用于:
- 给需要多种消息类型的资源管理器和客户端提供一个公共阻塞点;
- 给没有绑定到资源管理器的消息类型提供灵活的接口;
- 在线程中将阻塞和处理代码解耦合;
- Combine messages
QNX支持将IO消息或connect消息组合成一个消息,从而进行一些类似原子性的操作。比如通过将io_lseek
和io_read
消息组合成一个消息,资源管理器在收到这个消息时,readblock()
函数就会允许线程去原子性的执行lseek()
和read()
操作。