在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,但是可以根据系统需要进行修改。

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

内核的文件描述符表大小也可以通过编程的方式进行修改。rtpIoTablesizeGet()函数用于获取文件描述符表的大小,rtpIoTableSizeSet()函数用于对其进行修改。注意:这些函数在内核与RTP中均可使用(I/O系统将内核看做一类特殊的进程)。

3. RTP中的文件描述符表

在RTP中的文件描述符表的大小,定义了一个进程中可以同时打开的最大文件数量。该最大值是从其创建环境继承而来的。如果该进程由一个内核任务创建,那么新进程将继承内核任务的文件描述符表的最大值。

4.打开和关闭函数

在对一个设备执行I/O操作之前,必须使用open()或creat()函数打开一个文件描述符。open()函数所需的参数为:文件名、访问类型、文件权限。语法如下:


fd=open("name",flags,mode);

对于open()函数,参数mode是可选的,如果对文件权限并不关心,就可以将mode设置为0。

对于用户级与内核级调用,open()函数的flags参数可以指定为如下值:

VxWorks 7 System IO

VxWorks 7 System IO

在使用文件的访问与模式参数调用open()函数时,需要注意如下情况:

  1. 通常,仅能使用open()打开一个已经存在的设备和文件。然而,对于NFS、网络、dosFs和HRFS设备,可以通过带O_CREAT的标记使用open()函数。
  2. 可以使用open()函数打开HRFS目录,但是仅能使用O_RDONLY标志。
  3. 对于dosFs和NFS设备,可以使用O_CREAT标记和FSTAT_DIR模式创建一个子目录。dosFs将忽略其他mode参数。
  4. 对于HRFS设备,不能使用O_CREAT标记和FSTAT_DIR模式选项创建一个子目录。HRFS将忽略mode选项,仅创建一个普通文件。
  5. netDrv默认文件系统不支持F_STAT_DIR mode选项或O_CREAT标记。
  6. 对于NFS设备,open()的第三个参数通常用于指定文件模式。
  7. 尽管HRFS支持为一个文件设定权限模式,但是在VxWorks中并不这么使用。
  8. 文件可以使用O_SYNC标记打开,表明每次写操作都将立即把内容写到底层介质中。当前dosFs文件系统支持这个标记,可以用于同步FAT与目录条目。
  9. O_SYNC标记对HRFS文件系统不起作用,因为HRFS本身总是进行同步。HRFS总是更新文件,就好像O_SYNC标记被设置了一样。

注意:驱动或文件系统可能不会完全遵守flag值或mode值。如果驱动允许,一个按照O_RDONLY模式打开的文件实际上可能是可写的。

5. 创建和删除函数

面向文件的设备,除了能够打开已经存在的文件,还要能够创建和删除文件。

面向文件的设备可以使用creat()函数创建一个文件,并返回其文件描述符。creat()的参数与open()的参数类似,区别是creat()传入的文件名指向一个新文件,而open()传入的文件名指向的是一个已经存在的文件。

注意,在HRFS文件系统中,creat()函数是POSIX兼容的,其第二个参数用于指定文件权限;文件将按照O_RDWR模式打开。

对于dosFs,creat()函数不是POSIX兼容的,第二个参数用于指定打开模式标记。

remove()函数将删除文件系统中的一个命名文件。再删除文件之前,需要先关闭文件。

对于非文件系统设备,creat()函数与open()函数等效。remove()函数将不起作用。

6. 读和写函数

当通过open()或creat()函数得到一个文件描述符之后,可以调用read()或write()函数向文件中读取或写入数据。read()函数的参数包括:文件描述符、存放待读取数据的缓冲区地址,待读取数据的最大长度。

read()函数等待从指定文件读取数据,并返回实际读取到的字节数。对于一个文件系统设备,如果读取到的字节数比指定的字节数少,那么后续的read()调用将返回0,表明已经读取到文件的末尾。对于非文件系统设备,读取到的字节数可以比指定的大小要少,就算还有可读的数据也是允许的。后续的read()调用可能返回0.对于串口设备和TCP套接字,为了读取指定大小的数据,可能需要重复调用read()函数。读取失败时将返回ERROR(-1)。

write()函数的参数为:文件描述符,待写入数据的缓冲区地址,待写数据长度。语法如下:


actualBytes=write(fd,&buffer,nBytes);

write()函数保证在返回到调用函数之前,至少会将所有指定的数据缓存到输出缓冲区中,所以有可能数据还没有真正的写到设备中(因驱动而异)。write()函数返回写入的字节数大小;如果返回的大小不等于需要写入的大小,将返回错误。

RTP的read()和write()函数时POSIX兼容的。

7. 文件截断函数

有时需要丢弃文件中的一部分数据。当打开一个文件后,可以使用ftruncate()函数将文件截断为一个指定的大小。其参数为:文件描述符、期望的文件字节长度。语法如下:


status=ftruncate(fd,length);

如果截断成功,将返回OK。

如果一个文件描述符所指向的设备是不可截断的,那么ftruncate()将返回ERROR,并将errno设置为EINVAL。

如果指定大小比文件实际的大小还要大,其结果将取决于具体的文件系统。对于dosFs和HRFS,文件的大小将扩展到指定的大小然而,对于其他文件系统,ftruncate()将返回ERROR,并将errno设置为EINVAL。

ftruncate()函数时POSIX1003.1b标准的一部分。HRFS将完全支持,dosFs的实现则是部分兼容:创建和修改的次数不会改变。

对于HRFS,截断不会修改seek的位置,但是在dosFs中,seek的位置将被设置为文件末尾。

8. 使用select()等待多个文件描述符

VxWorks的select()函数提供了一种等待多个文件描述的方法(允许任务等待多个设备可用)。VxWorks的select()同UNIX和Windows是兼容的。

内核的selectLib库包括了select()和相关的函数,需要使用INCLUDE_SELECT组件。

对于RTP的select()函数,需要配置INCLUDE_IO_BASIC组件。

任务级的select()函数,不仅允许任务可以同时等待多个设备I/O,还允许任务制定等待多长时间。一个典型的例子就是客户端-服务器模型,服务器端同时等待多个文件描述符,以同时为本地和远端的客户端提供服务。服务器任务使用管道同本地客户通信,使用一个套接字同远端的客户端通信。服务器任务必须尽快响应客户端。如果服务器阻塞等待一个通信流,那么除非这个通信流被处理,否则其他通信流将得不到服务。select机制具有同时监控套接字和管道的能力,所以可以用于解决该问题。

任务将阻塞直到数据可用或设备可写。select()函数将在一个或多个文件描述符就绪或发生超时时返回。使用select()函数,任务可以制定等待哪些文件描述符的活动。在select()函数中使用位域指定感兴趣的读和写文件描述符。当select()函数返回时,位域将修改为反映当前哪些文件描述符可用。用于构建和操作位域的宏如下所示:

VxWorks 7 System IO

9. 在内核中使用select()

VxWorks 7 System IO

VxWorks 7 System IO

VxWorks 7 System IO

10. 在RTP中使用select()

VxWorks 7 System IO

VxWorks 7 System IO

VxWorks 7 System IO

11. POSIX文件系统函数

对于内核和RTP应用程序,VxWorks针对多种文件操作提供了相应的POSIX I/O和文件系统函数。如下所示:

VxWorks 7 System IO