关于进程级打开文件表与系统级打开文件表

进程级打开文件表与系统级打开文件表

当一个进程调用 open() 系统调用打开一个文件时,操作系统会进行一系列操作,并涉及到这两个重要的文件表。这两个表协同工作,实现了文件的高效管理和共享。

核心思想:

1. 进程级打开文件表 (Per-process Open File Table)

表格表示:

进程 A 的打开文件表

文件描述符 (fd) 指向系统级文件表的指针 / 索引
0 (标准输入) -> 系统表项 X
1 (标准输出) -> 系统表项 Y
2 (标准错误) -> 系统表项 Z
3 -> 系统表项 F1 (文件A)
4 -> 系统表项 F2 (文件B)
... ...

进程 B 的打开文件表

文件描述符 (fd) 指向系统级文件表的指针 / 索引
0 (标准输入) -> 系统表项 X
1 (标准输出) -> 系统表项 Y
2 (标准错误) -> 系统表项 Z
3 -> 系统表项 F1 (文件A)
4 -> 系统表项 F3 (文件C)
... ...

2. 系统级打开文件表 (System-wide Open File Table)

表格表示:

系统级打开文件表

表项索引 / 地址 指向 FCB/i-node 的指针 当前文件偏移量 (读写指针) 打开模式 (读/写/追加) 引用计数 其他信息 (如状态标志)
F1 -> i-node 100 (文件A) 1000 读写 (RW) 2 Non-blocking
F2 -> i-node 200 (文件B) 500 只读 (R) 1 Async
F3 -> i-node 300 (文件C) 0 写 (W) 1
X (标准输入) -> i-node of stdin ... 只读 (R) >1
Y (标准输出) -> i-node of stdout ... 写 (W) >1
Z (标准错误) -> i-node of stderr ... 写 (W) >1
... ... ... ... ... ...

说明:

3. 两者之间的关系和协同工作

  1. open() 系统调用

    • 当进程调用 open("fileA", mode) 时:

      • 操作系统首先根据文件名查找对应的 FCB/i-node。

      • 如果 FCB/i-node 存在且权限允许,操作系统会在系统级打开文件表中创建一个新的条目(如果这个文件是第一次被这个进程以这个模式打开,或者是一个新的 open() 调用)。这个条目记录了文件的当前读写位置、打开模式等。

      • 然后,操作系统在当前进程的进程级打开文件表中找一个空闲的位置,将该位置的指针指向新创建的系统级条目,并返回该位置的索引作为文件描述符给用户进程。

  2. read() / write() 系统调用

    • 当进程调用 read(fd, buffer, count) 时:

      • 操作系统根据进程的 fd(文件描述符)在进程级打开文件表中找到对应的指针。

      • 通过该指针,访问系统级打开文件表中对应的条目。

      • 从系统级条目中获取文件的当前读写位置和指向FCB/i-node的指针。

      • 然后通过 FCB/i-node 中的物理地址信息,在磁盘上读写数据。

      • 读写完成后,更新系统级条目中的当前读写位置

  3. close() 系统调用

    • 当进程调用 close(fd) 时:

      • 操作系统清除进程级打开文件表中 fd 对应的条目。

      • 并将系统级打开文件表中对应条目的引用计数减一

      • 如果引用计数变为零,则该系统级条目被清除,表示该文件实例已在整个系统范围内不再被任何进程引用。

4. 为什么要引入两级表?

这种两级结构提供了以下重要优势: