简单理解linux内核的链表教程

在看linux内核源代码的时候,经常在一些结构里看见struct list_head结构。找了一下源代码,在list.h中,有对这个结构的定义,这个就是linux内核中的链表结构。

仔细看看这个结构,就可以发现它和以前在讲数据结构的时候的链表有很大的差别——没有数据。list_head结构中仅仅包含了两个自己结构的指针,用来组建双向循环链表。最大的疑问就是,这个链表结构如何保存数据呢?

在list.h中,定义了list_entry宏。这个宏就是用来提取包含链表项的结构的指针。从list_entry宏的定义可以看到,它仅仅调用了kernel.h中的container_of()宏。后者真正实现了通过链表结构来获取包含链表的结构的地址(指针)。

container_of(ptr, type, member)宏需要三个参数。ptr:指向链表的指针;type:包含链表项结构的类型;member:链表项在结构中的名称。

其中的实现有两句语句:

const typeof( ((type *)0)->member ) *__mptr = (ptr); //声明临时变量__mptr,储存链表的指针。这个变量的类型由gcc扩展函数typeof从结构的成员变量member中获取

//((type *)0)->member将地址0强制转换为结构的指针,并获取链表的对象

(type *)((char*) __mptr – offsetof(type, member)); //将上句获取到的地址减去链表项在结构中的偏移量,得到结构的真实地址,并将这个地址转换成所需类型结构的指针

//offsetof(type, member)函数定义在stddef.h中,它返回member在结构type中的偏移量,返回值为size_t

通过这宏,就返回了包含链表项的结构的指针,然后就可以通过这个指针来访问结构中的数据了。这样定义的链表,对于没有模板的c语言来说,可以有效的避免重复写很多包含不同数据类型的结构,不用在为每种不同的数据类型写一个链表节点项了。

时间: 2024-09-28 16:36:13

简单理解linux内核的链表教程的相关文章

Linux内核【链表】整理笔记(1)

转自:http://blog.chinaunix.net/uid-23069658-id-4576255.html 我们都知道Linux内核里的双向链表和学校里教给我们的那种数据结构还是些不一样.Linux采用了一种更通用的设计,将链表以及其相关操作函数从数据本身进行剥离,这样我们在使用链表的时候就不用自己去实现诸如节点的插入.删除.遍历等操作了.当然,Linux也是从2.1.x内核开始才对链表进行了这样的统一,和我们目前看到的样子几乎差不多: 点击(此处)折叠或打开 struct list_h

深入理解linux内核之(二)进程

                                      深入理解linux内核之(二)进程       程序是静态的,进程是正在执行的程序的一个实例,一个程序可以由多个进程组成.进程是资源分配的实体.在进程被创建出来之后,该子进程几乎和父进程一样.子进程复制了父进程的地址空间,从fork()之后的第一条指令开始执行,和父进程有同样的程序可执行代码(exec调用除外).尽管子进程和父进程具有同样的程序执行代码,但是子进程拥有自己的stack和heap,因此,子进程对数据的修改对

Linux内核中链表的实现与应用【转】

转自:http://blog.chinaunix.net/uid-27037833-id-3237153.html 链表(循环双向链表)是Linux内核中最简单.最常用的一种数据结构.                1.链表的定义             struct list_head {                 struct list_head *next, *prev;             }            这个不含数据域的链表,可以嵌入到任何数据结构中,例如可按如下方

Linux内核【链表】整理笔记(2) 【转】

转自:http://blog.chinaunix.net/uid-23069658-id-4725279.html 关于链表我们更多时候是对其进行遍历的需求,上一篇博文里我们主要认识了一下和链表操作比较常用的几个内核API接口,其入参全都是清一色的struct list_head{}类型.至于链表的遍历,内核也有一组基本的接口(其实都是宏定义的)供开发者调用.     首先是list_for_each(pos, head),参数pos是需要开发者在外部提供的一个临时struct list_hea

没有容量的容器——linux内核的链表(sina博客移入)

在看linux内核源代码的时候,经常在一些结构里看见struct list_head结构.找了一下源代码,在list.h中,有对这个结构的定义,这个就是linux内核中的链表结构. 仔细看看这个结构,就可以发现它和以前在讲数据结构的时候的链表有很大的差别--没有数据.list_head结构中仅仅包含了两个自己结构的指针,用来组建双向循环链表.最大的疑问就是,这个链表结构如何保存数据呢? 在list.h中,定义了list_entry宏.这个宏就是用来提取包含链表项的结构的指针.从list_entr

Debian或Ubuntu等linux发型版上安装完整Linux内核源码教程

我需要为我的Debian或Ubuntu下载并安装完整树结构的内核源码以供编译一个定制的内核.那么在Debian或Ubuntu上有什么可行的方法来下载完整的内核源码呢? 在给你的Linux安装完整内核源码之前,先问问自己是否真的需要这样做.如果你仅仅是尝试去编译一个内核模块或是为内核定制驱动,你并不需要完整的内核源码树.你只需要安装一些与内核对应的头文件,这样就足够了.     只有在你需要生成一个定制的内核,而且内核源码中的一些内核默认设置要被你调整了的情况下,你才需要完整的内核源码树. 这里将

Centos下如何编译Linux内核的教程

Linux内核编译是一件简单却费事的事.但是独立的编译linux内核会帮助你很好的理解Linux内核的工作机理. 首先编译linux内核我们需要在当前linux操作系统下安装gcc编译器,因为我是Centos distribution版本 yum install gcc 接下来安装依赖环境: yum install ncurses-devel 现在我们以linux-3.18.1内核为例进行编译,假设我当前系统的版本为2.6.32 那么我首先在Linux内核发布的官网上http:/kernel.o

经典]Linux内核中ioremap映射的透彻理解【转】

转自:http://blog.csdn.net/lanyang123456/article/details/7403514 几乎每一种外设都是通过读写设备上的寄存器来进行的,通常包括控制寄存器.状态寄存器和数据寄存器三大类,外设的寄存器通常被连续地编址.根据CPU体系结构的不同,CPU对IO端口的编址方式有两种: (1)I/O映射方式(I/O-mapped) 典型地,如X86处理器为外设专门实现了一个单独的地址空间,称为"I/O地址空间"或者"I/O端口空间",CP

Linux内核实践

内核版本:2.6.34 接上篇<添加网络协议>. 为了用户方便查看brcm设备的工作状态,使用proc文件系统是很好的方 式.一个网络协议模块可以注册到网络空间中register_pernet_subsys(),这个函数会为子空间分配一个id号,通过id可以在网 络空间中找到分配给该子空间的内存:init_net->gen->ptr[id - 1].而我们正是利用这块内存去存储proc中的相关信息 :struct brcm_net,它记录了brcm设备在proc文件系统中的位置.