Linux设备驱动系列(16) —— 链表Linked List

article/2025/6/13 21:59:51

链表是一种数据结构,由一系列节点组成,每个节点包含数据部分和指向下一个节点的指针。链表可以动态增长或缩小,适合频繁插入和删除操作。常见的类型有单向链表、双向链表和循环链表。虽然访问速度较慢,但灵活性和操作效率使其在许多应用中非常有用。

本文将介绍Linux内核中提供的链表数据结构。

01

Linux中的链表

链表作为一种非常重要的数据结构,允许高效地存储和操作大量数据,在内核代码中链表的使用随处可见。

在Linux内核中,开发者无需自己实现链表或使用第三方库,内核内置了双向链表的实现struct list_head ,定义在linux/list.h头文件中。

02

Linux链表使用

下面将详细介绍Linux内核链表的常用接口和使用方式。

2.1

链表头初始化

Linux内核链表用链表头list_head来表示,因此链表的初始化其实就是初始化一个链表头。

LIST_HEAD宏将创建一个名为linked_list的链表,它是一个双向链表,即在没有插入任何节点之前,它的首尾指针都指向自身(也可以认为首尾指针指向自身时表示链表是空的)。

LIST_HEAD的内部实现如下:

#defineLIST_HEAD(name) \struct list_head name = LIST_HEAD_INIT(name)

structlist_head{structlist_head*next;structlist_head*prev;};

因此上面的初始化展开后是下面这个样子:

2.2

创建链表节点

Linux内核的链表节点也使用struct list_head来表示,它通常内嵌在自定义的数据结构中:

structmy_nodenode;

链表节点在插入链表之前也需要进行初始化,使用INIT_LIST_HEAD宏,例如:

2.3

添加节点到链表中

链表节点初始化完成后,就可以往链表中添加节点:

其中head表示链表头,new是要添加的节点。list_add将new添加到链表头部,而list_add_tail添加到链表尾部。

2.4

从链表中删除节点

从链表中删除节点实际上就是修改了一下节点及其相邻节点的prev和next指针指向,它不会释放节点的内存:

其中list_del_init在删除节点后还对该节点重新进行初始化操作。

2.5

从链表中替换节点

和删除节点同理,替换节点也只是修改了prev和next指针指向,并且list_replace_init还会对替换出来的节点(old)进行重新初始化操作:

2.6

移动链表中的节点

下面的函数中,list表示要移动的节点,list_move将其移动到链表首部,list_move_tail将其移动到链表尾部:

2.7

旋转链表节点

list_rotate_left 是 Linux 内核中用于双向链表操作的一个函数,它用于将链表的第一个节点移动到最后一个位置。这个操作可以看作是将链表左旋一次。

2.8

检查链表

Linux内核还提供了检查链表的相关函数,例如:

  • list_is_last:检查节点是否是链表最后一个节点。

  • list_empty:链表是否为空。

  • list_is_singular:链表是否只有一个节点。

list_is_last:检查节点是否是链表最后一个节点。

list_empty:链表是否为空。

list_is_singular:链表是否只有一个节点。

2.9

链表分割

list_cut_position函数用于将一个双向链表从指定位置剪切出来,形成一个新的链表段,其中:

  • list是新链表头指针。

  • head是原链表头指针。

  • entry指向原链表中某个节点的指针,从这个节点开始分割链表。

list是新链表头指针。

head是原链表头指针。

entry指向原链表中某个节点的指针,从这个节点开始分割链表。

2.10

链表连接

list_splice是 Linux 内核中用于将一个链表合并到另一个链表中的函数。它可以将整个链表 list 插入到 head 链表中,或者更具体地,将list链表插入到head链表首部。

2.11

链表遍历

Linux内核提供了一系列的函数来遍历和操作链表中的元素:

  • list_entry(ptr, type, member):通过链表节点的指针获取包含该节点的结构体指针。

  • list_for_each(pos, head):遍历链表中的每个节点。

  • list_for_each_entry(pos, head, member):遍历链表中的每个结构体实例。

  • list_for_each_entry_safe ( pos, n, head, member):安全地遍历链表中的每个结构体实例,可以在遍历过程中安全地删除节点。

  • list_for_each_prev(pos, head):逆向遍历链表中的每个节点。

  • list_for_each_entry_reverse(pos, head, member):逆向遍历链表中的每个结构体实例。

list_entry(ptr, type, member):通过链表节点的指针获取包含该节点的结构体指针。

list_for_each(pos, head):遍历链表中的每个节点。

