Appearance
文件描述符层
Unix 接口的一个很酷的方面是,Unix 中的大多数资源都表示为文件,包括设备(如控制台)、管道,当然还有真正的文件。文件描述符层就是实现这种统一性的层。
正如我们在第 1 章中看到的,Xv6 为每个进程提供了自己的打开文件表,或文件描述符。每个打开的文件都由一个 struct file
表示,它是一个 inode 或管道的包装器,外加一个 I/O 偏移量。每次调用 open
都会创建一个新的打开文件(一个新的 struct file
):如果多个进程独立打开同一个文件,不同的实例将有不同的 I/O 偏移量。另一方面,一个单独的打开文件(同一个 struct file
)可以多次出现在一个进程的文件表中,也可以出现在多个进程的文件表中。如果一个进程使用 open
打开文件,然后使用 dup
创建别名,或使用 fork
与子进程共享,就会发生这种情况。引用计数跟踪对特定打开文件的引用次数。一个文件可以以只读、只写或读写方式打开。readable
和 writable
字段跟踪这一点。
系统中所有打开的文件都保存在一个全局文件表中,即 ftable
。文件表有分配文件的函数(filealloc
)、创建重复引用的函数(filedup
)、释放引用的函数(fileclose
),以及读写数据的函数(fileread
和 filewrite
)。
前三个遵循了现在熟悉的形式。filealloc
扫描文件表,查找一个未被引用的文件(f->ref == 0
)并返回一个新的引用;filedup
增加引用计数;而 fileclose
减少它。当一个文件的引用计数达到零时,fileclose
根据类型释放底层的管道或 inode。
函数 filestat
、fileread
和 filewrite
实现了对文件的 stat
、read
和 write
操作。filestat
只允许在 inode 上调用,并调用 stati
。fileread
和 filewrite
检查操作是否被打开模式允许,然后将调用传递给管道或 inode 的实现。如果文件代表一个 inode,fileread
和 filewrite
使用 I/O 偏移量作为操作的偏移量,然后将其推进。管道没有偏移量的概念。回想一下,inode 函数要求调用者处理锁定。inode 锁定的一个方便的副作用是读写偏移量是原子更新的,因此多个进程同时写入同一个文件不会覆盖彼此的数据,尽管它们的写入最终可能会交错。