Linux list_head

在linux kernel里面链表应用非常广泛。

我们在应用程序中,定义一个链表结构通常要包含数据域,如下:

typedef struct _listNode{

int data;

struct _listNode *prev, *next;

}ListNode;

但在内核代码中,定义的链表都没有数据域, 如下:

struct list_head {

  struct list_head *next, *prev;

};
如果需要定义双链表结构,则在数据结构中包含一个list_head的成员变量,

struct book{

int data;

struct list_head list;

}

假设我们有另外一个结构体person,里面也有一个链表,这个链表是book的双链表。(代表一个人有多本书)

struct person{

char *name;

int booknum;

struct list_head booklist;

}

我们在初始化时,创建book的结构,并且将book加入到person的book list中。

struct person *myperson;

book= kmalloc(sizeof(struct book), GFP_KERNEL);

list_add_tail(&book->list, &myperson->booklist);
person->booknum++

那么后续我们知道booklist结构的地址(address A),如何知道booklist中的book结构(address B)呢?

struct book mybook;

list_for_each_entry(mybook, &myperson->booklist, list) //遍历myperson->booklist,每个元素放在mybook.

#define list_for_each_entry(pos, head, member) \
  for (pos = list_first_entry(head, typeof(*pos), member); \
  &pos->member != (head); \
  pos = list_next_entry(pos, member))

#define list_first_entry(ptr, type, member) \
  list_entry((ptr)->next, type, member)

最终展开的myperson->booklist的第一个元素的book结构为list_entry((&myperson->booklist)->next, struct book, list)

可以看出通过list_entry来获取myperson->booklist中的book结构。

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

#define container_of(ptr, type, member) ({ \//ptr为(&myperson->booklist)的元素的地址(address A),type为实际的结构struct book,list是book中的list成员名字
  const typeof( ((type *)0)->member ) *__mptr = (ptr); \
  (type *)( (char *)__mptr - offsetof(type,member) );})

将list_entry展开

((struct book*)((char *)((&myperson->booklist)->next)-(size_t)(&((struct book *)0)->list)))

(unsigned long)(&((struct book *)0)->list))即list相对于book 首地址的偏移(上图的offset)。

1. ( (type*)0 ) 将零转型为type类型指针; 
2. ((tpye*)0)->member访问结构中的数据成员; 
3. &( ( (type*)0 )->member)取出数据成员的地址; 
4.(size_t)(&(((type*)0)->member))转换成size_t类型,即member相对type结构首地址的偏移。

myperson的booklist 的地址(address A) 减去 偏移(offset)即为book结构首地址(Address B)。

时间: 2024-11-03 03:29:08

Linux list_head的相关文章

内核双向链表

链表是一种重要的数据结构,应用的非常广泛.链表分为单向链表与双向链表,一般的实现就是在结构体中内嵌指向下一个元素的指针.例如: struct name { int num; ...; struct name *next; struct name *prev; } 但是linux内核中的实现确有点特殊他是通过独立定义一个链表结构,通过结构体中内嵌这个结构来完成的,这样就实现了链表的定义与结构体的分离.linux内核中广泛的应用了这种链表,可以这么说,如果没有linux list_head链表就不会

linux内核源码“双向链表list_head”

摘要:linux内核源码真是好东东,是众多高手思维的结晶,在linux 源代码中有个头文件为list.h .很多linux 下的源代码都会使用这个头文件,它里面定义了一个结构, 以及定义了和其相关的一组函数,这个结构是这样的: structlist_head{ structlist_head *next, *prev; }; 如果您之前学过双向链表,那么当你看到这个结构的时候,会觉得似曾相识.岂止似曾相识,如果你看过Fio的源码,你会觉得它用的如此广泛,下面我们通过一个实例演示如何使用 一.编写

linux内核源码“双向链表list_head”续

上篇博文<linux内核源码"双向链表list_head">中以一个实例介绍了list_head双向链表的用法,只有实例的代码,并没有list_head链表的代码,考虑到各位好学博友的强烈愿望,今天把list_head的代码即list.h头文件粘贴到此,供各位好学博友使用. 一.list.h头文件源码 [[email protected] cstudy]# cat list.h             #list.h头文件 #ifndef _LINUX_LIST_H #de

linux内核中的hlist_head、list_head、hlist_node结构体

在linux内核中经常会看到这几个结构体: struct list_head; struct hlist_head; struct hlist_node; 在linux内核源代码中对这三个结构体的定义如下: struct list_head { struct list_head *prev; struct list_head *next; } struct hlist_node { struct hlist_node **prev; struct hlist_node *next; } stru

Linux 内核list_head 学习

Linux 内核list_head 学习(一) http://www.cnblogs.com/zhuyp1015/archive/2012/06/02/2532240.html 在Linux内核中,提供了一个用来创建双向循环链表的结构 list_head.虽然linux内核是用C语言写的,但是list_head的引入,使得内核数据结构也可以拥有面向对象的特性,通过使用操作list_head 的通用接口很容易实现代码的重用,有点类似于C++的继承机制(希望有机会写篇文章研究一下C语言的面向对象机制

Linux内核中的list_head

一般我们想要实现一种数据结构的双链队列,一般都是这样操作: typedef struct Datastructure { struct Datastructure *next; struct Datastructure *prev; //...... }datastructure; 然而在Linux内核中,使用了大量不同的数据结构的双链队列. 因此,内核作者们把指针prev和next从具体的宿主中抽象出来成为了一种数据结构list_head. struct list_head { struct

Linux进程的睡眠和唤醒

1   Linux进程的睡眠和唤醒 在Linux中,仅等待CPU时间的进程称为就绪进程,它们被放置在一个运行队列中,一个就绪进程的状态标志位为TASK_RUNNING.一旦一个运行中的进程时间片用完, Linux内核的调度器会剥夺这个进程对CPU的控制权,并且从运行队列中选择一个合适的进程投入运行. 当然,一个进程也可以主动释放CPU的控制权.函数schedule()是一个调度函数,它可以被一个进程主动调用,从而调度其它进程占用CPU.一旦这个主动放弃CPU的进程被重新调度占用CPU,那么它将从

Linux内核数据结构——链表

目录 目录 简介 单向链表 双向链表 环形链表 Linux内核中的链表实现 offsetof container_of container_of 第一部分 container_of 第二部分 链表初始化 向链表中增加一个节点 删除节点 移动节点 判断链表是否为空 遍历链表 Demo测试 mlisth mlistc 执行结果 简介 最近在学习Android Binder驱动程序实现的时候,发现里面的数据结构用到了struct list_head.而我google发现struct list_head

linux内核探索之内存管理(二):linux系统中的内存组织--结点、内存域和页帧

本文主要参考<深入linux内核架构>(3.2节)及Linux3.18.3内核源码 概述:本文主要描述了内存管理相关的数据结构:结点pg_data_t.内存域struct zone以及页帧(物理页):struct page ,以及该结构相关的一些基本概念. 1. 概述 内存划分为接点,每个结点关联到系统中的一个处理器,在内核中表示为pg_data_t. 各个结点又划分为内存域,比如DMA内存域,高端内存域,普通内存域. 内核内存域的宏: enum zone_type { #ifdef CONF