深入理解Linux内核中的链表

      最近,开始研读一下Linux的内核代码,刚一开始,就有令人惊叹的发现,不得不感叹内核代码设计得之美!单是最常用的链表也设计得不得不令人佩服!
1.1.链表list_head
    include/linux/list.h
    很经典,链表在内核中很常用,例如管理进程,进程的各个状态队列都是使用这个双向链表实现的。内核中的链表定义成和数据无关的形式,而不是通常我们使用的链表格式,例如
typedef struct _list{
    Elemtype elem;
    struct _list *next;
}list;
内核中的链表定义为
struct list_head{
    struct list_head *next, *prev;
};
可见,这个链表节点中不包含任何数据,只有两个指针。当需要使用链表来组织数据结构时,这个结构中就包含一个list_head成员,例如
struct _list_struct{
    Elemtype elem;
    struct list_head list;
    ...
};
显而易见,链表实现成和数据分离的好处是,不用为每种数据都定义链表操作,可以使用统一的链表操作即可。但是问题是:只知道数据成员list的地址,怎样去访问自身以及其他成员呢?
#define list_entry(ptr,type,member)    /
    container_of(ptr,type,member)
而container_of(ptr,type,member)宏定义在include/list/kernel.h中
#define container_of(ptr,type,member)    ({
    const typeof( ((type *)0)->member) *__ptr=ptr;
    (type *)( (char *)__ptr - offsetof(type,member));})
    上面的宏有几点需要解释:
1)typeof(type) 宏
    typeof(type) 宏返回变量type的类型,例如:int a; typeof(a) b;等价于int b;
2)offsetof(type,member)宏
    它定义在include/linx/stddef.h中,如下:
#define offsetof(TYPE, MEMBER)  ((size_t) &((TYPE *)0)->MEMBER)
这个宏返回member在type类型中的偏移量,type是一个结构,例如:
typeof(list_head,next);返回0,也就是返回相对于结构起始地址的偏移量。
3)为什么要使用typeof(((type *)0)->member)来定义指针 __ptr,而不是这样:
const typeof(member) *__ptr=ptr;?
    其实,这个很简单,因为member是结构的成员,只能通过结构来访问!
4)访问数据
    在文件include/linux/list.h中,有访问链表数据的代码
#define list_for_each_entry(pos, head, member)
    for(pos=list_entry((head)->next,typeof(*pos),member);...)
从上面的使用来看,替换list_entry宏以及container_of宏后,变成如下:
    pos=({const typeof(((typeof(*pos) *)0)->member) *__ptr=(head)->next;
            (typeof(*pos) *)((char *)__ptr - offsetof(typeof(typeof(*pos)),member));});
1)这里的语法很奇怪,小括号()中包含了一个代码段{},这是平常都见不到的。

1.2.链表hlist_head
    hlist_head链表也是一个双向链表,它的定义如下
struct hlist_head{
    struct hlist_node *first;
};
struct hlist_node{
    struct hlist_node *next, **pprev;
};
    显然,这个双向链表不是真正的双向链表,因为表头只有一个first域,为什么这样设计?代码中的注释解释:为了节约内存,特别适合作为Hash表的冲突链,但Hash表很大时,那么表头节约下来的内存就相当客观了,虽然每个表头只节约一个指针。
    同时,表头的不一致性也会带来链表操作上的困难,显然就是在表头和首数据节点之间插入节点时需要特别处理,这也就是为什么会设计二级指针pprev的原因。看看代码
static inline void hlist_add_before(struct hlist_node *n,struct hlist_node *next)
{
    n->pprev=next->pprev;
    n->next=next;
    next->pprev=&n->next;
    *(n->pprev)=n;
}
    解释:指针n指向新节点,指针next指向将要在它之前插入新节点的那个节点。
看上面的代码,就可以看到二级指针pprev的威力了!有没有看到,当next就是第一个数据节点时,这里的插入也就是在表头和首数据节点之间插入一个节点,但是并不需要特别处理!而是统一使用*(n->pprev)来访问前驱的指针域(在普通节点中是next,而在表头中是first)。这太经典了!

  • 0
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 29
    评论
