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
原创粉丝点击