list_entry定义

/**
* list_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*/
#define list_entry(ptr, type, member) /
((type *)((char *)(ptr)-(unsigned long)(&((type *))->member)))

  在Linux内核中,函数list_entry()用来获取节点地址.

  其不难理解为:从一个结构的成员指针找到其容器的指针。

  1. ptr是找容器的那个变量的指针,把它减去自己在容器中的偏移量的值就应该 得到容器的指针。(容器就是包含自己的那个结构)。
  2. 指针的加减要注意类型,用(char*)ptr是为了计算字节偏移。
  3. ((type *)0)->member是一个小技巧。
  4. 前面的(type *)再转回容器的类型。
#define list_entry(ptr, type, member) /
((type *)((char *)(ptr)-(unsigned long)(&((type *))->member))
  • ptr是指向list_head类型链表的指针
  • type为一个结构
  • 而member为结构type中的一个域,类型为list_head
  • 这个宏返回指向type结构的指针

  在内核代码中大量引用了这个宏,因此,搞清楚这个宏的含义和用法非常重要。

设有如下结构体定义:

typedef struct xxx
{
……(结构体中其他域,令其总大小为size1)
type1 member;
……(结构体中其他域)
}type;

定义变量:

type a;
type * b;
type1 * ptr;

执行:

ptr=&(a.member);
b=list_entry(ptr,type,member);

  这样就使b指向a,得到了a的地址。

如何做到的呢?

&((type *))->member

  把“0”强制转化为指针类型,则该指针一定指向“0”(数据段基址)。

  因为指针是“type *”型的,所以可取到以“0”为基地址的一个type型变量member域的地址。

  那么这个地址也就等于member域到结构体基地址的偏移字节数。

 ((type *)((char *)(ptr)-(unsigned long)(&((type *))->member)))

  (char *)(ptr)使得指针的加减操作步长为一字节,(unsigned long)(&((type *)0)->member)等于ptr指向的member到该member所在结构体基地址的偏移字节数。二者一减便得出该结构体的地址。转换为 (type *)型的指针,便大功告成。


list.h注释

  每一个熟悉内核的程序员,写出来的程序会更加优美和高效,因为内核代码本身就是优美和高效的,我们可以加以借荐;

  但是内核的庞大程度与复杂的各种结构使很多人望而生畏,因此我把经常使用的内核链表核心文件给加了注释,以方便使用。

 //################  注释:By 成鹏致远     ################//
//################ net :infodown.tap.cn ################//
//################ time:2013-7-30   ################// #ifndef __DLIST_H
#define __DLIST_H /* This file is from Linux Kernel (include/linux/list.h) //————————>位置
* and modified by simply removing hardware prefetching of list items. //————————>在预处理阶段对链表项进行替换
* Here by copyright, credits attributed to wherever they belong.
* Kulesh Shanmugasundaram (kulesh [squiggly] isis.poly.edu)
*/ /*
* Simple doubly linked list implementation. //————————>简单的双向链表实现
*
* Some of the internal functions (“__xxx”) are useful when
* manipulating whole lists rather than single entries, as //————————>最好对整个链表进行操作
* sometimes we already know the next/prev entries and we can
* generate better code by using them directly rather than
* using the generic single-entry routines.
*/ //################ 通过内部结构指针返回外部容器指针 ################//
/**
* container_of - cast a member of a structure out to the containing structure //————————>container_of:从一个结构的成员指针找到其容器的指针
*
* @ptr: the pointer to the member. //————————>ptr:指向menber的指针,即找容器的那个变量的指针
* @type: the type of the container struct this is embedded in. //————————>type:容器的类型
* @member: the name of the member within the struct. //————————>member:容器中struct类型成员
*
*/
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) //————————>offsetof:TYPE结构类型中MEMBER结构指针与TYPE结构指针的偏移量 #define container_of(ptr, type, member) ({ \ //————————>container_of:从一个结构的成员指针找到其容器的指针
const typeof( ((type *))->member ) *__mptr = (ptr); \ //————————>ptr:指向menber的指针,即找容器的那个变量的指针
(type *)( (char *)__mptr - offsetof(type,member) );}) //————————>type:容器的类型
//————————>member:容器中struct类型成员 //################ 链表初始化 ################//
/*
* These are non-NULL pointers that will result in page faults //————————>野指针会导致页面出错
* under normal circumstances, used to verify that nobody uses //————————>以下初始化方法保证了不会出现野指针(确认没有空指针传入)
* non-initialized list entries.
*/
#define LIST_POISON1 ((void *) 0x00100100)
#define LIST_POISON2 ((void *) 0x00200 struct list_head { //————————>内核链表结构
struct list_head *next, *prev;
}; #define LIST_HEAD_INIT(name) { &(name), &(name) } //————————>LIST_HEAD_INIT(name):用name来初始化链表 #define LIST_HEAD(name) \ //————————>LIST_HEAD(name):间接用LIST_HEAD_INIT(name)来初始化链表,本质:LIST_HEAD(name)用来定义+初始化
struct list_head name = LIST_HEAD_INIT(name) #define INIT_LIST_HEAD(ptr) do { \ //————————>运行时初始化,功能相同:初始化
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while () //################ 链表插入算法 ################//
/*
* Insert a new entry between two known consecutive entries. //————————>在两个连续的结点间插入新的结点
*
* This is only for internal list manipulation where we know //————————>只能用于操作已知prev和next指针的内部链表
* the prev/next entries already!
*/
static inline void __list_add(struct list_head *new, //————————>__list_add:内联静态函数
struct list_head *prev, //————————>参数:三个指向list_head的结构体指针(新结点,前向结点,后向结点)
struct list_head *next)
{
next->prev = new; //————————>双向链表中插入new结点
new->next = next;
new->prev = prev;
prev->next = new;
} /**
* list_add – add a new entry //————————>list_add:头插法增加新节点
* @new: new entry to be added //————————>new:新节点指针
* @head: list head to add it after //————————>head:链表头结点指针,在之后插入
*
* Insert a new entry after the specified head. //————————>头插法
* This is good for implementing stacks. //————————>符合栈操作
*/
static inline void list_add(struct list_head *new, struct list_head *head) //————————>list_add:在head后面插入new
{ //————————>new:新节点指针
__list_add(new, head, head->next); //————————>head:链表头结点指针
} /**
* list_add_tail – add a new entry //————————>list_add_tail :尾插法增加新节点
* @new: new entry to be added //————————>new:新节点指针
* @head: list head to add it beforer //————————>head:链表头结点指针,在之前插入
*
* Insert a new entry before the specified head.
* This is useful for implementing queues. //————————>符合队列操作
*/
static inline void list_add_tail(struct list_head *new, struct list_head *head) //————————>list_add_tail :在head前面插入new
{
__list_add(new, head->prev, head);
} //################ 链表删除算法 ################//
/*
* Delete a list entry by making the prev/next entries //————————>通过改变prev和next的指向来删除节点
* point to each other.
*
* This is only for internal list manipulation where we know //————————>同样只能用于操作已知prev和next指针的内部链表
* the prev/next entries already!
*/
static inline void __list_del(struct list_head *prev, struct list_head *next) //————————>__list_del:删除结点
{ //————————>prev:待删除结点的前向指针
next->prev = prev; //————————>next:待删除结点的后向指针
prev->next = next;
} /**
* list_del – deletes entry from list. //————————>list_del:删除节点
* @entry: the element to delete from the list. //————————>entry:要删除的结点
* Note: list_empty on entry does not return true after this, the entry is in an undefined state. //————————>操作后调用list_empty则返回随机值
*/
static inline void list_del(struct list_head *entry) //————————>删除entry结点
{
__list_del(entry->prev, entry->next);
entry->next = (void *) ; //————————>置空
entry->prev = (void *) ;
} /**
* list_del_init – deletes entry from list and reinitialize it. //————————>list_del_init:删除并初始化节点
* @entry: the element to delete from the list.
*/
static inline void list_del_init(struct list_head *entry) //————————>删除并初始化entry指向的结点
{
__list_del(entry->prev, entry->next); //————————>删除
INIT_LIST_HEAD(entry); //————————>然后初始化
} //################ 链表移动算法 ################//
/**
* list_move – delete from one list and add as another’s head //————————>list_move:从链表中删除一个节点并添加到另一个链表头部
* @list: the entry to move //————————>list:要移动的节点
* @head: the head that will precede our entry //————————>head:目标链表的头结点
*/
static inline void list_move(struct list_head *list, //————————>list_move:从链表中删除list并添加到head后面
struct list_head *head)
{
__list_del(list->prev, list->next); //————————>先删除
list_add(list, head); //————————>然后在head后面添加list
} /**
* list_move_tail – delete from one list and add as another’s tail //————————>list_move_tail:从链表中删除一个节点并添加到另一个链表尾部
* @list: the entry to move
* @head: the head that will follow our entry
*/
static inline void list_move_tail(struct list_head *list, //————————>list_move_tail:从链表中删除list并添加到head前部
struct list_head *head)
{
__list_del(list->prev, list->next); //————————>先删除
list_add_tail(list, head); //————————>然后在head前面添加list
} //################ 判断链表空状态 ################//
/**
* list_empty – tests whether a list is empty
* @head: the list to test.
*/
static inline int list_empty(struct list_head *head) //————————>list_empty:判断head指向的链表是否为空
{
return head->next == head; //————————>只有一个头结点
} //################ 链表合并算法 ################// static inline void __list_splice(struct list_head *list, //————————>__list_splice:将list链表合并到head链表上
struct list_head *head)
{
struct list_head *first = list->next; //————————>list的首结点
struct list_head *last = list->prev; //————————>list的尾结点
struct list_head *at = head->next; //————————>head的首结点
//————————>将list所以结点链接到head的后面
first->prev = head; //————————>list首结点向前指向head
head->next = first; //————————>head向后指向list的首结点 last->next = at; //————————>list的尾结点向后指向head的首结点
at->prev = last; //————————>head的首结点向前指向list的尾结点
} /**
* list_splice – join two lists //————————>list_splice:合并两个链表
* @list: the new list to add. //————————>list:要合并的链表
* @head: the place to add it in the first list. //————————>目标链表
*/
static inline void list_splice(struct list_head *list, struct list_head *head) //————————>list_splice:将list合并到head后面
{
if (!list_empty(list)) //————————>条件:list链表不为空
__list_splice(list, head);
} /**
* list_splice_init – join two lists and reinitialise the emptied list. //————————>list_splice_init:合并两个链表并重新初始化被链接的链表2013-7-30
* @list: the new list to add. //————————>list:要合并的链表
* @head: the place to add it in the first list. //————————>目标链表
*
* The list at @list is reinitialised //————————>list:被重新初始化
*/
static inline void list_splice_init(struct list_head *list, //————————>list_splice_init:将list合并到head,并重新初始化list
struct list_head *head)
{
if (!list_empty(list)) { //————————>条件:list链表不为空
__list_splice(list, head);
INIT_LIST_HEAD(list);
}
} //################ 通过内部结构指针返回外部容器指针 ################//
/**
* list_entry – get the struct for this entry //————————>list_entry:得到结点的外部结构地址
* @ptr: the &struct list_head pointer. //————————>ptr:指向struct list_head类型链表的指针
* @type: the type of the struct this is embedded in. //————————>type:包含结点的结构体类型
* @member: the name of the list_struct within the struct. //————————>member:type结构中的结点类型
*/
#define list_entry(ptr, type, member) \ //————————>list_entry:得到type结构的指针
((type *)((char *)(ptr)-(unsigned long)(&((type *))->member))) //————————>ptr:指向struct list_head类型链表的指针
//————————>type:包含结点的结构体类型
//————————>member:type结构中的结点类型 //################ 链表遍历算法 ################//
/**
* list_for_each - iterate over a list //————————>list_for_each:迭代一个链表
* @pos: the &struct list_head to use as a loop counter. //————————>pos:循环计数器,struct list_head类型
* @head: the head for your list. //————————>遍历链表头指针
*/
#define list_for_each(pos, head) \ //————————>list_for_each:利用for循环迭代head指向的链表
for (pos = (head)->next; pos != (head); \
pos = pos->next) //————————>通过next指针逐项后移 /**
* list_for_each_prev - iterate over a list backwards //————————>list_for_each_prev:反向迭代一个链表
* @pos: the &struct list_head to use as a loop counter. //————————>pos:循环计数器,struct list_head类型
* @head: the head for your list. //————————>遍历链表头指针
*/
#define list_for_each_prev(pos, head) \ //————————>list_for_each_prev:利用for循环反向迭代head指向的链表
for (pos = (head)->prev; pos != (head); \
pos = pos->prev) //————————>也是通过next指针逐项后移 /**
* list_for_each_safe - iterate over a list safe against removal of list entry //————————>list_for_each_safe:迭代一个链表
* @pos: the &struct list_head to use as a loop counter.
* @n: another &struct list_head to use as temporary storage //————————>多用一个临时辅助变量进行迭代
* @head: the head for your list.
*/
#define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next) /**
* list_for_each_entry - iterate over list of given type //————————>list_for_each_entry:遍历链表中的内核链表容器结构
* @pos: the type * to use as a loop counter. //————————>数据项结构指针类型,指向外部结构体
* @head: the head for your list. //————————>遍历链表头指针
* @member: the name of the list_struct within the struct. //————————>链表中结构成员的名字
*/
#define list_for_each_entry(pos, head, member) \ //————————>list_for_each_entry:遍历head指向的链表的容器结构(外部结构体)
for (pos = list_entry((head)->next, typeof(*pos), member); \
&pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member)) //————————>通过list_entry传入next来遍历外部结构 /**
* list_for_each_entry_safe – iterate over list of given type safe against removal of list entry //————————>llist_for_each_entry_safe:遍历链表中的内核链表容器结构
* @pos: the type * to use as a loop counter.
* @n: another type * to use as temporary storage //————————>多用一个临时辅助变量进行迭代
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry_safe(pos, n, head, member) \ //————————>list_for_each_entry_safe:遍历head指向的链表的容器结构(外部结构体)
for (pos = list_entry((head)->next, typeof(*pos), member), \
n = list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n), member)) #endif

