Chinaunix首页 | 论坛 | 博客
  • 博客访问: 743435
  • 博文数量: 141
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1115
  • 用 户 组: 普通用户
  • 注册时间: 2014-03-17 14:32
个人简介

小公司研发总监,既当司令也当兵!

文章分类

全部博文(141)

分类: LINUX

2016-02-17 20:02:56

上一篇文章里提到task_struct里有一个PID散列表
  1. struct pid_link pids[PIDTYPE_MAX];
这里简单说一下pid_link

  1. struct pid_link
  2. {
  3.     struct hlist_node node;
  4.     struct pid *pid;
  5. };
其中hlist_node是双向链表的一个节点
  1. struct hlist_node {
  2.     struct hlist_node *next, **pprev;
  3. };
由以上代码可知,pid的散列表是一个双向链表

下面介绍一些基本的函数
1、添加一个新的PID到PID散列表
关于PID的代码都在kernel/pid.c中
  1. void attach_pid(struct task_struct *task, enum pid_type type,
  2.         struct pid *pid)
  3. {
  4.     struct pid_link *link;

  5.     link = &task->pids[type];
  6.     link->pid = pid;
  7.     hlist_add_head_rcu(&link->node, &pid->tasks[type]);
  8. }
以上是添加一个PID到对应的散列表的代码:
1、首先初始化节点,设置对应的链表指针,设置PID
2、将节点加入到对应的链表中

2、获得task_struct关联的PID实例
  1. static inline struct pid *task_pid(struct task_struct *task)
  2. {
  3.     return task->pids[PIDTYPE_PID].pid;
  4. }
这个函数比较简单,task_struct中的
  1. struct pid_link pids[PIDTYPE_MAX];
这个字段将task对应的
  1. enum pid_type
  2. {
  3.     PIDTYPE_PID,
  4.     PIDTYPE_PGID,
  5.     PIDTYPE_SID,
  6.     PIDTYPE_MAX
  7. };
三种PID都存在一个数组中,因此,要取PID,则只需取PIDTYPE_PID对应的实例即可,同理也可以取得PGID和SID

3、取得PID对应的数字ID
首先PID是在指定的命名空间里的,所以只要取得pid在指定命名空间里的upid的nr字段即可
  1. pid_t pid_nr_ns(struct pid *pid, struct pid_namespace *ns)
  2. {
  3.     struct upid *upid;
  4.     pid_t nr = 0;

  5.     if (pid && ns->level <= pid->level) {
  6.         upid = &pid->numbers[ns->level];
  7.         if (upid->ns == ns)
  8.             nr = upid->nr;
  9.     }
  10.     return nr;
  11. }
upid = &pid->numbers[ns->level];这一句是取得指定深度对应的upid,pid最末端的number[1]字段是可扩展的,里面存放了pid在不同命名空间里对应的upid(即是局部pid),
ns->level<=pid->level这个判断的主要原因是:保证pid在命名空间的可见范围内
最后判断取得的upid的命名空间和传入的是否一致,若一致则取出nr并返回。

4、分配一个PID
内核中Pid是用位图来存储的,分配pid即是在位图中寻找第一个没有使用的pid(也即是第一个值为0的比特),对于一个PID,能够看得到这个pid的命名空间都需要分配一个upid,同时upid要放入到pid散列表中

主要通过以下两个函数实现:
  1. struct pid *alloc_pid(struct pid_namespace *ns)
  2. {
  3.     struct pid *pid;
  4.     enum pid_type type;
  5.     int i, nr;
  6.     struct pid_namespace *tmp;
  7.     struct upid *upid;

  8.     pid = kmem_cache_alloc(ns->pid_cachep, GFP_KERNEL);
  9.     if (!pid)
  10.         goto out;

  11.     tmp = ns;
  12.     for (i = ns->level; i >= 0; i--) {
  13.         nr = alloc_pidmap(tmp);
  14.         if (nr < 0)
  15.             goto out_free;

  16.         pid->numbers[i].nr = nr;
  17.         pid->numbers[i].ns = tmp;
  18.         tmp = tmp->parent;
  19.     }

  20.     get_pid_ns(ns);
  21.     pid->level = ns->level;
  22.     atomic_set(&pid->count, 1);
  23.     for (type = 0; type < PIDTYPE_MAX; ++type)
  24.         INIT_HLIST_HEAD(&pid->tasks[type]);

  25.     upid = pid->numbers + ns->level;
  26.     spin_lock_irq(&pidmap_lock);
  27.     for ( ; upid >= pid->numbers; --upid)
  28.         hlist_add_head_rcu(&upid->pid_chain,
  29.                 &pid_hash[pid_hashfn(upid->nr, upid->ns)]);
  30.     spin_unlock_irq(&pidmap_lock);

  31. out:
  32.     return pid;

  33. out_free:
  34.     while (++i <= ns->level)
  35.         free_pidmap(pid->numbers + i);

  36.     kmem_cache_free(ns->pid_cachep, pid);
  37.     pid = NULL;
  38.     goto out;
  39. }
代码比较长,我们主要关心以下代码
  1. struct pid *pid;
  2.     enum pid_type type;
  3.     int i, nr;
  4.     struct pid_namespace *tmp;
  5.     struct upid *upid;
  6. ....
  7.     tmp = ns;
  8.     for (i = ns->level; i >= 0; i--) {
  9.         nr = alloc_pidmap(tmp);
  10. .....

  11.         pid->numbers[i].nr = nr;
  12.         pid->numbers[i].ns = tmp;
  13.         tmp = tmp->parent;
  14.     }
  15. ...
  16.    pid->level = ns->level;

for ( ; upid >= pid->numbers; --upid)
hlist_add_head_rcu(&upid->pid_chain,
&pid_hash[pid_hashfn(upid->nr, upid->ns)]);
1)首先,循环里是对每个命名空间都分配一个nr,从子命名空间一直到全局命名空间
2)将每个upid放到PID散列表中。

参考资料:
1、《深入Linux内核架构》

阅读(2247) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~