linux 2.6源代码情景分析笔记之进程4

来源:互联网 发布:苍穹变坐骑5-6进阶数据 编辑:程序博客网 时间:2024/04/27 23:32


散列(hash)函数并不总能确保pid与表索引一一对应。两个不同的pid散列到相同的表索引称为冲突(colliding),linux利用链表来处理冲突的pid,每一个表项是由冲突的进程描述符组成的双向链表。
pid散列表的数据结构解决了所有这些难题,他们可以为包含在一个散列表中的任何pid号定义进程链表。最主要的数据结构是四个pid结构的数组,它在进程描述符的pid字段中。

struct pid
{
        /* Try to keep pid_chain in the same cacheline as nr for find_pid */
        int nr;pid的数值
        struct hlist_node pid_chain;/* list of pids with the same nr, only one of them is in the hash */链接散列链表的下一个和前一个元素
        struct list_head pid_list;每个pid的进程链表头
};

基本运作:pid_hash中的四个基本类型表头找到tgid哈希表,然后找到对应表项再进一步找到进程描述符中的pid_chain字段,然后进一步找到process descriptor中的pid_chain表项,然后找到哈希表。

处理pid散列表的函数和宏:

#define do_each_task_pid(who, type, task)                               /
        if ((task = find_task_by_pid_type(type, who))) {                /
                prefetch((task)->pids[type].pid_list.next);             /
                do {

#define while_each_task_pid(who, type, task)                            /
                } while (task = pid_task((task)->pids[type].pid_list.next,/
                                                type),                  /
                        prefetch((task)->pids[type].pid_list.next),     /
                        hlist_unhashed(&(task)->pids[type].pid_chain)); /
        }                                                               /

#endif
标记do-while循环的开始和结束,循环作用于在pid值等于nr的pid链表上,链表的类型由参数type给出,task参数指向当前被扫描的元素的进程描述符。
在type类型的散列表中查找pid等于nr的进程。该函数返回所匹配的进程描述符指针。
task_t *find_task_by_pid_type(int type, int nr)
{
        struct pid *pid;

        pid = find_pid(type, nr);
        if (!pid)
                return NULL;

        return pid_task(&pid->pid_list, type);
}

struct pid * fastcall find_pid(enum pid_type type, int nr)
{
        struct hlist_node *elem;
        struct pid *pid;

        hlist_for_each_entry(pid, elem,
                        &pid_hash[type][pid_hashfn(nr)], pid_chain) {
                if (pid->nr == nr)
                        return pid;
        }
        return NULL;
}

#define pid_task(elem, type) list_entry(elem, struct task_struct, pids[type].pid_list)
把task指向的pid等于nr的进程描述符插入type类型的散列表中。如果一个pid等于nr的进程描述符已经在散列表中,这个函数就只把task插入已有的pid进程链表中。
int fastcall attach_pid(task_t *task, enum pid_type type, int nr)
{
        struct pid *pid, *task_pid;
" ============================================================================
" Netrw Directory Listing                                        (netrw v132)
"   /home/mxy/linux11/arch
"   Sorted by      name
"   Sort sequence: [//]$,/.h$,/.c$,/.cpp$,*,/.o$,/.obj$,/.info$,/.swp$,/.bak$,/~$
"   Quick Help: <F1>:help  -:go up dir  D:delete  R:rename  s:sort-by  x:exec
" ============================================================================
../
alpha/
arm/
arm26/
cris/
frv/
h8300/
i386/
ia64/
m32r/
m68k/
m68knommu/
mips/
parisc/
ppc/
ppc64/
s390/
sh/
sh64/
sparc/
sparc64/
um/
v850/
x86_64/

        task_pid = &task->pids[type];
        pid = find_pid(type, nr);
        if (pid == NULL) {
                hlist_add_head(&task_pid->pid_chain,
                                &pid_hash[type][pid_hashfn(nr)]);
                INIT_LIST_HEAD(&task_pid->pid_list);
        } else {
                INIT_HLIST_NODE(&task_pid->pid_chain);
                list_add_tail(&task_pid->pid_list, &pid->pid_list);
        }
        task_pid->nr = nr;

        return 0;
}
从type类型的pid进程链表中删除task所指向的进程描述符。如果删除后pid进程链表没有变为空,则函数终止,否则该函数还要从type类型的散列表中删除进程描述符。最后如果pid值没有出现在任何其他的散列表中,为了这个值能够被反复使用,该函数还必须清除pid位图中的相应位。

void fastcall detach_pid(task_t *task, enum pid_type type)
{
        int tmp, nr;

        nr = __detach_pid(task, type);
        if (!nr)
                return;

        for (tmp = PIDTYPE_MAX; --tmp >= 0; )
                if (tmp != type && find_pid(tmp, nr))
                        return;

        free_pidmap(nr);
}

static fastcall int __detach_pid(task_t *task, enum pid_type type)
{
        struct pid *pid, *pid_next;
        int nr = 0;

        pid = &task->pids[type];
        if (!hlist_unhashed(&pid->pid_chain)) {
                hlist_del(&pid->pid_chain);

                if (list_empty(&pid->pid_list))
                        nr = pid->nr;
                else {
                        pid_next = list_entry(pid->pid_list.next,
                                                struct pid, pid_list);
                        /* insert next pid from pid_list to hash */
                        hlist_add_head(&pid_next->pid_chain,
                                &pid_hash[type][pid_hashfn(pid_next->nr)]);
                }
        }

        list_del(&pid->pid_list);
        pid->nr = 0;

        return nr;
}