内核中的定义:

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结构解析的更多相关文章

  1. 【驱动】网卡驱动·linux内核网络分层结构

    Preface   Linux内核对网络驱动程序使用统一的接口,并且对于网络设备采用面向对象的思想设计. Linux内核采用分层结构处理网络数据包.分层结构与网络协议的结构匹配,既能简化数据包处理流程 ...

  2. [转]linux内核网络分层结构

    Preface   Linux内核对网络驱动程序使用统一的接口,并且对于网络设备采用面向对象的思想设计. Linux内核采用分层结构处理网络数据包.分层结构与网络协议的结构匹配,既能简化数据包处理流程 ...

  3. Linux 网络设备驱动开发(一) —— linux内核网络分层结构

    Preface Linux内核对网络驱动程序使用统一的接口,并且对于网络设备采用面向对象的思想设计. Linux内核采用分层结构处理网络数据包.分层结构与网络协议的结构匹配,既能简化数据包处理流程,又 ...

  4. 基于tiny4412的Linux内核移植 --- aliases节点解析

    作者信息 作者: 彭东林 邮箱:pengdonglin137@163.com QQ:405728433 平台简介 开发板:tiny4412ADK + S700 + 4GB Flash 要移植的内核版本 ...

  5. Linux内核学习笔记2——Linux内核源码结构

    一 内核组成部分 内核是一个操作系统的核心,主要由五个部分组成:进程调度,内存管理,虚拟文件系统,网络结构,进程间通信. 1.进程调度(SCHED) 控制进程对CPU的访问.当需要选择下一个进程运行时 ...

  6. linux内核源码结构

    一.概述 Linux内核庞大,但是这些文件的结构还是有章可循的,分别位于不同的目录下,各个目录功能相对独立. 二.源码结构表 目录名 描述 arch 体系结构相关的代码,对于每个架构的CPU,arch ...

  7. linux内核之链表操作解析

    本文只是对linux内核中的链表进行分析.内核版本是linux-2.6.32.63.文件在:linux内核/linux-2.6.32.63/include/linux/list.h.本文对list.h ...

  8. 基于tiny4412的Linux内核移植 --- aliases节点解析【转】

    转自:https://www.cnblogs.com/pengdonglin137/p/5252348.html 阅读目录(Content) 作者信息 平台简介 正文 回到顶部(go to top) ...

  9. Linux内核源代码的结构(转)

    源代码所有在目录:/usr/src/linux (大部分linux发行版本中)  init 内核初始化代码  kernel 内核核心部分:进程.定时.程序执行.信号.模块...  mm 内存处理  a ...

随机推荐

  1. 实现一个简单的Unity3D三皮卡——3D Picking (1)

    3D Picking 其原理是从摄像机位置到空间发射的射线.基于光线碰到物体回暖. 这里我们使用了触摸屏拿起触摸,鼠标选择相同的原理,仅仅是可选API不同. 从unity3D官网Manual里找到下面 ...

  2. C#验证IP地址

    using System.Net; try { IPAddress a = IPAddress.Parse(输入的IP字符串); } catch (System.Exception ex) { Mes ...

  3. windows下 composer常见问题及处理

    错误一: Warning: This development build of composer is over 30 days old. It is recommend ed to update i ...

  4. jquery的使用 关于 option ,append,attr,val()等的使用

    //遍历option和添加.移除option function changeShipMethod(shipping){ var len = $("select[@name=ISHIPTYPE ...

  5. 前后端分离之Web前端架构设计

    架构设计:前后端分离之Web前端架构设计 在前面的文章里我谈到了前后端分离的一些看法,这个看法是从宏观的角度来思考的,没有具体的落地实现,今天我将延续上篇文章的主题,从纯前端的架构设计角度谈谈前后端分 ...

  6. wcf事务(随记)

    ----------------------------------------------------wcf事务:1.ACID:原子性.一致性.隔离性.持久性:2.事务:添加命名空间(using S ...

  7. gof设计模式回顾

    gof23根据讲师学习笔记回顾: 1.gof:Gang of Four;叫grasp更具有针对性,解决具体的问题; ---------------------总共分为三大类: ---------创建型 ...

  8. Redis简介与简单安装

    Redis简介与简单安装   一.NoSQL的风生水起 1.1 后Web2.0时代的发展要求 随着互联网Web2.0网站的兴起,传统的关系数据库在应付Web2.0网站,特别是超大规模和高并发的SNS类 ...

  9. 依赖注入和IOC

    http://www.bbsmvc.com/archiver/csharp/thread-831-1.html 本来想使用一下Ninject的,然后搜索了很久,都没找到比较详细的关于Ninject的使 ...

  10. Android:开发环境搭建、移植

    一:搭建Android安卓开发环境 准备文件 1.eclipse-SDK-4.2-win32.zip 2.JDK(Java Development Kit) 3.ADT,安卓开发的一个eclipse的 ...