Linux内核设备驱动之内核中链表的使用笔记整理

Linux内核设备驱动之内核中链表的使用笔记整理

1. 简介

在Linux内核中,链表(linked list)是一个常用的数据结构,用于实现不同的数据结构,例如队列、栈、哈希表等。链表的结构相对于数组更加灵活,可以动态地添加和删除元素,但是在访问链表中的元素时需要遍历整个链表,因此访问速度相对较慢。在驱动程序中,链表的使用也很普遍,例如用于管理设备队列、内存块等。

Linux内核提供了链表实现的头文件<linux/list.h>,通过struct list_head结构体定义链表节点。每个节点包含两个指针,next指向链表的下一个节点,prev指向链表的前一个节点。所以可以通过链表遍历访问链表中的所有节点。以下将从链表的定义、初始化、添加/删除、遍历等方面进行详细介绍。

2. 链表定义与初始化

链表是由多个链表节点构成的,每个链表节点都有其自己的数据域和指向前一个节点和后一个节点的指针。所以链表节点的定义如下:

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

struct list_head即是一个链表节点。

在定义好链表节点结构体之后,就可以定义链表了,链表即是由多个链表节点构成的,形式上”的链表即是指向链表节点的指针。

struct list_head my_list_head;

链表的初始化可以使用INIT_LIST_HEAD宏来完成。该宏将链表的头部节点设为空,使所有节点都不再被链接起来。

INIT_LIST_HEAD(&my_list_head);

3. 添加/删除节点

链表添加/删除节点的操作是非常常见的操作。本部分将介绍如何在链表中添加/删除节点。

链表中的每一个元素都被形式化地视为一个链表节点,它的链表属性通过list_head数据结构而实现,我们可插入任何的元素到这个节点的前面或者后面。

以下代码展示如何插入一个元素(一个inode)到链表中。

void add_to_list(struct inode *node, struct list_head *head)
{
    list_add(&node->list, head);
}

list_add是一个Linux提供的宏,以下是它的定义:

#define list_add(new, head) __list_add((new), (head), (head)->next)

可以看到,list_add函数的参数中,第一个参数new是新的节点,第二个参数head是链表的头部节点,第三个参数则是new节点添加的位置。将新节点插入到链表头部或尾部的代码如下:

# 链表头部插入新节点
void add_to_head(struct inode *node, struct list_head *head)
{
    list_add(&node->list, head);
}

# 链表尾部插入新节点
void add_to_tail(struct inode *node, struct list_head *head)
{
    list_add_tail(&node->list, head);
}

在链表中删除一个节点,可以使用list_del宏,该宏对链表节点的前后指针进行处理,将当前节点从链表中删掉:

void delete_one_node(struct inode *node, struct list_head *head)
{
    list_del(&node->list);
}

4. 遍历链表

遍历链表是必不可少的,而Linux内核链表的遍历有两种方式,一种是while loop遍历,另一种则是各种带有foreach宏的快捷方式,以下详细介绍这两种方式。

遍历链表的基本操作就是从链表的头部节点依次往下遍历,对于每一个节点执行想要的操作,这里我们展示如何遍历整个链表并输出每一个节点的地址信息:

void traverse_list(struct list_head *head)
{
    struct inode *pos, *next;
    list_for_each_entry_safe(pos, next, head, list) {
        printk(KERN_INFO "entry: %p\n", pos);
    }
}

在上述代码中,list_for_each_entry_safe是一个宏,其依次遍历链表中的每一个节点,在节点的list成员中获取前/后指针(pos),在代码块中对pos节点进行操作,next则是遍历保护结构体,防止在遍历时节点被意外地删除。

阅读剩余 49%

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Linux内核设备驱动之内核中链表的使用笔记整理 - Python技术站

(0)
上一篇 2023年6月27日
下一篇 2023年6月27日