### 回答1: 《深入理解Linux内核》是一本经典的计算机科学书籍,它是由Daniel P. Bovet和Marco Cesati共同撰写的。该书深入介绍了Linux内核的各个方面,包括进程管理、内存管理、文件系统、设备驱动程序等等。 在《深入理解Linux内核,作者系统地介绍了Linux内核的设计和实现原理。他们从整体架构开始,逐步深入讲解各个子系统的功能和实现细节,全面展示了Linux内核的工作原理。通过学习这本书,读者可以学习到Linux内核的基本概念、关键数据结构和算法,以及与其他操作系统的对比。 这本书针对的读者主要是计算机专业的学生和从业人员。它不仅能帮助读者更深入地理解Linux操作系统,还能培养读者分析和解决操作系统相关问题的能力。同时,书丰富的实例和代码也对学习者进行了良好的指导,帮助他们更好地理解和掌握内核编程技巧。 总而言之,《深入理解Linux内核》是一本值得深入研读的经典教材。它不仅详细介绍了Linux内核的各个方面,还为读者提供了丰富的实例和代码,帮助他们更好地理解和掌握内核编程技巧。读完这本书,读者可以更深入地理解Linux内核的工作原理,为深入研究和开发操作系统打好坚实的基础。 ### 回答2: 《深入理解 Linux 内核》是一本介绍 Linux 操作系统内核设计和实现原理的经典著作。这本书的目的是帮助读者深入了解 Linux 内核的核心概念、运行机制和关键模块,从而更好地理解 Linux 操作系统的工作原理。 首先,这本书涵盖了 Linux 内核的各个方面,包括进程管理、内存管理、进程间通信、文件系统、设备驱动程序等。通过深入了解这些模块的设计和实现原理,读者可以全面掌握 Linux 内核的工作方式,并能够更好地进行系统调优和应用开发。 此外,本书还介绍了 Linux 内核的主要数据结构和算法,包括链表、红黑树、哈希表等。对这些数据结构深入理解,对于理解 Linux 内核代码和实现原理非常重要。通过详细讲解这些数据结构的设计和实现,读者可以更好地理解它们在 Linux 内核的使用场景和性能特性。 另外,本书还详细介绍了 Linux 内核的调试和性能优化技术。作者详细介绍了使用 GNU 调试器来调试内核代码、使用运行时检测工具来检测内核错误、使用静态分析工具来分析内核代码等技术。这些技术对于诊断和解决内核问题非常有帮助,并能够提高系统性能。 总的来说,深入理解 Linux 内核这本书是一本系统而深入的介绍 Linux 内核设计和实现原理的优秀著作。通过学习这本书,读者可以全面掌握 Linux 内核的运行机制和关键模块,提高对 Linux 操作系统的理解和应用开发的能力。 ### 回答3: 《深入理解Linux内核》 PDF是一本经典的Linux内核学习资料,它以深入和全面的方式探索了Linux内核的工作原理和设计思想。 首先,这本书介绍了Linux内核的基本概念和组成结构。它从进程管理、内存管理、文件系统等方面详细解析了内核的各个功能模块,让读者了解内核的整体架构和运行机制。 其次,这本书深入剖析了Linux内核的调度器和进程管理。它详细介绍了调度器的工作原理,包括进程调度策略、调度队列的管理等内容。此外,它还讨论了进程的创建、销毁以及进程状态转换等方面,帮助读者理解进程管理的核心概念和实现原理。 此外,这本书还介绍了Linux内核的内存管理机制。它涵盖了虚拟内存、分页机制、内存分配和回收等关键话题。通过解析内存管理的细节,读者可以更好地理解Linux内核如何管理系统资源,并优化内存使用效率。 此外,《深入理解Linux内核》 PDF还深入讲解了Linux的文件系统。它涵盖了文件系统的组织结构、文件系统缓存、文件的读写操作等关键知识点。通过学习文件系统的实现原理,读者可以了解文件系统如何存储和管理文件数据,并对文件I/O操作有更深入的理解。 最后,这本书还涵盖了设备驱动程序和网络协议栈等内容。它讲解了设备驱动程序的框架和实现原理,以及Linux内核对网络通信的支持。通过学习这些内容,读者可以了解Linux内核如何与外设和网络进行交互。 总之,这本书通过详细而全面的介绍,帮助读者深入理解Linux内核的工作原理和设计思想。它不仅适合想要深入研究Linux内核的专业人士,也适合对Linux系统有兴趣的读者参考学习。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 29
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值