Expand description
文件描述符表
该模块实现了进程级的文件描述符管理,提供 POSIX 兼容的文件描述符操作。
§核心组件
§设计理念
§文件描述符的本质
文件描述符(FD)是进程级的整数索引,指向打开的文件对象:
FDTable
┌────┬──────────────────────┐
│ 0 │ Arc<StdinFile> │ ← stdin
│ 1 │ Arc<StdoutFile> │ ← stdout
│ 2 │ Arc<StderrFile> │ ← stderr
│ 3 │ Arc<RegFile> │
│ 4 │ Arc<PipeFile> │
│ 5 │ None │
└────┴──────────────────────┘§POSIX 语义
§最小可用 FD
alloc() 总是返回最小的可用文件描述符:
let fd1 = fd_table.alloc(file1)?; // 返回 3
let fd2 = fd_table.alloc(file2)?; // 返回 4
fd_table.close(3)?;
let fd3 = fd_table.alloc(file3)?; // 返回 3 (重用)§dup 语义
dup 系列操作共享 File 对象(包括 offset):
fd[3] ──┐
├──> Arc<RegFile> { offset: AtomicUsize }
fd[4] ──┘
// fd[3] 和 fd[4] 共享 offset,一个 read() 会影响另一个§FD 标志 vs 文件状态标志
- FD 标志 (FdFlags): 文件描述符级别,dup 时不共享
FD_CLOEXEC: exec 时关闭
- 文件状态标志 (OpenFlags): File 对象级别,dup 时共享
O_RDONLY/O_WRONLY/O_RDWR: 访问模式O_APPEND: 追加模式O_NONBLOCK: 非阻塞模式
§fork 和 exec
§fork 时
父子进程共享整个 FDTable:
父进程 ──┐
├──> Arc<FDTable>
子进程 ──┘§exec 时
自动关闭带 FD_CLOEXEC 标志的文件:
fd_table.close_exec(); // exec 前调用§并发安全
FDTable 内部使用 SpinLock 保护:
files:Vec<Option<Arc<dyn File>>>fd_flags:Vec<FdFlags>
多线程访问 FDTable 时会竞争锁,但 File 对象本身(如 RegFile 的 offset) 使用原子操作,无需额外锁定。
§使用示例
§基本操作
use vfs::{FDTable, RegFile};
let fd_table = FDTable::new();
// 分配文件描述符
let file = Arc::new(RegFile::new(dentry, OpenFlags::O_RDONLY));
let fd = fd_table.alloc(file)?;
// 访问文件
let file = fd_table.get(fd)?;
file.read(&mut buf)?;
// 关闭文件描述符
fd_table.close(fd)?;§dup 操作
// dup: 复制到最小可用 FD
let new_fd = fd_table.dup(old_fd)?;
// dup2: 复制到指定 FD
fd_table.dup2(old_fd, new_fd)?;
// dup3: dup2 + 设置标志
fd_table.dup3(old_fd, new_fd, OpenFlags::O_CLOEXEC)?;§重定向示例
// 将 stdout 重定向到文件
let file = open_file("/tmp/output.txt", O_WRONLY | O_CREAT)?;
let fd = fd_table.alloc(file)?;
fd_table.dup2(fd, 1)?; // 1 = stdout
fd_table.close(fd)?;
// 现在所有 println! 都会写到文件Structs§
- FDTable
- 文件描述符表