list_for_each_entry(pos, head, member):遍历链表中的每个结构体实例。

list_for_each_entry_safe ( pos, n, head, member):安全地遍历链表中的每个结构体实例,可以在遍历过程中安全地删除节点。

list_for_each_prev(pos, head):逆向遍历链表中的每个节点。

list_for_each_entry_reverse(pos, head, member):逆向遍历链表中的每个结构体实例。

03

Linux链表代码演示

kernel_driver.c

volatileintmy_value = 0;

structmy_node{structlist_headlist;intdata;};staticLIST_HEAD(my_list);

staticstructworkqueue_struct*own_workqueue;

staticvoidstatic_wq_fn(struct work_struct *work){structmy_node*node= NULL;

pr_info("Static workqueue function called on CPU[%d]\n", smp_processor_id);

node = kmalloc(sizeof(struct my_node), GFP_KERNEL);node->data = my_value;INIT_LIST_HEAD(&node->list);list_add_tail(&node->list, &my_list);}staticDECLARE_WORK(static_work, static_wq_fn);

staticvoiddynanic_wq_fn(struct work_struct *work){pr_info("Dynamic workqueue function called on CPU[%d]\n", smp_processor_id);}staticstructwork_structdynamic_work;

#defineIRQ_NO 63

staticirqreturn_t irq_handler(intirq, void*dev_id){pr_info("Shared IRQ[%d]: Interrupt Occurred\n", irq);queue_work(own_workqueue, &static_work);queue_work_on(3, own_workqueue, &dynamic_work);returnIRQ_HANDLED;}

dev_tdev = 0;staticstructclass*dev_class;staticstructcdevmy_cdev;structkobject*kobj_ref;

staticssize_t sysfs_show(struct kobject *kobj,struct kobj_attribute *attr, char*buf){returnsprintf(buf, "%d", my_value);}

staticssize_t sysfs_store(struct kobject *kobj,struct kobj_attribute *attr, constchar*buf, size_tcount){sscanf(buf, "%d", &my_value);returncount;}

structkobj_attributemy_attr= __ATTR(my_value, 0660, sysfs_show, sysfs_store);

staticssize_t my_read(struct file *filp,char__user *buf, size_tlen, loff_t*off){structmy_node*node;inti = 0;

list_for_each_entry(node, &my_list, list){pr_info("Node[%d] { data = %d }\n", i++, node->data);}

pr_info("Total Nodes = %d\n", i);return0;}

staticssize_t my_write(struct file *filp,constchar__user *buf, size_tlen, loff_t*off){char__buf[10] = {0};

if(copy_from_user(__buf, buf, len) == 0) {pr_info("Write: %s", __buf);sscanf(__buf, "%d", &my_value);}generic_handle_irq(IRQ_NO);returnlen;}

staticstructfile_operationsfops= {.owner = THIS_MODULE,.read = my_read,.write = my_write,};

staticint__init my_driver_init(void){if((alloc_chrdev_region(&dev, 0, 1, "my_dev")) < 0)return-1;

cdev_init(&my_cdev, &fops);my_cdev.owner = THIS_MODULE;my_cdev.ops = &fops;

if((cdev_add(&my_cdev, dev, 1)) < 0)gotor_class;

if(IS_ERR(dev_class = class_create(THIS_MODULE, "my_class")))gotor_class;

if(IS_ERR(device_create(dev_class, NULL, dev, NULL, "my_device")))gotor_device;

kobj_ref = kobject_create_and_add("my_sysfs", kernel_kobj);if(sysfs_create_file(kobj_ref, &my_attr.attr))gotor_sysfs;

if(request_irq(IRQ_NO, irq_handler, IRQF_SHARED,"my_device", (void*)(irq_handler)))gotoirq;

INIT_WORK(&dynamic_work, dynanic_wq_fn);

own_workqueue = create_workqueue("own_wq");

return0;irq:free_irq(IRQ_NO, (void*)(irq_handler));r_sysfs:kobject_put(kobj_ref);sysfs_remove_file(kernel_kobj, &my_attr.attr);

r_device:device_destroy(dev_class, dev);class_destroy(dev_class);r_class:unregister_chrdev_region(dev, 1);cdev_del(&my_cdev);return-1;}

staticvoid__exitmy_driver_exit(void){structmy_node*cur, *next;list_for_each_entry_safe(cur, next, &my_list, list){list_del(&cur->list);kfree(cur);}

destroy_workqueue(own_workqueue);free_irq(IRQ_NO, (void*)(irq_handler));kobject_put(kobj_ref);sysfs_remove_file(kernel_kobj, &my_attr.attr);device_destroy(dev_class, dev);class_destroy(dev_class);cdev_del(&my_cdev);unregister_chrdev_region(dev, 1);}

