linux内核重要结构体,Linux中list_head结构体相关 | 技术部落

在Linux内核中,提供了一个用来创建双向循环链表的结构 list_head。虽然linux内核是用C语言写的,但是list_head的引入,使得内核数据结构也可以拥有面向对象的特性,通过使用操作list_head 的通用接口很容易实现代码的重用,有点类似于C++的继承机制。

下面就是kernel中的list_head结构定义:

struct list_head {

struct list_head *next, *prev;

};

list_head是linux kernel中非常重要的一个结构体,是双向链表的数据结构体,为了减少浪费,众多链表都是用list_head以及其相关原语操作,list_head这个结构看起来怪怪的,它竟没有数据域!所以看到这个结构的人第一反应就是我们怎么访问数据?其实list_head不是拿来单独用的,它一般被嵌到其它结构中:

比如所有的进程是靠它串联在一起的,所有的inode也靠它串联在一起等等。

需要注意的一点是,头结点head是不使用的,这点需要注意。

使用list_head组织的链表的结构如下图所示:

1897d57be9d8ce8e7a24cb031628036d.png

list_head

特别注意的是,list_head中的指针存放的是另一个list_head的地址,而不是含有list_head结构的整个数据结构的地址;

举例如下:

struct file_node{

char c;

struct list_head node;

};

此时list_head就作为它的父结构中的一个成员了,当我们知道list_head的地址(指针)时,我们可以通过list.c提供的宏 list_entry 来获得它的父结构的地址。下面我们来看看list_entry的实现:(list_entry: 与container_of功能相同)

#define list_entry(ptr,type,member)\

container_of(ptr,type,member)

#define offsetof(TYPE,MEMBER) ((size_t)&((TYPE *)0)->MEMBER)

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

const typeof( ((type*)0)->member ) *__mptr=(ptr);\

(type*)( (char*)__mptr - offsetof(type,member) );} )

这里涉及到三个宏,还是有点复杂的,我们一个一个来看:

#define offsetof(TYPE,MEMBER) ( (size_t)& ((TYPE *)0)-> MEMBER )

我们知道 0 地址内容是不能访问的,但 0地址的地址我们还是可以访问的, 这里用到一个取址运算符

(TYPE *)0 它表示将 0地址强制转换为TYPE类型,((TYPE *)0)-> MEMBER 也就是从0址址找到TYPE 的成员MEMBER 。

我们结合上面的结构file_node来看

将实参代入 offset( struct file_node, node );最终将变成这样:

( (size_t) & ((struct file_node*)0)-> node );这样看的还是不很清楚,我们再变变:

struct file_node *p = NULL;

& p->node;

这样应该比较清楚了,即求 p 的成员 node的地址,只不过p 为0地址,从0地址开始算成员node的地址,也就是 成员 node 在结构体 struct file_node中的偏移量。offset宏就是算MEMBER在TYPE中的偏移量的。

我们再看第二个宏

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

const typeof( ((type*)0)->member ) *__mptr=(ptr);\

(type*)( (char*)__mptr - offsetof(type,member) );} )

这个宏是由两个语句组成,最后container_of返回的结果就是第二个表达式的值。这里__mptr为中间变量,这就是list_head指针类型,它被初始化为ptr的值,而ptr就是当前所求的结构体中list_head节点的地址。为什么要用中间变量,这是考虑到安全性因素,如果传进来一个ptr++,所有ptr++放在一个表达式中会有副作用,像 (p++)+(p++)之类。

(char*)__mptr 之所以要强制类型转化为char是因为地址是以字节为单位的,而char的长度就是一个字节。

container_of的值是两个地址相减,

刚说了__mptr是结构体中list_head节点的地址,offset宏求的是list_head节点MEMBER在结构体TYPE中的偏移量,那么__mptr减去它所在结构体中的偏移量,就是结构体的地址。

所以list_entry(ptr,type,member)宏的功能就是,由结构体成员地址求结构体地址。其中ptr 是所求结构体中list_head成员指针,type是所求结构体类型,member是结构体list_head成员名。通过下图来总结一下:

ca8580b3ad7f7c50b4349acda052ec12.png

list

列举一些双链表的常用操作:

双向链表的遍历——list_for_each

//注:这里prefetch 是gcc的一个优化选项,也可以不要

#define list_for_each(pos, head) \

