linux内核链表分析
2013-09-29 17:03
267 查看
linux内核的链表一般都是双向循环链表,双向循环链表的效率是最高的,找头节点,尾节点,直接前驱,直接后继时间复杂度都是O(1),而使用单链表,单向循环链表或其他形式的链表是不能完成的。
linux内核链表最大特点就是它的通用性,不必因为结构体中的数据域的不通而单独为操作链表设计一套方案.
linux内核在linux/list.h文件中定义了内核通用链表list_head类型基本结构:
LIST_HEAD和INIT_LIST_HEAD都是对表头进行初始化,使next
和 prev指向自己。
通过这个函数看这个链表的前节点和后节点是否相等判断是否为空。
插入
向一个链表插入有两种方式:一是在头节点后面插入新节点,二是在链表末尾插入新节点。
(1)在头节点后面插入新节点
(2)在链表末尾插入新节点
这里采用头插法,也可改成为插法测试结果。
linux内核链表最大特点就是它的通用性,不必因为结构体中的数据域的不通而单独为操作链表设计一套方案.
linux内核在linux/list.h文件中定义了内核通用链表list_head类型基本结构:
/* * Simple doubly linked list implementation. * * Some of the internal functions ("__xxx") are useful when * manipulating whole lists rather than single entries, as * sometimes we already know the next/prev entries and we can * generate better code by using them directly rather than * using the generic single-entry routines. */ struct list_head { struct list_head *next, *prev; }; list_head定义了一个双向链表。 然后对链表头进行初始化,可使用两种方法进行。 /* * Simple doubly linked list implementation. * * Some of the internal functions ("__xxx") are useful when * manipulating whole lists rather than single entries, as * sometimes we already know the next/prev entries and we can * generate better code by using them directly rather than * using the generic single-entry routines. */ struct list_head { struct list_head *next, *prev; }; #define LIST_HEAD_INIT(name) { &(name), &(name) } #define LIST_HEAD(name) \ struct list_head name =LIST_HEAD_INIT(name) static inline void INIT_LIST_HEAD(struct list_head *list) { list->next = list; list->prev = list; }
LIST_HEAD和INIT_LIST_HEAD都是对表头进行初始化,使next
和 prev指向自己。
** * list_empty - tests whether a list is empty * @head: the list to test. */ static inline int list_empty(const struct list_head *head) { return head->next == head; }
** * list_empty - tests whether a list is empty * @head: the list to test. */ static inline int list_empty(const struct list_head *head) { return head->next == head; }
通过这个函数看这个链表的前节点和后节点是否相等判断是否为空。
插入
向一个链表插入有两种方式:一是在头节点后面插入新节点,二是在链表末尾插入新节点。
(1)在头节点后面插入新节点
/* * 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); }
(2)在链表末尾插入新节点
/** * 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); } /* * 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(struct list_head *entry) { __list_del(entry->prev, entry->next); entry->next = (void *)0xDEADBEEF; entry->prev = (void *)0xBEEFDEAD; } #else extern void list_del(struct list_head *entry); #endif 遍历 /** * list_first_entry - get the first element from a list * @ptr: the list head to take the element from. * @type: the type of the struct this is embedded in. * @member: the name of the list_struct within the struct. * * Note, that list is expected to be not empty. */ #define list_first_entry(ptr, type, member) \ list_entry((ptr)->next, type, member) 从头节点的下一个节点开始遍历,一直末尾。 删除 /** * 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(struct list_head *entry) { __list_del(entry->prev, entry->next); entry->next = (void *)0xDEADBEEF; entry->prev = (void *)0xBEEFDEAD; } #else extern void list_del(struct list_head *entry); #endif 测试代码 #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/list.h> MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("List Module"); MODULE_ALIAS("List module"); struct student { char name[100]; int num; struct list_head list; }; struct student *pstudent; struct student *tmp_student; struct list_head student_list; struct list_head *pos; int mylist_init(void) { int i = 0; INIT_LIST_HEAD(&student_list); pstudent = kmalloc(sizeof(struct student)*5,GFP_KERNEL); memset(pstudent,0,sizeof(struct student)*5); for(i=0;i<5;i++) { sprintf(pstudent[i].name,"Student%d",i+1); pstudent[i].num = i+1; list_add( &(pstudent[i].list), &student_list); } list_for_each(pos,&student_list) { tmp_student = list_entry(pos,struct student,list); printk("<0>student %d name: %s\n",tmp_student->num,tmp_student->name); } return 0; } void mylist_exit(void) { int i ; /* 实验:将for换成list_for_each来遍历删除结点,观察要发生的现象,并考虑解决办法 */ for(i=0;i<5;i++) { list_del(&(pstudent[i].list)); } kfree(pstudent); } module_init(mylist_init); module_exit(mylist_exit);
这里采用头插法,也可改成为插法测试结果。
相关文章推荐
- Linux内核2.6.14源码分析-双向循环链表代码分析(巨详细)
- linux内核――链表结构分析
- linux内核链表分析与实践
- [转]Linux内核源码分析——list链表结构
- [原理分析]linux内核中的链表原理实践[1]
- linux内核部件分析(四)——更强的链表klist
- linux内核分析--内核中的数据结构之双链表(续)
- Linux内核链表深度分析
- [原理分析]linux内核中的链表原理实践[3]
- linux内核中链表代码分析---list.h头文件分析(一)
- linux内核之链表结构分析
- linux内核struct链表程序与分析
- linux内核链表分析
- linux内核链表分析与实践
- linux内核中链表代码分析---list.h头文件分析(二)
- linux内核链表分析
- linux内核链表分析
- 链表的艺术——Linux内核链表分析
- Linux内核链表深度分析【转】
- linux内核链表分析