异步输入输出允许在执行输入输出操作的同时并发地执行原始任务。在任务与I/O操作在逻辑上是相互独立的情况下,可以使用AIO将I/O操作从任务中分离出来。VxWorks的AIO实现符合POSIX1003.1标准。

AIO的可以带来更高的处理效率:它允许在资源可用时进行I/O操作,而不用等待相关事件完成。AIO避免了 同步I/O中的一些不必要的任务阻塞,从而减少了I/O与内部处理之间对资源的竞争,同时也提高了吞吐量。

VxWorks配置

为了使用AIO,需要添加INCLUDE_POSIX_AIO和INCLUDE_POSIX_AIO_SYSDRV组件。第二个组件使能了辅助AIO系统驱动,当前所有的VxWorks设备都需要这个驱动以进行AIO操作。

POSIX AIO函数

VxWorks的aioPxLib库提供了POSIX AIO函数。为了异步访问一个文件,可以使用open()函数打开该文件。然后使用open()返回的文件描述符调用AIO函数。POSIX AIO函数(包括两个非POSIX函数)如下表所示:

VxWorks 7 System IO

当VxWorks配置了INCLUDE_POSIX_AIO之后,内核初始化代码将自动条用aioPxLibInit()函数。aioPxInit()函数使用MAX_LIO_CALLS作为其唯一参数。当MAX_LIO_CALLS配置参数被设置为0(默认为0),将会使用AIO_CLUST_MAX宏,该宏的值在privateaioPxLibP.h中定义为100。

VxWorks还提供了其他内核格式化I/O功能。

1. 使用串行I/O轮询模式输出:kprintf()

kprintf()按照printf()相同的方式进行格式化输出,区别在于kprintf()是按照轮询的方式向目标串口输出字符。该函数主要用于系统调试,可以在系统启动过程中(中断使能或I/O系统初始化之前)或在ISR中使用,这些都是printf()无法实现的。该函数由INCLUDE_DEBUG_KPRINTF组件提供。

kputs()提供了类似的功能,只是不能格式化输出。该函数由INCLUDE_DEBUG_KPUTS组件提供。

可选的组件INCLUDE_DEBUG_KWRITE_USER可用于实现输出到存储介质中。

内核函数kprintf()和kputs()可以用于向用户自定义的存储介质中写入数据(如FLASH)。

下面的函数展示了如何向用户预留的内存中写入数据。

VxWorks 7 System IO

执行如下步骤以使用该函数:

(1) 将代码添加到一个C文件中;

(2) 使用合适的BSP创建一个VIP项目;

(3) 将这个C文件添加到VIP中;

(4) 为项目添加如下组件:

在VxWorks中,基础I/O是最底层的I/O。基础I/O的接口同标准C库中的I/O原语是源码级兼容的。最基础的I/O调用有7个,如下图所示。

VxWorks 7 System IO

1. 文件描述符

在基础I/O层级,文件通过文件描述符引用。一个文件描述符是一个由open()或creat()函数返回的整数。其他I/O调用使用一个文件描述符作为参数,以操作某个特定的文件。

文件描述符不是全局的。内核与RTP均有其独有的文件描述符集合。内核中的任务或某个任务中的子任务将共享文件描述符。例如:

  1. 如果任务A和任务B运行在进程foo中,然后它们均使用write()函数对文件描述符7进行操作,那么它们将对同一个文件(设备)进行写操作。
  2. 如果一个进程bar与进程foo独立运行(bar不是foo的孩子),然后进程bar的任务X和任务Y使用文件描述符7进行write()操作,那么这个文件将与进程foo的任务A和任务B所操作的文件描述符7指定的文件不同。
  3. 如果进程foobar由进程foo创建,然后进程foobar的任务M和任务B分别调用write()对文件描述符7进行操作,那么它们所操作的文件将同进程foo中的任务A和任务B按照文件描述符7操作的文件相同。然而,如果任务将该文件关闭了,后续再次打开文件描述符7时,该文件描述符将指向另外的文件。

当文件打开时,将分配并返回一个文件描述符;当文件关闭时,文件描述符将被释放。

2. 内核中的文件描述符表

内核中可用的文件描述符数量由宏NUM_FILES定义。这个数量也定义了文件描述符表的大小,该表控制了同时可以使用多少个文件描述符。默认大小是50,但是可以根据系统需要进行修改。

为了避免用尽文件描述符,导致创建文件时出现错误,应用程序应该在不再使用一个文件描述符时将其关闭。

VxWorks提供了一个完全支持ANSI C的标准I/O包(stdio.h),因此与Unix和Windows的标准I/O包兼容。

1. VxWorks配置标准I/O

对于VxWorks内核,主要的传统标准I/O函数由一个VxWorks组件提供,少数的函数由其他组件提供。这种模块化的方法使系统仅包含常用的函数功能组件,从而降低对系统内存的占用。

如下组件提供了标准的I/O函数:

  1. INCLUDE_ANSI_STDIO:提供ANSI标准I/O函数。
  2. INCLUDE_FORMATTED_IO:提供fioLib库(非缓冲的),包括了非ANSI标准的I/O函数,如oprintf()和fdprintf()。

fioLib中的函数不适用由标准I/O库ansiStdio所提供的缓冲I/O机制。所以就算VxWorks中没有包括ansiStdio库,也可以使用fioLib中的函数。

2. 关于标准I/O和缓冲

当应用程序执行很多小数据量的读写操作时,使用由标准I/O提供的带缓冲的I/O函数将比基础的不具备缓冲的I/O函数有更好的性能。

尽管VxWorks I/O系统是高效的,但是对于每个低层次调用(基础I/O)还是存在一些问题。首先,I/O系统从设备独立的用户调用(read()、write())需要转换到与该调用对应的设备相关函数上。其次,当一个设备驱动同时被多个用户调用时,驱动需要执行互斥或队列操作。

因为VxWorks原语执行非常快,所以这些问题影响较小。然而,如果应用程序每次只从文件中读取一个字符,那么还是会放大这些问题所带来的影响。例如按照如下方式调用read:

1.VxWorks I/O系统

VxWorks I/O系统可以为任何类型的设备提供简单、统一、与设备独立的管理接口。这些设备包括:

  1. 字符设备:如终端或通信线路;
  2. 随机访问块设备:如磁盘;
  3. 虚拟设备:如任务间的管道pipes和sockets;
  4. 监控设备:如数字和模拟I/O设备;
  5. 网络设备:如可进行远程访问的设备;

VxWorks I/O系统为基础I/O与带缓冲的I/O均提供了标准的C库。基础I/O库与Unix兼容;带缓冲的I/O库与ANSI兼容。

内核I/O

因其独特的设计,使得VxWorks I/O系统比大多数的其他I/O系统更快、更灵活。这对实时系统是一个很重要的属性。

下图展示了VxWorks内核I/O系统中不同元素之间的关系。除了文件系统函数与网络元素之外,其余元素具有进行描述。

VxWorks 7 System IO

I/O系统与RTP应用程序

下图展示了可供RTP使用的VxWorks I/O系统元素之间的关系。后续将对这些元素进行描述。

VxWorks 7 System IO

VxWorks I/O与主机系统I/O之间的区别