for (pos = (head)->next; prefetch(pos->next), pos != (head); \

pos = pos->next)

生成双向链表的头结点——LIST_HEAD()

//LIST_HEAD() -- 生成一个名为name的双向链表头节点

#define LIST_HEAD(name) \

struct list_head name = LIST_HEAD_INIT(name)

static inline void INIT_LIST_HEAD(struct list_head *list)

{

list->next = list;

list->prev = list;

}

双向链表的插入操作 -- list_add()

//将new所代表的结构体插入head所管理的双向链表的头节点head之后: (即插入表头)

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

{

__list_add(new, head, head->next);

}

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;

}

从list中删除结点——list_del()

static inline void list_del(struct list_head *entry)

{

__list_del(entry->prev, entry->next);

entry->next = LIST_POISON1;

entry->prev = LIST_POISON2;

}

static inline void __list_del(struct list_head * prev, struct list_head * next)

{

next->prev = prev;

prev->next = next;

}

判断链表是否为空(如果双向链表head为空则返回真,否则为假)——list_empty()

static inline int list_empty(const struct list_head *head)

{

return head->next == head;

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/519172.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java老矣,尚能饭否?2020 Java生态系统报告出炉

最近,Jrebel公布了一份2020 Java生态系统报告,这份报告主要关注开发人员在开发过程中使用的技术。这份报告包含了技术人员正在用的编程语言、应用程序架构、应用服务器、运行时平台、框架技术、IDE、JRE/JDK版本、数据库、部署模型、构建工具和虚拟化工具…

AI评委引热议,阿里巴巴表示:AI不会取代工程师

昨日,一位能给工程师代码打分的“AI评委”引发了热议。起因是在2019阿里巴巴“83行代码挑战赛”决赛现场,一位运行在云端的AI评委和现场的专家评委、大众评委配合,一起对选手提交的的代码做综合评价。 “AI是否会取代工程师”的话题再次在网络…

windows2012运行linux,Linux一分钟部署完毕上线运行,windows server你要折磨我两天?...

原标题:Linux一分钟部署完毕上线运行,windows server你要折磨我两天?周四晚上好,各位~~经过数度折腾之后,终于对windows累觉不爱了。且不说点点点的弊端,浪费鼠标左右键的机械力,还有无数个需要…

使用DataWorks来调度AnalyticDB任务

DataWorks作为阿里云上广受欢迎的大数据开发调度服务,最近加入了对于AnalyticDB的支持,意味着所有的AnalyticDB客户可以获得任务开发、任务依赖关系管理、任务调度、任务运维等等全方位强大的能力,现在就给大家仔细介绍下如何使用DataWorks来…

稳定、可扩展、模块化、简化部署过程、版本控制……一文看懂 Kubernetes 到底如何运用!...

来源 | Daniele Fontani编译 | 火火酱,责编 | Carol出品 | CSDN云计算(ID:CSDNcloud)说实话,我是个Kubernetes爱好者。Kubernetes是软件开发的重要一步。当我遇到它时,我就想:“这就是将容器融入…

提升不止一点点,Dubbo 3.0 预览版详细解读

Dubbo 自 2011 年 10 月 27 日开源后,已被许多非阿里系的公司使用,其中既有当当网、网易考拉等互联网公司,也不乏中国人寿、青岛海尔等大型传统企业。更多用户信息,可以访问Dubbo GitHub,issue#1012: Wanted: whos usi…

Jenkins Tutorial

什么是Jenkins Jenkins是一个自动化平台,它允许你使用pipelines去部署应用。它也可以自动化其他任务。 BUILDTESTDEPLOYMENT Jenkins 架构 首先,你拥有一个Master Server,它控制pipelines和安排Build到你的Agent上; 其次&…

阿里云首次在ASPLOS'19发布重磅论文:揭秘帮助ECS快速迭代的热升级技术

第24届ACM编程语言和操作系统(ASPLOS19),于2019年4月13日至17日,在普罗维登斯召开,阿里云高级技术专家郑晓代表团队在会上发表了技术报告。 论文主题为《Fast and Scalable VMM Live Upgrade in Large Cloud Infrastr…

痛!做C#半年,挣的不如做AI1个月?”看到第二句泪目……

前段时间在网上发现一个热门话题:“做开发一年,在北京月薪不到1万,有点迷茫。” 其中,这个回答我永远忘不了:来源:库库的派派知乎回答,已取得授权在这短短的一条信息里,小编佩服不…

联想电脑u盘安装Linux,如何使用u盘安装linux系统

ps: 请注意,硬盘不是软盘7. 选择您的U盘作为硬盘驱动器,然后写入usb hdd 8. 点击[写]三,安装系统1. 将U盘插入计算机2. 启动计算机并按住[F2]进入BIOS以修改第一个启动项3. 选择U盘后,跳转到以下界面4. 按键盘键进入第二个“测试…

源码|详解分布式事务之 Seata-Client 原理及流程

前言 在分布式系统中,分布式事务是一个必须要解决的问题,目前使用较多的是最终一致性方案。自年初阿里开源了Fescar(四月初更名为Seata)后,该项目受到了极大的关注,目前已接近 8000 Star。Seata 以高性能和…

SonarQube中配置c语言/c++语言代码规则插件

文章目录一、下载安装重新启动1. 下载文件2.安装3. 重新启动SonarQube4. SonarQube管控台验证二、SonarQube管控台配置2.1. 创建配置模板2.2. 添加规则2.3. 查看配置模板规则列表2.4. 修改默认语言规则应用2.5. C配置流程同上我是java出身,因为特殊需要,要用sonarqube做一套c代…

从虚拟化前端Bug学习分析Kernel Dump

前言 也许大家都知道,分析 Kernel Dump 有个常用的工具叫 Crash,在我刚开始学习分析 Kernel Dump 的时候,总是花大量的时间折腾这个工具的用法,却总是记不住这个工具的功能。后来有一次在参加某次内部分享的时候,有位…

Apache Shiro RememberMe 1.2.4 反序列化过程命令执行漏洞【原理扫描】

文章目录一、分析定位1. 漏洞描述2. 项目引发漏洞简述二、 若依系统2.1. 版本升级2.2. 配置文件2.3. 推荐做法2.4. 栗子2.5. 项目场景三、Gus系统3.1. shiro版本升级3.2. 调用重新生成3.3. 生成工具类shiro漏洞补充:一、分析定位 1. 漏洞描述 目前厂商已经发布了新…

Linux系统json文件打中文,如何在 Linux 终端上漂亮地打印 JSON 文件

JSON 文件非常棒,因为它们以人类可读的格式存储数据集合。然而,如果 JSON 文件被最小化过,那么阅读 JSON 文件可能会很痛苦。• 来源:linux.cn • 作者:Abhishek Prakash • 译者:geekpi •(本文字数&#…

超级干货!31 条2020 年最新版 ZooKeeper面试题,先收藏再看!| 博文精选

作者| ThinkWon责编 | Carol出品 | CSDN云计算(ID:CSDNcloud)金三银四,虽然受疫情影响,大多数企业还未正式复工,但没有条件,创造条件也要上,许多企业已经开始物色合适的人才了&#…

Node.js 应用故障排查手册 —— 雪崩型内存泄漏问题

楔子 实践篇一中我们也看到了一个比较典型的由于开发者不当使用第三方库,而且在配置信息中携带了三方库本身使用不到的信息,导致了内存泄漏的案例,实际上类似这种相对缓慢的 Node.js 应用内存泄漏问题我们总是可以在合适的机会抓取堆快照进行…

检测到远端X服务正在运行中

文章目录一、 漏洞详情二、 解决方案2.1. 方案1(推荐使用)2.2. 方案2一、 漏洞详情 二、 解决方案 2.1. 方案1(推荐使用) 既然漏洞是6000端口导致的,首先要分析linux6000端口是谁在用呢、又和什么程序有关?如果没有用直接关掉6000端口即可,…

Kubernetes从懵圈到熟练:读懂这一篇,集群节点不下线

排查完全陌生的问题,完全不熟悉的系统组件,是售后工程师的一大工作乐趣,当然也是挑战。今天借这篇文章,跟大家分析一例这样的问题。排查过程中,需要理解一些自己完全陌生的组件,比如systemd和dbus。但是排查…

面试还搞不懂Redis,快看看这40道面试题!| 博文精选

作者| 程序员追风责编 | Carol出品 | CSDN云计算(ID:CSDNcloud)近年来,微服务变得越来越热门,越来越多的应用部署在分布式环境中。常用的分布式实现方式之一就有 Redis。对于想要年后换东家的程序员来说,如…