linux内核编程之list_head
来源:互联网 发布:js escape替代方法 编辑:程序博客网 时间:2024/06/04 20:01
【版权声明:转载请保留出处:blog.csdn.net/gentleliu。邮箱:shallnew*163.com】
linux内核头文件 #include <linux/list.h> 中定义了一个list_head类型的结构体:
struct list_head {struct list_head *next, *prev;};
一般我们的链表节点都包含许多成员,要使用list_head结构体来构造链表的话需要将该结构体嵌入节点结构,可以声明节点结构体如下:
struct todo_struct { int count; struct list_head list;};
节点之间时通过list成员来进行连接。
使用前需要首先声明一个链表头,并初始化。
struct list_head todo_list;INIT_LIST_HEAD(&todo_list);
初始化的实现如下:
static inline void INIT_LIST_HEAD(struct list_head *list){list->next = list;list->prev = list;}
向该链表添加节点使用list_add和list_add_tail函数
list_add(&pnode->list, &todo_list);//在头部添加list_add_tail(&pnode->list, &todo_list);//在尾部添加
其中第一个参数是将要加入到链表的节点结构体中的list_head成员,第二个参数为该链表的头结点或链表中某一个节点中list_head成员,新的节点将在第二个参数的前面或后面加入。
函数实现如下:
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;}static inline void list_add(struct list_head *new, struct list_head *head){__list_add(new, head, head->next);}static inline void list_add_tail(struct list_head *new, struct list_head *head){__list_add(new, head->prev, head);}
删除链表节点使用list_del函数
list_del(struct list_head *entry);
该函数删除拥有参数list_head结构的链表节点。
该函数实现如下:
static inline void __list_del(struct list_head * prev, struct list_head * next){next->prev = prev;prev->next = next;}static inline void list_del(struct list_head *entry){__list_del(entry->prev, entry->next);entry->next = NULL;entry->prev = NULL;}
判断链表是否为空使用函数list_empty,实现如下:
static inline int list_empty(const struct list_head *head){return head->next == head;}当我们遍历该链表时是通过链表list_head中两个的成员来寻找的,但是我们得到的也仅仅是节点结构体中list_head结构体的地址,我们需要得到的是整个结构体的地址,并通过该地址得到该结构体里面的其他成员的值。怎么办呢?我们可以使用宏list_entry(struct list_head *ptr, type_of_struct, field_name)来达到这个目的,该宏可以将list_head指针映射回包含它的大结构指针。
ptr指向正在被使用的list_head的指针,type_of_struct是包含list_head的大结构体类型,field_name是大结构体中拥有list_head类型的变量名字,在本例中为list。
struct todo_struct *pnode = NULL;struct list_head *ptr = NULL;pnode = list_entry(ptr, struct todo_struct, list);此处可以通过传入的list_head指针p得到的拥有该指针的大结构体pnode地址,此时就可以取得结构体中任意变量的值了。
一般我们遍厉一个链表都使用一个循环来实现,如下:
for (ptr = todo_list.next; ptr != &todo_list; ptr = ptr->next) {pnode = list_entry(ptr, struct todo_struct, list);// ......}
事实上内核实现了遍厉链表的宏:
#define list_for_each(pos, head) \for (pos = (head)->next; prefetch(pos->next), pos != (head); \pos = pos->next)所以上面代码可以修改为:
list_for_each(pos, head) {pnode = list_entry(p, struct todo_struct, list);// ......}
当我们循环遍厉时可能会删除节点,此时可以使用另外一个宏:
list_for_each_safe(struct list_head *curser, struct list_head *next, struct list_head *list);
他只是简单的在循环开始处把链表下一项存储在next中。
其实现如下:
#define list_for_each_safe(pos, n, head) \for (pos = (head)->next, n = pos->next; pos != (head); \pos = n, n = pos->next)
事实上list_head还实现了将list_for_each_safe)和list_entry合起来使用的宏:
list_for_each_entry(type cursor, struct list_head *list, member);list_for_each_entry_safe(type cursor, type next, struct list_head *list, member);
使用该宏就不需要在循环内调用lit_entry了。
其实现如下:
#define list_for_each_entry(pos, head, member)\for (pos = list_entry((head)->next, typeof(*pos), member);\ &pos->member != (head); \ pos = list_entry(pos->member.next, typeof(*pos), member))#define list_for_each_entry_safe(pos, n, head, member)\for (pos = list_entry((head)->next, typeof(*pos), member),\n = list_entry(pos->member.next, typeof(*pos), member);\ &pos->member != (head);\ pos = n, n = list_entry(n->member.next, typeof(*n), member))
下面给一个我的一个简单使用示例:
#include <linux/kernel.h>#include <linux/module.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/string.h>// #include <linux/spinlock.h>#include <linux/list.h>struct todo_struct { int count; struct list_head list;};struct list_head todo_list;//rwlock_t list_lock = RW_LOCK_UNLOCKED;void sln_list_create(void){ int i = 0; struct todo_struct *pnode = NULL; for (i = 0; i < 10; i++) { pnode = (struct todo_struct *)kmalloc(sizeof(struct todo_struct), GFP_ATOMIC); if (NULL == pnode) { return; } pnode->count = i;// write_lock(&list_lock); list_add_tail(&pnode->list, &todo_list);// write_unlock(&list_lock); }}void sln_list_del(int val){ struct todo_struct *pnode = NULL; struct list_head *p = NULL;// write_lock(&list_lock); list_for_each(p, &todo_list) { pnode = list_entry(p, struct todo_struct, list); if (pnode->count == val) { list_del(p);// write_unlock(&list_lock); return ; } }// write_unlock(&list_lock);}void sln_list_del2(int val){ struct todo_struct *pnode = NULL; struct list_head *p = NULL, *next = NULL;// write_lock(&list_lock); list_for_each_safe(p, next, &todo_list) { pnode = list_entry(p, struct todo_struct, list); if (pnode->count == val) { list_del(p);// write_unlock(&list_lock); return ; } }// write_unlock(&list_lock);}void sln_list_traverse(void){ struct todo_struct *pnode = NULL; struct list_head *p = NULL;// read_lock(&list_lock); list_for_each(p, &todo_list) { pnode = list_entry(p, struct todo_struct, list); printk(KERN_ALERT"%d\n", pnode->count); } printk(KERN_ALERT"\n");// write_lock(&list_lock);}void sln_list_traverse2(void){ struct todo_struct *pnode = NULL; list_for_each_entry(pnode, &todo_list, list) { printk(KERN_ALERT"%d\n", pnode->count); }}static __init int sln_list_init(void){ printk(KERN_ALERT"=====%s=====\n", __func__); INIT_LIST_HEAD(&todo_list); sln_list_create(); sln_list_traverse(); sln_list_del(6); sln_list_traverse(); sln_list_del2(4); sln_list_traverse2(); return 0;}static __exit void sln_list_exit(void){ printk(KERN_ALERT"=====%s=====\n", __func__);}module_init(sln_list_init);module_exit(sln_list_exit);MODULE_LICENSE("GPL");
2 0
- linux内核编程之list_head
- linux内核之list_head
- linux 内核分析之list_head
- linux 内核分析之list_head
- linux 内核分析之list_head
- linux 内核分析之list_head
- linux 内核分析之list_head
- linux 内核分析之list_head
- linux 内核分析之list_head
- linux 内核分析之list_head
- linux 内核分析之list_head
- linux 内核分析之list_head
- linux 内核分析之list_head
- linux 内核分析之list_head
- linux 内核分析之list_head
- linux 内核分析之list_head
- linux 内核分析之list_head
- Linux内核模块编程_struct list_head
- Silverlight基础学习1/23
- git tip: How to undo an uncommitted change/deletion for a specific file in your working directory
- struts2的执行流程分析
- 高性能C++网络库libtnet实践:comet单机百万连接挂载测试
- c++学习笔记(12.继承与多态)
- linux内核编程之list_head
- 基于QMainWindow主窗体程序
- UML图 符号的定义
- 图像检索中一些特征索引技术
- 阿里巴巴集团2014秋季校园招聘笔试题
- kaldi上的深度神经网络(Deep Neural Networks in Kaldi)
- Quick share by "Python -m SimpleHTTPServer 8000"
- ios提交二进制
- SIGCOMM13论文简要选读