Linux下file_struct

来源:互联网 发布:温州淘宝城 编辑:程序博客网 时间:2024/05/18 03:07

file结构体:

struct file结构体定义在include/Linux/fs.h中定义。文件结构体代表一个打开的文件,系统中的每个打开的文件在内核空间都有一个关联的 struct file。它由内核在打开文件时创建,并传递给在文件上进行操作的任何函数。在文件的所有实例都关闭后,内核释放这个数据结构。在内核创建和驱动源码中,struct file的指针通常被命名为file或filp。

struct file {

                    union {

                    struct list_head fu_list;          文件对象链表指针linux/include/linux/list.h

                    struct rcu_head fu_rcuhead;          RCU是Linux 2.6内核中新的锁机制

       } f_u;

 

 struct path f_path;                   包含dentry和mnt两个成员,用于确定文件路径

 #define f_dentry f_path.         dentry f_path的成员之一,当前文件的dentry结构

 #define f_vfsmnt f_path.mnt          表示当前文件所在文件系统的挂载根目录

 const struct file_operations *f_op;           与该文件相关联的操作函数

 atomic_t f_count;            文件的引用计数(有多少进程打开该文件)

 unsigned int f_flags;          对应于open时指定的flag

 mode_t f_mode;          读写模式:open的mod_t mode参数

 off_t f_pos;          该文件在当前进程中的文件偏移量

 struct fown_struct f_owner;         该结构的作用是通过信号进行I/O时间通知的数据。

 unsigned int f_uid, f_gid;         文件所有者id,所有者组id

 struct file_ra_state f_ra;         在linux/include/linux/fs.h中定义,文件预读相关

 unsigned long f_version;

 #ifdef CONFIG_SECURITY

 void *f_security;

 #endif

  void *private_data;

 #ifdef CONFIG_EPOLL

  struct list_head f_ep_links;

 spinlock_t f_ep_lock;

 #endif /* #ifdef CONFIG_EPOLL */

 struct address_space *f_mapping;

 };


struct files_struct

  对于每个进程,包含一个files_struct结构,用来记录文件描述符的使用情况,定义在include/linux/file.h中

  struct files_struct

  {

  atomic_t count; 使用该表的进程数

  struct fdtable *fdt;

  struct fdtable fdtab;

  spinlock_t file_lock ____cacheline_aligned_in_smp;

  int next_fd; 数值最小的最近关闭文件的文件描述符,下一个可用的文件描述符

  struct embedded_fd_set close_on_exec_init; 执行exec时需要关闭的文件描述符初值集合

  struct embedded_fd_set open_fds_init; 文件描述符的屏蔽字初值集合

  struct file * fd_array[NR_OPEN_DEFAULT]; 默认打开的fd队列

  };

  struct fdtable {

  unsigned int max_fds;

  struct file ** fd; 指向打开的文件描述符列表的指针,开始的时候指向fd_array,当超过max_fds时,重新分配地址

  fd_set *close_on_exec; 执行exec需要关闭的文件描述符位图(fork,exec即不被子进程继承的文件描述符)

  fd_set *open_fds; 打开的文件描述符位图

  struct rcu_head rcu;

  struct fdtable *next;

};

 

这里着重说一下 fd。

 

fd: 文件描述符


fd只是一小整数,在open时产生。起到一个索引的作用,进程通过PCB中的文件描述符表找到该fd所指向的文件指针filp。

        文件描述符的操作(如: open)返回的是一个文件描述符,内核会在每个进程空间中维护一个文件描述符表, 所有打开的文件都将通过此表中的文件描述符来引用;而流(如: fopen)返回的是一个FILE结构指针, FILE结构是包含有文件描述符的,FILE结构函数可以看作是对fd直接操作的系统调用的封装,它的优点是带有I/O缓存。

        每个进程在PCB(ProcessControl Block)即进程控制块中都保存着一份文件描述符表,文件描述符就是这个表的索引,文件描述表中每个表项都有一个指向已打开问件的指针,现在我们明确一下:已打开的文件在内核中用file结构体表示,文件描述符表中的指针指向file结构体。

 

那么我们用图表述一下:

 

 

那么下面我们举一个例子:


当我们运行的时候 我们看一下结果:


是按照我们预期输出到标准输出流的。

 

可是 我们如果把它写入文件里


我们发现,写入文件时先写入的是write,printf与fwrite后写入,并且被写入了两次。

当然与fork有关,那么,这又是为什么?

 

printf和fwrite都是库函数:结合已有知识,我们了解到当使用库函数命令时,打印消息并没有直接写到输出位置上,而是先把数据写到输出缓冲区,在刷新至输出位置。


 1、当输出目标位置为输出到显示器时,则刷新方式是行刷新;

 2、当输出目标位置为输出到文件中时,刷新方式由行缓冲变为全缓冲,全缓冲是指当把缓冲区写满后才能刷新。(或者强制刷新)


代码中printf和fwrite第一次打印,在fork操作之前,第二次在fork操作之后,原因是因为在fork操作前,printf和fwrite的输出命令将数据先写到缓冲区中,此时只执行了这两条命令,由于是全缓冲的刷新方式,所以这两条命令并不足以将缓存写满,所以数据暂存在缓冲区中;

然后进行fork创建子进程,由于fork创建出的父子进程代码共享,而数据不共享,各自私有一份,缓冲区中的数据都属于数据,因为父进程的残留数据还在缓冲区中,所以fork完毕后,父子进程将缓存中的数据各自存一份有父进程残留数据的数据,所以当父子进程各自刷新时,父子进程会各自执行一次printf和fwrite的输出命令(触发写时拷贝),所以命令就从原来的两条变为四条。

1 0
原创粉丝点击