Linux内核 hlist_head/hlist_node结构解析
内核中的定义:
struct hlist_head {
struct hlist_node *first;
};
struct hlist_node {
struct hlist_node *next, **pprev;
};
这个数据结构与一般的hash-list数据结构定义有以下的区别:
1) 首先,hash的头节点仅存放一个指针,也就是first指针,指向的是list的头结点,没有tail指针也就是指向list尾节点的指针,这样的考虑是为了节省空间——尤其在hash bucket很大的情况下可以节省一半的指针空间.
2) list的节点有两个指针,但是需要注意的是pprev是指针的指针,它指向的是前一个节点的next指针;其中首元素的pprev指向链表头的fist字段,末元素的next为NULL. (见下图).

现在疑问来了:为什么pprev不是prev也就是一个指针,用于简单的指向list的前一个指针呢?这样即使对于first而言,它可以将prev指针指向list的尾结点.
主要是基于以下几个考虑:
1) hash-list中的list一般元素不多(如果太多了一般是设计出现了问题),即使遍历也不需要太大的代价,同时需要得到尾结点的需求也不多.
2) 如果对于一般节点而言,prev指向的是前一个指针,而对于first也就是hash的第一个元素而言prev指向的是list的尾结点,那么在删除一个 元素的时候还需要判断该节点是不是first节点进行处理.而在hlist提供的删除节点的API中,并没有带上hlist_head这个参数,因此做这 个判断存在难度.
3) 以上两点说明了为什么不使用prev,现在来说明为什么需要的是pprev,也就是一个指向指针的指针来保存前一个节点的next指针--因为这样做即使 在删除的节点是first节点时也可以通过*pprev = next;直接修改指针的指向.来看删除一个节点和修改list头结点的两个API:
static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
{
struct hlist_node *first = h->first;
n->next = first;
if (first)
first->pprev = &n->next;
h->first = n;
n->pprev = &h->first; //此时n是hash的first指针,因此它的pprev指向的是hash的first指针的地址
} static inline void __hlist_del(struct hlist_node *n)
{
struct hlist_node *next = n->next;
struct hlist_node **pprev = n->pprev;
*pprev = next; // pprev指向的是前一个节点的next指针,而当该节点是first节点时指向自己,因此两种情况下不论该节点是一般的节点还是头结点都可以通过这个操作删除掉所需删除的节点
if (next)
next->pprev = pprev;
}
Linux内核 hlist_head/hlist_node结构解析的更多相关文章
- 【驱动】网卡驱动·linux内核网络分层结构
Preface Linux内核对网络驱动程序使用统一的接口,并且对于网络设备采用面向对象的思想设计. Linux内核采用分层结构处理网络数据包.分层结构与网络协议的结构匹配,既能简化数据包处理流程 ...
- [转]linux内核网络分层结构
Preface Linux内核对网络驱动程序使用统一的接口,并且对于网络设备采用面向对象的思想设计. Linux内核采用分层结构处理网络数据包.分层结构与网络协议的结构匹配,既能简化数据包处理流程 ...
- Linux 网络设备驱动开发(一) —— linux内核网络分层结构
Preface Linux内核对网络驱动程序使用统一的接口,并且对于网络设备采用面向对象的思想设计. Linux内核采用分层结构处理网络数据包.分层结构与网络协议的结构匹配,既能简化数据包处理流程,又 ...
- 基于tiny4412的Linux内核移植 --- aliases节点解析
作者信息 作者: 彭东林 邮箱:pengdonglin137@163.com QQ:405728433 平台简介 开发板:tiny4412ADK + S700 + 4GB Flash 要移植的内核版本 ...
- Linux内核学习笔记2——Linux内核源码结构
一 内核组成部分 内核是一个操作系统的核心,主要由五个部分组成:进程调度,内存管理,虚拟文件系统,网络结构,进程间通信. 1.进程调度(SCHED) 控制进程对CPU的访问.当需要选择下一个进程运行时 ...
- linux内核源码结构
一.概述 Linux内核庞大,但是这些文件的结构还是有章可循的,分别位于不同的目录下,各个目录功能相对独立. 二.源码结构表 目录名 描述 arch 体系结构相关的代码,对于每个架构的CPU,arch ...
- linux内核之链表操作解析
本文只是对linux内核中的链表进行分析.内核版本是linux-2.6.32.63.文件在:linux内核/linux-2.6.32.63/include/linux/list.h.本文对list.h ...
- 基于tiny4412的Linux内核移植 --- aliases节点解析【转】
转自:https://www.cnblogs.com/pengdonglin137/p/5252348.html 阅读目录(Content) 作者信息 平台简介 正文 回到顶部(go to top) ...
- Linux内核源代码的结构(转)
源代码所有在目录:/usr/src/linux (大部分linux发行版本中) init 内核初始化代码 kernel 内核核心部分:进程.定时.程序执行.信号.模块... mm 内存处理 a ...
随机推荐
- 快速构建Windows 8风格应用14-ShareContract概述及原理
原文:快速构建Windows 8风格应用14-ShareContract概述及原理 本篇博文主要介绍Share Contract概述.Share Contract实现原理.实现Share Contra ...
- 【Android开发日记】第一个任务Android Service!Service靴+重力感应器+弹出窗口+保持执行
前言: 近期在写一个小程序,需求是手机摇一摇就弹窗出来.第一次使用了Service,学习了两天,实现了Service弹窗,开机启动,Service启动和销毁,Service保持一直执行. 满足了自己的 ...
- Android基础笔记(十)- 帧动画、补间动画具体解释、对话框
帧动画 补间动画Tween Animation 对话框以及面试中的注意点 帧动画 帧动画非常easy,我们首先看一下Google官方解释This is a traditional animation ...
- [置顶] Android开发之Thread类分析
在我们Linux系统中创建线程函数为:pthread_create(),在Android中我们为线程封装了一个类Thread,实际调用的还是pthread_create() 当我们想创建线程的时候,只 ...
- Oracle表介绍--簇表
簇和簇表 簇其实就是一组表,是一组共享相同数据块的多个表组成. 将经常一起使用的表组合在一起成簇可以提高处理效率. 在一个簇中的表就叫做簇表.建立顺序是:簇→簇表→数据→簇索引 ...
- mvc4中jquery-ui日期控件datepicker的应用
mvc4中jquery-ui日期控件datepicker的应用 本文适合mvc中日期选择需要的同学: 假设读者已经具备了mvc4和javascript中的相关知识 一. 开始项目之前把项目中目录:/C ...
- Product Trader(操盘手)
Product Trader(操盘手) 索引 意图 结构 参与者 适用性 效果 相关模式 实现 实现方式(一):Product Trader 的示例实现. 意图 使客户程序可以通过命名抽象超类和给定规 ...
- ASP.NET SignalR 2.0入门指南
ASP.NET SignalR 2.0入门指南 介绍SignalR ASP.NET SignalR 是一个为 ASP.NET 开发人员的库,简化了将实时 web 功能添加到应用程序的过程.实时Web功 ...
- Jenkins Slave 设置
Jenkins Slave node环境变量设置有很多trap,在最近的工作当中,我把slave部署在red hat linux 上,进行c++项目的编译部署和发布,但是在执行工程的时候,总会报出某些 ...
- Effective C++(19) 设计class犹如设计type
问题聚焦: 这一节不涉及代码,但是我们需要明确的一点是,思想比代码要重要得多. 设计优秀的classes是一项艰巨的工作,就像设计好的types一样. 我们应该带着和“语言设计 ...