【内核】内核链表使用说明,list.h注释的更多相关文章

  1. linux内核中链表代码分析---list.h头文件分析(一)【转】

    转自:http://blog.chinaunix.net/uid-30254565-id-5637596.html linux内核中链表代码分析---list.h头文件分析(一) 16年2月27日17 ...

  2. linux内核中链表代码分析---list.h头文件分析(二)【转】

    转自:http://blog.chinaunix.net/uid-30254565-id-5637598.html linux内核中链表代码分析---list.h头文件分析(二) 16年2月28日16 ...

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

    我们都知道Linux内核里的双向链表和学校里教给我们的那种数据结构还是些不一样.Linux采用了一种更通用的设计,将链表以及其相关操作函数从数据本身进行剥离,这样我们在使用链表的时候就不用自己去实现诸 ...

  4. linux 内核的链表操作(好文不得不转)

    以下全部来自于http://www.ibm.com/developerworks/cn/linux/kernel/l-chain/index.html 无任何个人意见. 本文详细分析了 2.6.x 内 ...

  5. Linux嵌入式 -- 内核 - 内核链表

    1. linux内核链表 链表数据结构的定义: struct list_head  {  struct list_head *next, *prev;  };  list_head结构包含两个指向li ...

  6. 鸿蒙内核源码分析(源码注释篇) | 鸿蒙必定成功,也必然成功 | 百篇博客分析OpenHarmony源码 | v13.02

    百篇博客系列篇.本篇为: v13.xx 鸿蒙内核源码分析(源码注释篇) | 鸿蒙必定成功,也必然成功 | 51.c.h .o 几点说明 kernel_liteos_a_note | 中文注解鸿蒙内核 ...

  7. Linux内核单链表

    主要说明Linux内核中单链表操作的关键思想,需要注意的地方 1. 假设 为了说明关键思想,对数据结构进行了精简 2. 数据结构定义 struct ListNode { int val; ListNo ...

  8. 24小时学通Linux内核--内核探索工具类

    寒假闲下来了,可以尽情的做自己喜欢的事情,专心待在实验室里燥起来了,因为大二的时候接触过Linux,只是关于内核方面确实是不好懂,所以十天的时间里还是希望能够补充一下Linux内核相关知识,接下来继续 ...

  9. Linux内核-内核线程

    线程分类:内核线程.用户线程(指不需要内核支持而完全建立在用户空间的线程库,这种线程效率高,由于Linux内核没有轻量级进程(线程)的概念,因此不能独立的对用户线程进行调度,而是由一个线程运行库来组织 ...

随机推荐

  1. Map的深浅拷贝的探究

    1. 复制map示例 首先看一个例子,当我使用不同方法将一个源map拷贝到另一个map后,改变源map,复制后的map理应不受影响 import java.math.BigDecimal; impor ...

  2. Linux-静态库生成

    Linux上的静态库,其实是目标文件的归档文件.在Linux上创建静态库的步骤如下: 写源文件,通过 gcc -c xxx.c 生成目标文件. 用 ar 归档目标文件,生成静态库. 配合静态库,写一个 ...

  3. Spring 3.0 AOP 之 AOP 术语 (一)

    关于AOP.之前我已写过一个系列的随笔: <自己实现简单的AOP>,它的关注点在于实现.实现语言是C#,实现方式为 自定义实现 RealProxy 抽象类.重写Invoke方法,以便进行方 ...

  4. 【svn】解析subversion的使用

    目录结构: contents structure [-] 安装客户端 安装服务端 创建仓库 启动仓库 创建客户端与仓库取得联系 使用svn服务 SVN密码管理 SVN的仓库布局和常规命令 分支.合并和 ...

  5. 自定义 iPhone 铃声

    1.iPhone 铃声格式 iPhone 的来电铃声时长限制为 40 秒,短信铃声时长限制为 25 秒,且 iOS5 及以上的系统才支持 m4r 格式的短信铃声. 2.自定义 iPhone 铃声 1) ...

  6. 《JAVA与模式》之建造者模式

    1.概念 将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示. [构建与表示分离,同构建不同表示] 与抽象工厂的区别:在建造者模式里,有个指导者,由指导者来管理建造者,用户是与指导者 ...

  7. 一步一步掌握java的线程机制(二)----Thread的生命周期

    之前讲到Thread的创建,那是Thread生命周期的第一步,其后就是通过start()方法来启动Thread,它会执行一些内部的管理工作然后调用Thread的run()方法,此时该Thread就是a ...

  8. Oracle 12C -- temporal validity

    temporal validity需要在创建表的时候使用一个vaild-time维度(包含时间起始和结束) 创建有valid-time维度的表 (1)显式指定两个date-time列 SQL> ...

  9. 恢复Ext3下被删除的文件

    下面是这个教程将教你如何在Ext3的文件系统中恢复被rm掉的文件. 假设我们有一个文件名叫 ‘test.txt’  $ls -il test.txt 15 -rw-rw-r– 2 root root ...

  10. mysql 8.0 java连接报错:Unknown system variable 'query_cache_size'

    java连接mysql 8.0.11报错 java.sql.SQLException: Unknown system variable 'query_cache_size' at com.mysql. ...