|
4 | 4 | 本节导读 |
5 | 5 | ------------------------------------------- |
6 | 6 |
|
7 | | -本节我们介绍为何要把标准输入/输出用文件来进行抽象,以及如何以文件和文件描述符概念来重新定义标准输入/输出,并在进程中加入文件描述符表,同时将进程对于标准输入输出的访问的修改为基于文件抽象的接口实现。这主要是为下一节支持进程间信息传递的管道实现奠定了基础。由于管道是基于文件抽象接口来实现的,所以我们将首先对 **一切皆是文件** 的设计思路进行介绍。 |
| 7 | +本节我们介绍为何要把标准输入/输出用文件来进行抽象,以及如何以文件和文件描述符概念来重新定义标准输入/输出,并在进程中把各种文件描述符组织到文件描述符表中,同时将进程对于标准输入输出的访问修改为基于文件抽象的接口实现。这主要是为下一节支持进程间信息传递的管道实现打下基础。由于管道是基于文件抽象接口来实现的,所以我们将首先对 **一切皆是文件** 的设计思路进行介绍。 |
8 | 8 |
|
9 | 9 | 一切皆是文件 |
10 | 10 | ------------------------------------------- |
11 | 11 |
|
12 | 12 | .. chyyuu 可以简单介绍一下文件的起源??? |
13 | 13 |
|
14 | | -在UNIX操作系统之前,大多数的操作系统提供了各种复杂且不规则的设计实现来处理各种I/O设备(也可称为I/O资源),如键盘、显示器、以磁盘为代表的存储介质、以串口为代表的通信设备等,使得应用程序开发繁琐且很难统一表示和处理I/O设备。随着UNIX的诞生,一个简洁优雅的I/O设备的抽象出现了,这就是 **文件** 。在 UNIX 操作系统中,”**一切皆文件**“ (Everything is a file) 是一种重要的设计思想,这种设计思想继承于 Multics 操作系统的 **通用性** 文件的设计理念,并进行了进一步的简化。在本章中,应用程序看到并被操作系统管理的 **文件** (File) 就是一系列的字节组合。操作系统不关心文件内容,只关心如何对文件按字节流进行读写的机制,这就意味着任何程序可以读写任何文件(即字节流),对文件具体内容的解析是应用程序的任务,操作系统对此不做任何干涉。例如,一个Rust编译器可以读取一个C语言源程序并进行编译,操作系统并并不会阻止这样的事情发生。 |
| 14 | +在UNIX操作系统之前,大多数的操作系统提供了各种复杂且不规则的设计实现来处理各种I/O设备(也可称为I/O资源),如键盘、显示器、以磁盘为代表的存储介质、以串口为代表的通信设备等,使得应用程序开发繁琐且很难统一表示和处理I/O设备。随着UNIX的诞生,一个简洁优雅的I/O设备抽象出现了,这就是 **文件** 。在 UNIX 操作系统中,”**一切皆文件**“ (Everything is a file) 是一种重要的设计思想,这种设计思想继承于 Multics 操作系统的 **通用性** 文件的设计理念,并进行了进一步的简化。在本章中,应用程序访问的 **文件** (File) 就是一系列的字节组合。操作系统管理文件,但操作系统不关心文件内容,只关心如何对文件按字节流进行读写的机制,这就意味着任何程序可以读写任何文件(即字节流),对文件具体内容的解析是应用程序的任务,操作系统对此不做任何干涉。例如,一个Rust编译器可以读取一个C语言源程序并进行编译,操作系统并并不会阻止这样的事情发生。 |
15 | 15 |
|
16 | 16 |
|
17 | | -有了文件这样的抽象后,操作系统内核就可把能读写的I/O资源按文件来进行管理,并把文件分配给进程,让进程以统一的文件访问接口与I/O 资源进行交互。在我们目前涉及到的I/O硬件设备中,大致可以分成以下几种: |
| 17 | +有了文件这样的抽象后,操作系统内核就可把能读写的I/O资源按文件来进行管理,并把文件分配给进程,让进程以统一的文件访问接口与I/O 资源进行交互。在目前和后续可能涉及到的I/O硬件设备中,大致可以分成以下几种: |
18 | 18 |
|
19 | 19 | - **键盘设备** 是程序获得字符输入的一种设备,也可抽象为一种只读性质的文件,可以从这个文件中读出一系列的字节序列; |
20 | 20 | - **屏幕设备** 是展示程序的字符输出结果的一种字符显示设备,可抽象为一种只写性质的文件,可以向这个文件中写入一系列的字节序列,在显示屏上可以直接呈现出来; |
21 | 21 | - **串口设备** 是获得字符输入和展示程序的字符输出结果的一种字符通信设备,可抽象为一种可读写性质的文件,可以向这个文件中写入一系列的字节序列传给程序,也可把程序要显示的字符传输出去;还可以把这个串口设备拆分成两个文件,一个用于获取输入字符的只读文件和一个传出输出字符的只写文件。 |
22 | 22 |
|
23 | 23 |
|
24 | | -在QEMU模拟的RISC-V计算机和K210物理硬件上存在串口设备,操作系统通过串口设备的输入侧连接到了同学使用的计算机的键盘设备,而串口设备的输出侧这连接到了同学使用的计算机的显示器窗口上。由于RustSBI直接管理了串口设备,并给操作系统提供了两个SBI接口,从而使得操作系统可以很简单地通过这两个SBI接口输出或输入字符。 |
| 24 | +在QEMU模拟的RISC-V计算机和K210物理硬件上存在虚拟/物理串口设备,开发者可通过QEMU的串口命令行界面或特定串口通信工具软件来对虚拟/物理串口设备进行输入/输出操作。由于RustSBI直接管理了串口设备,并给操作系统提供了基于串口收发字符的两个SBI接口,从而使得操作系统可以很简单地通过这两个SBI接口,完成输出或输入字符串的工作。 |
25 | 25 |
|
26 | 26 |
|
27 | 27 | 文件的抽象接口 ``File trait`` |
|
76 | 76 | 标准输入/输出对 ``File trait`` 的实现 |
77 | 77 | ---------------------------------------------------------------- |
78 | 78 |
|
79 | | -其实我们在第二章就对应用程序引入了基于 **文件** 的标准输出接口 ``sys_write`` ,在第五章引入了基于 **文件** 的标准输入接口 ``sys_read`` 。虽然之前还没有文件描述符表,我们提前把标准输出设备在文件描述符表中的文件描述符的值规定为 ``1`` ,用 ``Stdout`` 表示;把标准输入设备在文件描述符表中的文件描述符的值规定为 ``0``,用 ``Stdin`` 表示 。现在,我们可以重构操作系统,为标准输入和标准输出实现 ``File`` Trait,使得进程可以按文件接口与I/O外设进行交互: |
| 79 | +其实我们在第二章就对应用程序引入了基于 **文件** 的标准输出接口 ``sys_write`` ,在第五章引入了基于 **文件** 的标准输入接口 ``sys_read`` ;在第六章引入 **文件系统** ,在进程控制块中添加了表示打开文件集合的文件描述符表。我们提前把标准输出设备在文件描述符表中的文件描述符的值规定为 ``1`` ,用 ``Stdout`` 表示;把标准输入设备在文件描述符表中的文件描述符的值规定为 ``0``,用 ``Stdin`` 表示 。现在,我们可以重构操作系统,为标准输入和标准输出实现 ``File`` Trait,使得进程可以按文件接口与I/O外设进行交互: |
80 | 80 |
|
81 | 81 | .. code-block:: rust |
82 | 82 | :linenos: |
|
241 | 241 | 读写标准输入/输出文件 |
242 | 242 | --------------------------------------------------- |
243 | 243 |
|
244 | | -由于有基于文件抽象接口和文件描述符表,之前实现的文件读写系统调用 ``sys_read/write`` 可以直接用于标准输入/输出文件,很好第达到了代码重用的目标。 |
| 244 | +由于有基于文件抽象接口和文件描述符表,之前实现的文件读写系统调用 ``sys_read/write`` 可以直接用于标准输入/输出文件,很好地达到了代码重用的目标。 |
245 | 245 | 这样,操作系统通过文件描述符在当前进程的文件描述符表中找到某个文件,无需关心文件具体的类型,只要知道它一定实现了 ``File`` Trait 的 ``read/write`` 方法即可。Trait 对象提供的运行时多态能力会在运行的时候帮助我们定位到符合实际类型的 ``read/write`` 方法,完成不同类型文件各自的读写。 |
0 commit comments