句柄 | handle
int open(const char* pathname,int flags);
ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);
int close(int fd);
只要写过应用程序代码操作过文件不会陌生这几个函数,文件操作的几个关键步骤嘛,跟把大象装冰箱分几步一样.先得把冰箱门打开,再把大象放进去,再关上冰箱门.其中最重要的一个参数就是fd
,应用程序所有对文件的操作都基于它.fd
可称为文件描述符,或者叫文件句柄(handle),个人更愿意称后者. 因为更形象,handle
英文有手柄的意思,跟开门一样,握住手柄才能开门,手柄是进门关门的抓手.映射到文件系统,fd
是应用层出入内核层的抓手.句柄是一个数字编号, open | creat
去申请这个编号,内核会创建文件相关的一系列对象,返回编号,后续通过编号就可以操作这些对象.原理就是这么的简单,本篇将从fd
入手,跟踪文件操作的整个过程.
请记住,鸿蒙内核中,在不同的层面会有两种文件句柄:
- 系统文件句柄(
sysfd
),由内核统一管理,和进程文件句柄形成映射关系,一个sysfd
可以被多个profd
映射,也就是说打开一个文件只会占用一个sysfd
,但可以占用多个profd
,即一个文件被多个进程打开. - 进程文件句柄(
profd
),由进程管理的叫进程文件句柄,内核对不同进程中的fd
进行隔离,即进程只能访问本进程的fd
.举例说明之间的关系:
文件 sysfd profd
吃个桃桃.mp4 10 13(A进程)
吃个桃桃.mp4 10 3(B进程)
容嬷嬷被冤枉.txt 12 3(A进程)
容嬷嬷被冤枉.txt 12 3(C进程)
进程文件句柄
在鸿蒙一个进程默认最多可以有256
个fd
,即最多可打开256个文件.文件也是资源的一种,系列篇多次说过进程是管理资源的,所以在进程控制块中能看到文件的影子files_struct
. files_struct
可理解为进程的文件管理器,里面只放和本进程相关的文件,线程则共享这些文件.另外子进程也会拷贝一份父进程的files_struct
到自己的files_struct
上,在父子进程篇中也讲过fork
的本质就是拷贝资源,其中就包括了文件内容.
//进程控制块
typedef struct ProcessCB {
//..
#ifdef LOSCFG_FS_VFS
struct files_struct *files; /**< Files held by the process */ //进程所持有的所有文件,注者称之为进程的文件管理器
#endif //每个进程都有属于自己的文件管理器,记录对文件的操作. 注意:一个文件可以被多个进程操作
} LosProcessCB;
struct files_struct {//进程文件表结构体
int count; //持有的文件数量
struct fd_table_s *fdt; //持有的文件表
unsigned int file_lock; //文件互斥锁
unsigned int next_fd; //下一个fd
#ifdef VFS_USING_WORKDIR
spinlock_t workdir_lock; //工作区目录自旋锁
char workdir[PATH_MAX]; //工作区路径,最大 256个字符
#endif
};
fd_table_s
为files_struct
的成员,负责记录所有进程文件句柄的信息,个人觉得鸿蒙这块的实现有点乱,没有封装好.
struct fd_table_s {//进程fd表结构体
unsigned int max_fds;//进程的文件描述符最多有256个
struct file_table_s *ft_fds; /* process fd array associate with system fd *///系统分配给进程的FD数组 ,fd 默认是 -1
fd_set *proc_fds; //进程fd管理位,用bitmap管理FD使用情况,默认打开了 0,1,2 (stdin,stdout,stderr)
fd_set *cloexec_fds;
sem_t ft_sem; /* manage access to the file table */ //管理对文件表的访问的信号量
};
file_table_s
记录进程fd
和系统fd
之间的绑定或者说映射关系
struct file_table_s {//进程fd <--> 系统fd绑定
intptr_t sysFd; /* system fd associate with the tg_filelist index */
};
fd_set
实现了进程fd
按位图管理,系列操作为 FD_SET
,FD_ISSET
,FD_CLR
,FD_ZERO
除以8
是因为 char
类型占8
个bit
位.请尝试去理解下按位操作的具体实现.
typedef struct fd_set
{
unsigned char fd_bits [(FD_SETSIZE+7)/8];
} fd_set;
#define FD_SET(n, p) FDSETSAFESET(n, (p)->fd_bits[((n)-LWIP_SOCKET_OFFSET)/8] = (u8_t)((p)->fd_bits[((n)-LWIP_SOCKET_OFFSET)/8] | (1 << (((n)-LWIP_SOCKET_OFFSET) & 7))))
#define FD_CLR(n, p) FDSETSAFESET(n, (p)->fd_bits[((n)-LWIP_SOCKET_OFFSET)/8] = (u8_t)((p)->