Linux 内核链表(使用)

介绍

需要头文件:<linux/list.h>

当使用链表接口时, 你应当一直记住列表函数不做加锁. 本文将介绍内核链表简单添、删、改、查操作。并附使用示例

1.链表初始化

初始化在list.h

struct list_head { struct list_head *next, *prev; }; 

自己申请链表

struct my_list
{
        struct list_head list;
        int priority; /* driver specific */
        /* ... add other driver-specific fields */
};

列表的头常常是一个独立的 list_head 结构. 图链表头数据结构显示了这个简单的 struct list_head 是如何用来维护一个数据结构的列表的.
在这里插入图片描述
链表头必须在使用前用INIT_LIST_HEAD宏来初始化.

struct my_list my_l;
INIT_LIST_HEAD(&my_l.list); 

2.添加链表

2.1 添加链表头

static inline void list_add(struct list_head *new, struct list_head *head)

使用方法:

struct my_list new_node_01;
list_add(&new_node_01.list, &my_l.list);

2.2 添加链表尾

static inline void list_add_tail(struct list_head *new, struct list_head *head)

使用方法:

struct my_list new_node_02;
list_add_tail(&new_node_02.list, &my_l.list);

3.查询链表节点

3.1访问节点

通过遍历头节点,依次取出节点。需要注意:这个节点链表都是对struct list_head类型进行遍历的,假设找到struct lis_head,怎么去找到整个结构体,struct my_list,通过如下实现

#define list_entry(ptr, type, member) \ container_of(ptr, type, member)

可以看list_entry源码,本质是container_of实现的,即通过成员变量的指针地址,来找到整个结构体的起始地址。

使用如下:

//假设找到的节点是cur_list,注意(cur_list 类型是struct list_head)
struct my_list *find_node = list_entry(cur_list, struct my_head, list);

其中:

  • cur_list假设找到的节点
  • struct my_head是要找整个节点的结构体
  • list 是整个结构体对应的名称。根据struct my_list中成员名字决定,可以设置为其他名称

3.2遍历整个节点

#define list_for_each(pos, head) \
	for (pos = (head)->next; pos != (head); pos = pos->next)

其中:

  • pos 相当于动态位置(struct list_head类型)
  • head链表的节点(struct list_head类型)

使用方法:

struct my_list *find_node;
struct list_head *pos;
list_for_each(pos, new_node_01->list) {
	// 通过当前成员名list的指针地址pos,来找到整个struct my_list结构体的起始地址
	find_node = list_entry(pos, struct my_list, list);
}

3.删除链表节点

void list_del(struct list_head *entry);

即删除entry的节点

// 删除链表中的new_node_02节点
list_del(new_node_02.list);

样例子

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/list.h>

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;

static __init int mylist_init(void){
	int i=0;
    printk(KERN_ERR"melvin function = %s\n", __func__);

	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(KERN_ERR"melvin student %d name :%s\n", tmp_student->num, tmp_student->name);
	}

	return 0;
}

static __exit void mylist_exit(void){
	int i;
    printk(KERN_ERR"melvin function = %s\n", __func__);
	for(i=0; i < 5; i++){
		list_del(&(pstudent[i].list));
	}
	kfree(pstudent);
}

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Melvin");
MODULE_DESCRIPTION("list module");
module_init(mylist_init);
module_exit(mylist_exit);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值