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_LIST static 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; } #else extern 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_LIST static 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; } #else extern 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 的却别是显而易见的。*/
至此,内核链表有了本质的认识,那么对于其他的链表操作的分析是非常容易的。
时间: 2024-12-19 07:45:35