相关文章

  • Linux系统中查找文件的方法

    Linux系统中查找文件的方法有很多种,以下是其中常用的几种方法及详细步骤。 1. 使用find命令查找文件 find命令用于在目录树中搜索指定文件,并可以按文件名、文件类型、文件日期、文件大小等条件进行定位。具体操作步骤如下: find <搜索路径> <搜索条件> <操作> 其中,搜索路径表示要搜索的目录或文件,可以指定…

    other 2023年6月26日
    00
  • java动态绑定和静态绑定用法实例详解

    Java动态绑定和静态绑定用法实例详解 简介 Java中的绑定指的是将方法/变量与对象或类关联起来的过程。Java中有两种绑定方式:静态绑定和动态绑定。本文将会详细介绍这两种绑定方式的用法,以及基于它们的使用场景。 静态绑定 静态绑定是在编译时将方法或变量与对象或类关联起来的过程。静态方法或变量在编译时就已经绑定,无法在运行时更改。 下面是一个静态绑定的示例…

    other 2023年6月26日
    00
  • python基于双向链表实现LFU算法

    Python基于双向链表实现LFU算法的攻略如下: 什么是LFU算法? LFU(Least Frequently Used)算法是一种低级别的缓存淘汰策略,可用于解决缓存溢出问题。简单来说,当缓存已满且需要为新数据腾出空间时,该算法会淘汰最不频繁使用的数据。 LFU算法如何实现? 针对缓存中每条数据,需要记录3个重要信息:key、value和frequenc…

    other 2023年6月27日
    00
  • 详解Android项目多服务端接口适配(超简单)

    来详细讲解一下这篇文章的完整攻略。 标题 文章的标题是“详解Android项目多服务端接口适配(超简单)”,其中包含需要解决的问题,即多个服务端接口的适配问题,同时突出了解决方案的简单性。 问题描述 在现代的Android项目中,往往需要同时适配多个服务端接口,而这些接口可能存在着不同的数据格式、参数等问题,给开发时带来很大的困难。我们需要针对这些问题进行一…

    other 2023年6月27日
    00
  • 浅谈SpringBoot如何自定义Starters

    下面我来详细讲解“浅谈SpringBoot如何自定义Starters”的完整攻略。 什么是Starters Starters是SpringBoot的一个重要特性,它是SpringBoot在多个场景中预先定义的一组依赖包和默认配置。当我们创建SpringBoot应用时,只需要根据自己的需求添加对应的Starter依赖,就可以快速构建出符合要求的应用程序。 比如…

    other 2023年6月25日
    00
  • mysql如何判断是不是空字符串

    MySQL如何判断是不是空字符串 在MySQL中,判断一个字段是否为空字符串在实际应用中非常常见。下面介绍几种方法。 1. 使用 = 来判断 最简单的方法是使用等号来判断一个字段是否为空字符串。例如: SELECT * FROM my_table WHERE my_column = ”; 上面这条 SQL 语句会查询 my_table 表中 my_colu…

    其他 2023年3月28日
    00
  • C语言修炼之路数据类型悟正法 解析存储定风魔上篇

    C语言修炼之路数据类型悟正法 解析存储定风魔上篇攻略 引言 C语言是一门经典的程序设计语言,操作系统、驱动程序、嵌入式开发等领域都广泛应用。C语言数据类型悟正法是C语言学习中的重要环节,本攻略从数据类型的本质和存储特点入手,系统解析C语言数据类型,以期对C语言有更深入的理解和认识。 常见数据类型 C语言的数据类型包括基本数据类型和派生数据类型两类。 基本数据…

    other 2023年6月27日
    00
  • 详细讲解HTTP协议工作方式

    下面是详细讲解HTTP协议工作方式的完整攻略: HTTP协议工作方式 HTTP是超文本传输协议(HyperText Transfer Protocol)的缩写。它是互联网上应用最广泛的一种网络协议,主要用于Web浏览器和Web服务器之间的数据通信。HTTP协议是基于请求/响应模式工作的。客户端向服务器发送HTTP请求,服务器接收请求并向客户端返回HTTP响应…

    other 2023年6月27日
    00
合作推广
合作推广
分享本页
返回顶部