module_init(my_driver_init);module_exit(my_driver_exit);

MODULE_LICENSE("GPL");MODULE_AUTHOR("feifei <feifei@gmail.com>");MODULE_DEION("A simple device driver");MODULE_VERSION("1.15");

代码编译运行,运行结果如下:


http://www.hkcw.cn/article/ktPBrWFsbf.shtml

相关文章

期限最长50年!财政部重磅发布

今年,我国将发行1万亿元的超长期特别国债。5月13日,财政部公布了2024年一般国债、超长期特别国债发行的有关安排。 根据安排,超长期特别国债期限包括20年期、30年期、50年期,都是按半年付息。其中,30年期最先将在5月17日发行。5月24日发行20年超长期特别国债,6月14日发行…

汪峰正式官宣新女友!女方照片曝光,引全网争议:比章子怡还漂亮

来源|闲时花开(ID:xsha369) 母亲节那天,和章子怡离婚不过7个月的峰哥,被曝光了新女友。 话说当天晚上,汪峰被拍到带着儿子女儿,和一众好友聚餐。 吃完饭后,有个苗条优雅的长发女子,下楼梯时紧紧牵着汪峰的儿女。 孩子们也和她有说有笑,几个人亲近又自然,看起来就像一…

原创噩耗!26岁网红安然胃癌去世,最后5个月未进食,好友曝揪心细节

4月15日,抗癌网红圈,又一次传来了不好的消息,来自广东的知名抗癌网红安然,罹患胃癌不幸离世,年仅26岁,花季少女般的年龄,这就样永远的凋零,实在令人惋惜不已。据悉,安然是在22年8月底的时候,突然感觉肚子异常凸起,精力跟不上,因为觉得自己年轻平时健康状况良好,因…

部编版七年级语文上册第5课《秋天的怀念》知识点+图文解读+同步练习

第5课 秋天的怀念 课文电子版课文朗读 展开全文课文知识点 一、文常 《秋天的怀念》体裁:散文,选自《史铁生作品集》。 作者:史铁生,北京人,当代作家。代表作:小说《我的遥远的清平湾》《命若琴弦》《务虚笔记》;散文集《我与地坛》《病隙碎笔》。 作者与背景 史铁…

原创音乐剧的演变与发展:从古典到现代

音乐剧是一种结合音乐、歌唱、舞蹈和戏剧元素的表演艺术形式,本文将探讨音乐剧的起源和演变,并详细分析其在不同历史时期的发展轨迹。 从古典音乐剧到现代音乐剧,我们将回顾音乐剧的历史,探究其艺术特点、主题内容和影响力,以及对文化传承和观众的吸引力。 通过研究音乐剧…

原创袭人最后为何被薛宝钗撵出府?你看她和贾宝玉偷试后,都干了些啥

在《红楼梦》中,袭人作为贾宝玉的贴身丫鬟,一直以来都是个备受关注的角色。而且她聪明机灵,深得贾母和王夫人的信任。然而,她最终却被薛宝钗撵出了贾府,这是为啥?其实看看她干了什么就能理解了,我们一起来了解一下。贾府中的野心丫鬟 袭人,原名花袭人,本是一个出身贫苦…

成人网站的诱惑及潜在风险

在现代社会中,越来越多的人开始接触并使用互联网,这使得成人网站成为了许多年轻人的消遣方式之一。然而,这些网站所带来的诱惑和潜在风险不容忽视。本文将探讨浏览成人网站的可能影响及其对个人隐私的危害。 首先,频繁浏览成人网站可能导致沉迷其中无法自拔。起初,人们可能…

关于氟化氢(氢氟酸)的包装与储存,知道这一篇就够了!

关于氟化氢(氢氟酸)的包装与储存,知道这一篇就够了!氟化氢,是一种无机化合物,化学式为HF,在常态下是一种无色、有刺激性气味的有毒气体,具有非常强的吸湿性,接触空气即产生白色烟雾,易溶于水,可与水无限互溶形成氢氣酸。氣化氢分子间具有氢键,可表现出一些反常的性质,…

2024年日元升值前景分析

随着日本经济的逐步复苏,市场预期央行可能在未来实现货币政策正常化,从而推动日元升值至135附近。自2012年再次担任首相以来,安倍政府采取了一系列政策措施,被称为“安倍经济学”,旨在提振疲软的经济表现。这些措施包括负利率政策和大规模的货币宽松计划,以提高通胀率、贬…

