Linux教程

linux-2.6.38 pid对象管理方式学习笔记

本文主要是介绍linux-2.6.38 pid对象管理方式学习笔记,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

        进程ID对于linux内核的进程管理至关重要,进程ID包括PID、PGID、SID和TGID等,每个进程的task_struct除了维护有全局的level 0级别的pid、tgid以及保存在信号处理结构中的会话ID和进程组ID(task_struct->signal->__session + task_struct->signal->__pgrp)外,还需关联到pid分配子系统维护的各个pid命名空间的数据结构中。linux支持多级嵌套的PID命名空间,相同level的不同pid命名空间可能存在相同的局部PID,为方便管理同时避免维护大量重复的PID数据,linux采用统一的struct pid结构管理各个进程的局部pid信息。

        相关数据结构和定义:

enum pid_type 
{ 
        PIDTYPE_PID, 
        PIDTYPE_PGID, 
        PIDTYPE_SID, 
        PIDTYPE_MAX 
}; 

struct pid_namespace {
...
        struct task_struct *child_reaper;
...
        int level;
        struct pid_namespace *parent;
}; 

struct upid {
        int nr;
        struct pid_namespace *ns;
        struct hlist_node pid_chain;
};

struct pid 
{
        atomic_t count;
        /* 使用该pid的进程的列表 */
        struct hlist_head tasks[PIDTYPE_MAX];
        int level;
        struct upid numbers[1];
};

        所有共享同一ID的task_struct实例都按进程存储在一个散列表中,因此需要在struct task_struct中增加一个散列表元素:

struct task_struct { 
...
        /* PID与PID散列表的联系。 */
        struct pid_link pids[PIDTYPE_MAX];
...
};

struct pid_link 
{
        struct hlist_node node;
        struct pid *pid;
}; 

        struct pid_link中的pid指向进程所属的pid结构实例,node用作进程的散列表元素插入到struct pid对应的tasks数组中,建立pid实例到进程实例的双向连接。

        kernel/pid.c里定义有static struct hlist_head *pid_hash双链哈希散列表头用于管理维护每个pid实例的每一级struct upid实例,以便在给定命名空间中查找指定PID数值的pid结构实例。

struct hlist_head {

    struct hlist_node *first;

}

struct hlist_node {
    struct hlist_node *next, **pprev;
};

        pid查找采用的哈希函数定义如下:
 

#define pid_hashfn(nr, ns)    \
    hash_long((unsigned long)nr + (unsigned long)ns, pidhash_shift)

盗图一张:

图1 可感知命名空间的ID表示所用的数据结构关系

 pid管理系统相关接口定义:
1. struct pid *get_pid(struct pid *pid)用于对pid实例使用计数原子递增1;

2. void put_pid(struct pid *pid)对pid实例引用计数器原子递减1后检测引用计数器是否为0,如果为0,则调用kmem_cache_free将该pid对象撤销返回给slab缓存对象;

3. struct task_struct *get_pid_task(struct pid *pid, enum pid_type)返回所属的pid实例的[pid_type]散列表的第一个进程实例;

4. struct pid *get_task_pid(struct task_struct *task, enum pid_type type)返回指定进程type类型的pid实例;

5. void attach_pid(struct task_struct *task, enum pid_type type, struct pid *pid)建立进程与pid实例的关联,即赋值task_struct的pid_link和pid结构的tasks;

6. void detach_pid(struct task_struct *task, enum pid_type type)将指定进程从type类型pid实例的哈希链表中删除并将其pid对象设置为NULL,同时检测原pid实例若已无进程实例绑定,则将该pid对象的各层upid回收pidmap,最后调用put_pid释放pid实例;

7. void change_pid(struct task_struct *task, enum pid_type, struct pid *pid)将指定进程的type类型pid实例重新指向到传入的新pid实例,移除旧的联结并建立新的双向连接;

8. void transfer_pid(struct task_struct *old, struct task_struct *new, enum pid_type)与change_pid类似,只不过是将old进程与pid_type指向的pid实例的联结切换到new进程;

9. struct pid *find_pid_ns(int nr, struct pid_namespace *ns)在指定的命名空间中查找pid数值为nr的pid实例,该函数的实现比较简单,pid.c中的静态全局upid哈希链表pid_hash中插入有每个pid对象的每一级struct upid实例,遍历该表即可;

10. struct pid *find_vpid(int nr)实际调用find_pid_ns(nr, current->nsproxy->pid_ns),返回当前进程所属命名空间的nr pid实例;

11. struct pid *find_get_pid(int nr)实际调用get_pid(find_vpid(nr)),区别是更新了pid实例的引用计数值;

12. struct pid *alloc_pid(struct pid_namespace *ns)调用kmem_cache_alloc创建pid对象,并自顶向下初始化每一层pid->numbers[i]指向的upid实例,INIT_HLIST_HEAD(&pid->tasks[type])初始化tasks散列表;hlist_add_head_rcu(&upid->pid_chain, &pid_hash[pid_hashfn(upid->nr, upid->ns)])将每一级upid插入到静态全局pid_hash散列表中;

13. void free_pid(struct pid *pid)释放pid对象,hlist_del_rcu(&pid->numbers[i].pid_chain)从pid_hash散列表中删除每一级upid实例;free_pidmap(pid->numbers + i)将每一级nr返回给pidmap;最后调用call_rcu(&pid->rcu, delayed_put_pid)延时释放pid对象;

14. struct pid_namespace *ns_of_pid(struct pid *pid)返回pid最顶层level所属的pid namespace对象(即alloc该pid实例的pid命名空间);

15. pid_t pid_nr(struct pid *pid)返回全局pid数值(即init pid_namespace);

16. pid_t pid_nr_ns(struct pid *pid, struct pid_namespace *ns)返回pid对象中指定命名空间的pid数值;

17. pid_t pid_vnr(struct pid *pid)实际调用pid_nr_ns(pid, current->nsproxy->pid_ns);

18. struct pid *task_pid(struct task_struct *task)返回task->pids[PIDTYPE_PID].pid;

19. struct pid *task_tgid(struct task_struct *task)返回task->group_leader->pids[PIDTYPE_PID].pid,其中group_leader指向线程组组长进程的task_struct;

20. struct pid *task_pgrp(struct task_struct *task)返回task->group_leader->pids[PIDTYPE_PGID].pid;

21. struct pid *task_session(struct task_struct *task)返回task->group_leader->pids[PIDTYPE_SID].pid

这篇关于linux-2.6.38 pid对象管理方式学习笔记的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!