fd:数组的索引
当打开一个文件时,内核向进程返回一个文件描述符( open 系统调用得到),后续 read、write 这个文件时,则只需要用这个文件描述符来标识该文件,将其作为参数传入 read、write 。
用户使用系统调用 open、creat 来打开或创建一个文件,用户态得到的结果fd ,后续的 IO 操作全都是用 fd 来标识这个文件。
进程的抽象
进程的抽象是基于 struct task_struct 结构体:
struct task_struct {
// ...
struct files_struct *files;
}
struct task_struct 是进程的抽象封装,标识一个进程,在 Linux 里面的进程各种抽象视角,都是这个结构体给到你的。当创建一个进程,其实也就是 new 一个 struct task_struct 出来;每一个进程就是一个task_struct的结构体。
files: 指向files_struct的结构体,这个结构体就是用来管理该进程打开的所有文件的管理结构。
文件的维护和管理
struct files_struct {
// 读相关字段
atomic_t count;
bool resize_in_progress;
wait_queue_head_t resize_wait;
// 打开的文件管理结构
struct fdtable __rcu *fdt;
struct fdtable fdtab;
// 写相关字段
unsigned int next_fd;
unsigned long close_on_exec_init[1];
unsigned long open_fds_init[1];
unsigned long full_fds_bits_init[1];
struct file * fd_array[NR_OPEN_DEFAULT];
};
该结构体体内含多个数组,通过数组去管理打开的文件。
结构体files_struct是用来维护所有打开的文件的,内部的核心是由一个静态数组和动态数组管理结构实现。
struct file * fd_array[NR_OPEN_DEFAULT] 是一个静态数组,随着files_struct 结构体分配出来的,在 64 位系统上,静态数组大小为 64;它利用指针偏移指向被打开文件的指针。
struct fdtable 是个动态数组管理结构,数组边界是用字段描述的。
struct fdtable {
unsigned int max_fds;
struct file __rcu **fd; /* current fd array */
};
fd指向file指针,实现找到被打开的文件。
fd 就是数组的索引,也就是数组的编号。通过非负数 fd 就能拿到struct file结构体的地址。
具体一点就是如此,fd是文件描述符表的下标。
总结:
创建一个进程的时候就会new一个struct task_struct ,它就表示为一个进程,而进程所打开的文件由task_struct中的files_struct管理,它负责管理打开的文件;而在files_struct中存在struct file *fd_array 或struct fdtable,利用结构体数组或者fdtable.fd指向最终的某一个文件。创建进程抽象结构体1中存在管理所有打开文件的结构体2,在结构体2利用数组找到文件。