2、文件描述符
下面进一步介绍进程对自己所访问的file对象的管理方法。linux中使用一个数组来管理进程打开的文件的file对象,数组中的每个元素都存放一个纸箱进程所打开的文件的file对象。既然用一个数组来存放file对象,那么用数组的下标来访问文件就是一件顺理成章的方法,于是,linux就把数组元素的下标叫做该数组元素所对应的文件的文件描述符,该描述符就是系统对文件的标识,这个数组也叫文件描述符数组,如下图所示:
内核通过系统调用dup、dup2和fctl可以使数组中的多个元素指向同一个文件的file对象,也就是说,在linux中,同一个文件可以有多个文件描述符。
3、进程打开文件表
进程描述符数组中存放了一个进程所访问的所有文件,把这个文件描述符数组和这个数组在系统中的一些动态信息组合到一起,就形成了一个新的数据结构——进程打开文件表,即file_struct,其定义如下:
/* * Open file table structure */ struct files_struct { atomic_t count; //引用计数 spinlock_t file_lock; /* Protects all the below members. Nests inside tsk->alloc_lock */ struct fdtable *fdt; //管理文件描述符 struct fdtable fdtab; //管理文件描述符 fd_set close_on_exec_init; //位图 fd_set open_fds_init; //位图 struct file * fd_array[NR_OPEN_DEFAULT]; //文件描述符数组 }; |
显然,这个结构应该属于进程的私有数据,所以进程控制块task_struct用指针files指向它。
struct task_struct { ... /* open file information */ struct files_struct *files; ... }; |
进程与其打开文件之间的关系如下图所示。
4、文件描述符的管理
file_struct中的fdt和fdtab用于管理文件文件描述符,一个是fdtable类型,另一个是其指针类型。fdtable的定义如下:
struct fdtable { unsigned int max_fds; //可以代开的最大文件数 int max_fdset; //位图的最大长度 int next_fd; //下一个可用的fd struct file ** fd; /* current fd array 指向files_struct的fd_array */ fd_set *close_on_exec; fd_set *open_fds; //打开的文件标记,比如第2位为0,则打开了2号文件 struct rcu_head rcu; struct files_struct *free_files; struct fdtable *next; }; |
下图可以很直观的说明文件描述符fd的管理。