原创王英既然打不过扈三娘,新婚当日是如何进的洞房?原因很简单

前言 阴差阳错之下,她竟成了他的新娘,这一切,又是如何发生的?扈三娘,一个与众不同的女子。她不喜樱桃小口,不爱罗绮窗帘,只爱马革弓弦。一身铠甲,一双利刃,彰显的正是她的与众不同。 在扈家庄,扈三娘的身手之高强,足以媲美她的兄长。村民们见了她莫不叹服赞叹,心中…

原创70年代政治新星李德生,数年从地方升任中央,毛主席多次赞扬他

在上个世纪七十年代,有很多不太寻常的事情。 同样,在当时也有着不少人在短短的数年时间,就从基层一步跃迁到中央,有些更是官至最高领导层。 其中,开国少将李德生就是这样的一个人,原本建国以后,他本是安徽省革委会主任,但是几经辗转,很快便进入到了中共中央政治局,甚…

红魔9S Pro评测:游戏更稳更极致 AI陪你玩游戏很欢乐

红魔一直是当下手机市场中少有坚持游戏手机的厂商。它坚持主动散热的设计可以说是游戏手机的最优解之一了,就在去年年底,它带来了强悍的红魔9 Pro系列,纯平的机身、无挖孔的屏幕、强悍的第三代骁龙8以及最新的主动散热系统,让它成为了游戏手机的不二之选。时隔半年多,红魔…

什么是衣冠南渡?衣冠南渡的典故,衣冠南渡直接推动了什么

衣冠南渡是一个源自中国历史的典故,原指西晋末年,中原地区因战乱而发生的大规模人口南迁现象。这一事件标志着中原士族、士大夫等因避乱而向南迁移,并在此过程中,中原文明或中原政权也随之南迁。随着时间的推移,这一概念逐渐演化为一个熟典,代指缙绅、士大夫等因避乱…

蔡崇达《草民》:在泉州沿海小镇里找到自己的影子

著名作家蔡崇达的全新中短篇小说集《草民》于2024年6月上市,该书由广州新华出版发行集团策划,广州出版社出版。这是继《皮囊》《命运》之后蔡崇达的又一力作,三部作品共同构筑成“故乡三部曲”。《草民 》与此前的《皮囊》《命运》 构成“故乡三部曲” 不同于刻骨铭心的散文…

托勒密定理

数学教学研究本公众号内容均由邵勇本人独创,可以转发,但转载则需获得邵勇本人的授权。每周推送两到三篇内容上有份量的数学文章,但在行文上力争做到深入浅出。几分钟便可读完,轻松学数学。 亚历山大里亚的托勒密(Claudius Ptolemy)生活于大约公元2世纪。今天讲以他的名字…

60种宝石的简介和寓意

✎ willgem:珠宝一刊是珠宝玉石第一微刊,资深珠宝专家主编,是你珠宝玉石类「 资讯 鉴定 收藏」最佳选择。 和宝友交流,晒宝贝分享心得,查看文章末尾加入珠宝社区吧 1、红宝石: 红宝石在传统意义中,代表了热情与爱情,所以红宝石也有“爱情之石”的叫法。自古以来,红色都…

中国新闻奖一等奖作品,新华社《全球连线》栏目解析

《全球连线》栏目是新华社打造的中外文国际传播融媒体栏目,自2021年1月创设以来,主打短视频,兼顾文字、图片等类型报道,通过中、英、法、西、阿等多个语种对外发布,依托新华社遍布全球的新闻采集网络和传播渠道,聚焦重大突发新闻、时事热点事件、舆论焦点话题和中外交往故…

长期浏览黄色网站有哪些危险?出现这3种情况,请立即停止!

互联网中丰富多彩的信息带给人们新颖和刺激的感觉。想必很多人都主动或者被动浏览过黄色网站,甚至看完后还有点愧疚感,于是便偷偷删除搜索记录、观看历史,生怕被人发现...... 殊不知这免费观看的背后早已隐藏了太多危险......长期浏览黄色网站会有哪些隐藏危险? 1.手机/电脑…

重磅!2024年执业药师考试报名入口已开通!

2024年执业药师报名入口已开通! 内蒙古、上海今日开始报名! (各地陆续开放中)报名官网:中国人事考试网24年各地执业药师报名时间表 各地报名入口开通时间不一,同学们务必仔细查看所在考区的报名时间,按时提交报名信息接受审核完成报名。点击图片查看👇展开全文📢温…