【版权声明:转载请保留出处: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");