解释一下struct pid:
struct pid是kernel内部用来辨别各个进程概念。每一个struct pid都对应一个独立的task、进程组、session。当有进程attach到一起,struct pid就会组成为一个hash table,如此以来struct pid索引到的进程就可以通过pid数找到。
数字到指针的索引是通过struct idr来管理,struct idr中有一个redix tree,索引是立即数,对应值是指针
一切thread以task_struct为中心,struct pid是task_struct在pid领域的代言人
在pid领域struct pid_namespace是最高集合
pid_namespace包含struct idr idr,idr背后是一颗redix树,联系当前namespace的pid_t与struct pid指针
出现一个新的pid的时机是在创建或操作进程;
在较新的内核中,描述进程pid这个事儿由于掺杂了namespace变得复杂;
以Flag CLONE_NEWPID为界,决定在create_new_namespace时,是否创建一个新的pid_namespace
创建新的pid第一个目标是给当前进程一个pid_namespace,第二个目标是给children用,
如果Flage显示不必创建新的pid_namespace,
则直接使用父进程所用struct nsproxy->struct pid_namespace pid_ns_for_children
如果Flag显示需要创建新的pid_namespace,
则需要alloc一个新的struct pid_namespace,同时,
还要创建pid_namespace中为struct pid准备的slab,需要注意的是,
struct pid的slab并不等于sizeof(struct pid),
这与struct pid末元素struct upid个数有关,
upid用来指向当前struct pid所有的struct pid_namespace
这里需要解释一下:pid_namespace是可以嵌套的,不断创造子pid_namespace
所以一个struct pid是可能属于多个pid_namespace
也就意味着,一个struct pid可能有多个pid_t,分布在多级pid_namespace中
struct upid的两个元素nr和struct pid_namespace *ns,
nr就是在对应ns中的pid_t
而ns在struct pid构建时,按照嵌套层数,指向各层struct pid_namespace
所以这个slab的大小是
sizeof(struct pid) + (父_pid_ns->level + 1 + 1) * sizeof(struct upid)
多加一个1似乎是垫子
另外需要提到的是一个namespace的主结构体struct nsproxy,这个是每个task_struct一个的namespace入口,包含所有支持命名空间的子系统fs(mount)/uts/network/sysvipc/pid(for children)/net/cgroup
问题:PIDTYPE_PID/PIDTYPE_PGID/PIDTYPE_SID这几个不同的type的处理
pid描述一个thread
pgid描述一个thread group leader
sid描述一个session
由此,task_struct中struct pid_link pids[PIDTYPE_MAX]数组分别指向
PIDTYPE_PID-当前thread的struct pid
PIDTYPE_PGID-当前thread的thread group leader的struct pid
PIDTYPE_SID-当前thead所在session的struct pid
在copy_process过程在Flag没有CLONE_THREAD(不是创建线程)的情况下,
kernel仅保障了thead group leader(进程leader)的PIDTYPE_PGID/PIDTYPE_SID与父进程相同。
对于非thread group leader(普通线程),未找到对PIDTYPE_PGID/PIDTYPE_SID的配置
问题:struct task_struct->pid_t pid中是该进程在哪个namespace的pid
copy_process函数中可以看到,task_struct->pid = struct pid->numbers[0].nr,也就是最高层namespace
提示:Flag CLONE_THREAD对task_struct中的struct task_struct group_leader和pid_t tgid的影响
对CLONE_THREAD,group_leader/tgid与current的group_leader/tgid一致
对于非CLONE_THREAD,group_leader指向新创建的task本身,tgid即为新创建task的pid
提示:关于struct pid->unsigned int level如何指引pid_t查找task_struct
这个level值很重要,struct pid归属与多个namespace,当一个进程根据pid_t值查找task时,
首先要确定的是,这个pid_t属于哪个pid_namespace
查找是task发起的,自然不应该跃出此task所属的pid_namespace,
于是需要确定task是活跃在哪层pid_namespace,
level就用来确定这个层级信息
由此struct pid->struct upid[struct pid->level].struct pid_namespace
就指向一个task活跃的pid_namespace(接口task_active_pid_ns)
有了pid_t所在的pid_name_space,通过idr查找radix tree即可定位pid_t所指进程
遗留:没有想明白为什么struct pid不直接指向struct task_struct,
而是将task_struct->struct pid_link pids[type]-node与struct hlist_head tasks[type]构成的链表
链表里会有其他元素??无论会不会有其他元素,似乎只有first元素是被使用的,可能每次压first会引起
旧有first压栈效果,然后first被取出时,旧有first还能生效???不是太理解这部分设计。
对遗留的解释:PIDTYPE_PID可能只会有一个元素(不确定),但是对于trPIDTYPE_PGID/PIDTYPE_SID肯定是可以织有多个