Linux内核PID管理
前言
了解Linux内核PID管理的目的是想了解:当kill掉一个进程之后,/proc/目录下对应的pid目录是否会立即消失。
proc/pid
proc是一个虚拟文件系统,文件系统在注册时都会注册属于该文件系统的文件操作函数(file operations)和节点操作函数(inode operations),而proc文件系统的根目录作为一个特殊的文件节点,在文件系统注册时,还为该节点注册了特定的file operations和inode operations,进程对应的pid目录便是通过该节点的file operations来创建的:
/*
* This is the root "inode" in the /proc tree..
*/
struct proc_dir_entry proc_root = {
.low_ino = PROC_ROOT_INO,
.namelen = 5,
.mode = S_IFDIR | S_IRUGO | S_IXUGO,
.nlink = 2,
.refcnt = REFCOUNT_INIT(1),
.proc_iops = &proc_root_inode_operations,
.proc_fops = &proc_root_operations,
.parent = &proc_root,
.subdir = RB_ROOT,
.name = "/proc",
};
/*
* The root /proc directory is special, as it has the
* <pid> directories. Thus we don't use the generic
* directory handling functions for that..
*/
static const struct file_operations proc_root_operations = {
.read = generic_read_dir,
.iterate_shared = proc_root_readdir,
.llseek = generic_file_llseek,
};
static int proc_fill_super(struct super_block *s, struct fs_context *fc)
{
......
pde_get(&proc_root);
root_inode = proc_get_inode(s, &proc_root);
if (!root_inode) {
pr_err("proc_fill_super: get root inode failed\n");
return -ENOMEM;
}
s->s_root = d_make_root(root_inode);
if (!s->s_root) {
pr_err("proc_fill_super: allocate dentry failed\n");
return -ENOMEM;
}
......
}
当对proc文件系统的根目录进行访问时,如ls命令显示/proc目录下的文件时,其调用栈如下(即通过系统调用getdents来获取/proc下所有但的目录项,每一个目录项对应于一个文件):
__arm64_sys_getdents64
ksys_getdents64
iterate_dir
proc_root_readdir
在/proc目录下的文件分为两种:通过proc_create等接口创建产生的文件,如cpuinfo;pid目录文件。
static int proc_root_readdir(struct file *file, struct dir_context *ctx)
{
if (ctx->pos < FIRST_PROCESS_ENTRY) {
int error = proc_readdir(file, ctx); //先读取普通的文件目录,如通过proc_create创建的cpuinfo等节点
if (unlikely(error <= 0))
return error;
ctx->pos = FIRST_PROCESS_ENTRY;
}
return proc_pid_readdir(file, ctx);//读取pid目录节点
}
通过proc_pid_readdir函数读取pid目录文件的过程为:通过next_tgid遍历系统中的进程;遍历的过程中调用proc_fill_cache将进程信息以目录项(dentry)的形式填入用户缓冲区。也就是说每一次读取/proc目录,都会执行proc_pid_readdir函数根据当前系统中的进程构建pid目录项,所以当/proc下没有某一个pid目录时,表示该pid对应的进程一定不在。
/* for the /proc/ directory itself, after non-process stuff has been done */
int proc_pid_readdir(struct file *file, struct dir_context *ctx)
{
struct tgid_iter iter;
struct pid_namespace *ns = proc_pid_ns(file_inode(file));
loff_t pos = ctx->pos;
if (pos >= PID_MAX_LIMIT + TGID_OFFSET)
return 0;
if (pos == TGID_OFFSET - 2) {
struct inode *inode = d_inode(ns->proc_self);
if (!dir_emit(ctx, "self", 4, inode->i_ino, DT_LNK))
return 0;
ctx->pos = pos = pos + 1;
}
if (pos == TGID_OFFSET - 1) {
struct inode *inode = d_inode(ns->proc_thread_self);
if (!dir_emit(ctx, "thread-self", 11, inode->i_ino, DT_LNK))