Linux Kernel Source - 进程哈希表浅析

来源:互联网 发布:数字网络意思大全 编辑:程序博客网 时间:2024/06/08 22:48

哈希表实际上是一个struct task_struct * 的指针数组,即每个元素指向一组pid的进程描述符链表(此处一组不是指gid相同,而是pid满足如下第三行的宏定义,且相同)。

在Linux 2.4内核中定义如下:

#define PIDHASH_SZ (4096 >> 2)extern struct task_struct *pidhash[PIDHASH_SZ];       //定义哈希表数组的大小为1024#define pid_hashfn(x)    ((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1))   //x为进程pid,有此句可知可能存在多个进程pid对应一个哈希表元素。
哈希表如下图所示:

哈希函数并不总能确保PID与表的索引一一对应,两个不同的PID散列到相同的索引称为冲突。

既然有多个进程描述对应一个哈希表元素,那么怎样将一组进程描述符组成链表,并对应一个哈希表元素呢?

首先一下task_struct中与哈希表有关的两个字段:

struct task_struct{        ......struct task_struct *pidhash_next;        //哈希链表的下一个文件描述符的地址struct task_struct **pidhash_pprev;      //哈希链表的上一个文件描述符指针的地址        ......};
将新的的进程描述符插入哈希链表的实现如下:

static inline void hash_pid(struct task_struct *p)    //p为新进程描述符指针{struct task_struct **htable = &pidhash[pid_hashfn(p->pid)]; //与之对应的哈希表元素的地址,*htable指向一组进程描述符的哈希链表的首地址if((p->pidhash_next = *htable) != NULL) //*htable 不为空,即哈希链表不为空,将新的描述符插入链表第一的位置,其pidhash_next字段,指向原链表首部(*htable)->pidhash_pprev = &p->pidhash_next;//原链表首个进程描述符的pidhash_pprev初始化为,新链表首(即*p)pidhash_next成员的地址*htable = p;    //更新哈希表元素p->pidhash_pprev = htable;     //初始化新进程描述符的pidhash_pprev成员}

从哈希链表中删除一个文件描述符:

static inline void unhash_pid(struct task_struct *p){if(p->pidhash_next)         //如果*p不是哈希链表的尾端             p->pidhash_next->pidhash_pprev = p->pidhash_pprev; //*p下一个进程描述符的pidhash_pprev初始化为*p的pidhash_pprev        *p->pidhash_pprev = p->pidhash_next; //*p上一个进程描述符的指针指向*p的下一个文件描述符,由以上两句把进程描述符*p从链表中独立出来,即删除。}

根据进程pid查找进程描述符的指针:

static inline struct task_struct *find_task_by_pid(int pid){struct task_struct *p;        struct task_struct **htable = &pidhash[pid_hashfn(pid)];  //根据pid计算哈希表元素地址,即进程描述符所在链表头结点的地址               for(p = *htable; p && p->pid != pid; p = p->pidhash_next) //如果pid不等于当前哈希链表节点中的pid字段,则扫描下一个节点,直到相等;return p;      //找到返回进程描述符的指针}