首页 > 代码库 > 深入分析Linux内核链表

深入分析Linux内核链表

1. 普通单链表

技术分享

2. 内核链表

技术分享

上图是本人从其他博客盗来的,差点被糊弄过去。

下图是本人自己用KeyNote画的(唉!!画图真的是让人心好累啊!!)。

技术分享

差异是不是很明显啊?!

Read The Fucking Source Code

1. 初始化

/* include/linux/types.h */struct list_head {    struct list_head *next, *prev;};

/* include/linux/list.h */
/*××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××*/
// 一. 如何初始化一个链表,初始化后的链表是什么鸟样?
// 链表初始化的3个方法:
// 1.
#define LIST_HEAD_INIT(name) { &(name), &(name) }
// 使用示例: struct list_head test_list = LIST_HEAD_INIT(test_list);

// 2.
#define LIST_HEAD(name) \
    struct list_head name = LIST_HEAD_INIT(name)
// 使用示例: LIST_HEAD(module_bug_list);

// 3.
static inline void INIT_LIST_HEAD(struct list_head *list)
{
    list->next = list;
    list->prev = list;
}
// 使用示例: struct list_head test_list;
        INIT_LIST_HEAD(&test_list);
/*××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××*/

就连一个链表的初始化都想的这么周到!!真屌!!

初始化后,链表就是的鸟样:

技术分享

2. 插入

/* * Insert a new entry between two known consecutive entries. * * This is only for internal list manipulation where we know * the prev/next entries already! */#ifndef CONFIG_DEBUG_LISTstatic inline void __list_add(struct list_head *new,                  struct list_head *prev,                  struct list_head *next){    next->prev = new;    new->next = next;    new->prev = prev;    prev->next = new;}#elseextern void __list_add(struct list_head *new,                  struct list_head *prev,                  struct list_head *next);#endif/** * list_add - add a new entry * @new: new entry to be added * @head: list head to add it after * * Insert a new entry after the specified head. * This is good for implementing stacks. */static inline void list_add(struct list_head *new, struct list_head *head){    __list_add(new, head, head->next);}/** * list_add_tail - add a new entry * @new: new entry to be added * @head: list head to add it before * * Insert a new entry before the specified head. * This is useful for implementing queues. */static inline void list_add_tail(struct list_head *new, struct list_head *head){    __list_add(new, head->prev, head);}
/**
* list_add 和 list_add_tail的区别是:
* list_add 始终是在链表头后的的第一个位置进行插入:例如链表:head --> 数据1 --> 数据2 --> 数据3,插入新元素后:head --> new --> 数据1 --> 数据2 --> 数据3
* list_add_tail 始终实在链表末尾插入新元素:例如链表:head --> 数据1 --> 数据2 --> 数据3,插入新元素后:head --> 数据1 --> 数据2 --> 数据3 --> new
*/
/**
* 仔细分析上述函数,可以发现其函数抽象的巧妙。
* __list_add 接收三个参数:分别是new, prev, next。任何位置的双链表插入操作,只需这3个参数。那么new元素一定是在prev和next之间进行插入。
* 所以很明显:list_add是在head和head->next之间插入,那就是链表的第一个元素。
* list_add_tail实在head->prev和head之间插入,那就是链表的最后一个元素。

*/

 3. 删除

/* * Delete a list entry by making the prev/next entries * point to each other. * * This is only for internal list manipulation where we know * the prev/next entries already! */static inline void __list_del(struct list_head * prev, struct list_head * next){    next->prev = prev;    prev->next = next;}/** * list_del - deletes entry from list. * @entry: the element to delete from the list. * Note: list_empty() on entry does not return true after this, the entry is * in an undefined state. */#ifndef CONFIG_DEBUG_LISTstatic inline void __list_del_entry(struct list_head *entry){    __list_del(entry->prev, entry->next);}static inline void list_del(struct list_head *entry){    __list_del(entry->prev, entry->next);    entry->next = LIST_POISON1;    entry->prev = LIST_POISON2;}#elseextern void __list_del_entry(struct list_head *entry);extern void list_del(struct list_head *entry);#endif

/**
* 上述代码中存在两个宏,在include/linux/poison.h中的定义如下:
*/
/*
 * These are non-NULL pointers that will result in page faults
 * under normal circumstances, used to verify that nobody uses
 * non-initialized list entries.
* 是非空指针,在正常情况下会导致 page faults,用来验证没有人使用未初始化的链表项。
 */
#define LIST_POISON1  ((void *) 0x00100100 + POISON_POINTER_DELTA)
#define LIST_POISON2  ((void *) 0x00200200 + POISON_POINTER_DELTA)

/*
* __list_del_entry 和 list_del 的却别是显而易见的。
*/

   

  至此,内核链表有了本质的认识,那么对于其他的链表操作的分析是非常容易的。

深入分析Linux内核链表