4.   5.2双向循环链表

哈希表的主要作用是根据进程的pid可以快速地找到对应的进程,但它没有反映进程创建的顺序,也无法反映进程之间的亲属关系,因此引入双向循环链表。每个进程task_struct 结构中的prev_tasknext_task域用来实现这种链表,如图4.4所示


4.4  双向循环链表

 

SET_LINK用来在该链表中插入一个元素:

#define SET_LINKS(p) do { \

      (p)->next_task = &init_task; \

      (p)->prev_task = init_task.prev_task; \

      init_task.prev_task->next_task = (p); \

      init_task.prev_task = (p); \

      (p)->p_ysptr = NULL; \

       if (((p)->p_osptr = (p)->p_pptr->p_cptr) != NULL) \

               (p)->p_osptr->p_ysptr = p; \

        (p)->p_pptr->p_cptr = p; \

       } while (0)

 

从这段代码可以看出,链表的头和尾都init_task,它对应的是进程0pid0),也就是所谓的空进程,它是所有进程的祖先。这个宏把进程之间的亲属关系也链接起来。另外,还有一个宏for_each_task()

 

#define for_each_task(p) \

        for (p = &init_task ; (p = p->next_task) != &init_task ; )

 

这个宏是循环控制语句,注意init_task的作用,因为空进程是一个永远不存在的进程,因此用它做链表的头和尾是安全的。

 

因为进程的双向循环链表是一个临界资源,因此在使用这个宏时一定要加锁,使用完后开锁。