5.3.4 用户空间的I/O软件

尽管大部分I/O软件都在操作系统内部,但是仍然有一小部分在用户空间,包括与用户程序连接在一起的库,甚至完全运行于内核之外的程序。系统调用(包括I/O系统调用)通常由库过程实现。当一个C程序包含调用


count=write(fd,buffer,nbytes);


时,库过程write将与该程序连接在一起,并包含在运行时出现在内存中的二进制程序中。所有这些库过程的集合显然是I/O系统的组成部分。

广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元

虽然这些过程所做的工作不过是将这些参数放在合适的位置供系统调用使用,但是确有其他I/O过程实际实现真正的操作。输入和输出的格式化是由库过程完成的。一个例子是C语言中的printf,它以一个格式串和可能的一些变量作为输入,构造一个ASCII字符串,然后调用write以输出这个串。作为printf的一个例子,考虑语句


printf("The square of%3d is%6d\n",i,i *i);


该语句格式化一个字符串,该字符串是这样组成的:先是14个字符的串“The square of”(注意of后有一个空格),随后是i值作为3个字符的串,然后是4个字符的串“is”(注意前后各有一个空格),然后是i2 值作为6个字符的串,最后是一个换行。

对输入而言,类似过程的一个例子是scanf,它读取输入并将其存放到一些变量中,采用与printf同样语法的格式串来描述这些变量。标准的I/O库包含许多涉及I/O的过程,它们都是作为用户程序的一部分运行的。

并非所有的用户层I/O软件都是由库过程组成的。另一个重要的类别是假脱机系统。假脱机(spooling)是多道程序设计系统中处理独占I/O设备的一种方法。考虑一种典型的假脱机设备:打印机。尽管在技术上可以十分容易地让任何用户进程打开表示该打印机的字符特殊文件,但是假如一个进程打开它,然后很长时间不使用,则其他进程都无法打印。

另一种方法是创建一个特殊进程,称为守护进程(daemon),以及一个特殊目录,称为假脱机目录(spooling directory)。一个进程要打印一个文件时,首先生成要打印的整个文件,并且将其放在假脱机目录下。由守护进程打印该目录下的文件,该进程是允许使用打印机特殊文件的惟一进程。通过保护特殊文件来防止用户直接使用,可以解决某些进程不必要地长期空占打印机的问题。

假脱机不仅仅用于打印机,还可以在其他情况下使用。例如,通过网络传输文件常常使用一个网络守护进程。要发送一个文件到某个地方,用户可以将该文件放在一个网络假脱机目录下。稍后,由网络守护进程将其取出并且发送出去。这种假脱机文件传输方式的一个特定用途是USENET新闻系统,该网络由世界上使用因特网进行通信的成千上万台计算机组成,针对许多话题存在着几千个新闻组。要发送一条新闻消息,用户可以调用新闻程序,该程序接收要发出的消息,然后将其存放在假脱机目录中,待以后发送到其他计算机上。整个新闻系统是在操作系统之外运行的。

图5-17对I/O系统进行了总结,给出了所有层次以及每一层的主要功能。从底部开始,这些层是硬件、中断处理程序、设备驱动程序、与设备无关的软件,最后是用户进程。

阅读 ‧ 电子书库
图 5-17 I/O系统的层次以及每一层的主要功能

图5-17中的箭头表明了控制流。例如,当一个用户程序试图从一个文件中读一个块时,操作系统被调用以实现这一请求。与设备无关的软件在缓冲区高速缓存中查找有无要读的块。如果需要的块不在其中,则调用设备驱动程序,向硬件发出一个请求,让它从磁盘中获取该块。然后,进程被阻塞直到磁盘操作完成。

当磁盘操作完成时,硬件产生一个中断。中断处理程序就会运行,它要查明发生了什么事情,也就是说此刻需要关注哪个设备。然后,中断处理程序从设备提取状态信息,唤醒休眠的进程以结束此次I/O请求,并且让用户进程继续运行。