【内核】内核链表使用说明,list.h注释
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()用来获取节点地址.
其不难理解为:从一个结构的成员指针找到其容器的指针。
- ptr是找容器的那个变量的指针,把它减去自己在容器中的偏移量的值就应该 得到容器的指针。(容器就是包含自己的那个结构)。
- 指针的加减要注意类型,用(char*)ptr是为了计算字节偏移。
- ((type *)0)->member是一个小技巧。
- 前面的(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注释的更多相关文章
- linux内核中链表代码分析---list.h头文件分析(一)【转】
转自:http://blog.chinaunix.net/uid-30254565-id-5637596.html linux内核中链表代码分析---list.h头文件分析(一) 16年2月27日17 ...
- linux内核中链表代码分析---list.h头文件分析(二)【转】
转自:http://blog.chinaunix.net/uid-30254565-id-5637598.html linux内核中链表代码分析---list.h头文件分析(二) 16年2月28日16 ...
- Linux内核【链表】整理笔记(1)
我们都知道Linux内核里的双向链表和学校里教给我们的那种数据结构还是些不一样.Linux采用了一种更通用的设计,将链表以及其相关操作函数从数据本身进行剥离,这样我们在使用链表的时候就不用自己去实现诸 ...
- linux 内核的链表操作(好文不得不转)
以下全部来自于http://www.ibm.com/developerworks/cn/linux/kernel/l-chain/index.html 无任何个人意见. 本文详细分析了 2.6.x 内 ...
- Linux嵌入式 -- 内核 - 内核链表
1. linux内核链表 链表数据结构的定义: struct list_head { struct list_head *next, *prev; }; list_head结构包含两个指向li ...
- 鸿蒙内核源码分析(源码注释篇) | 鸿蒙必定成功,也必然成功 | 百篇博客分析OpenHarmony源码 | v13.02
百篇博客系列篇.本篇为: v13.xx 鸿蒙内核源码分析(源码注释篇) | 鸿蒙必定成功,也必然成功 | 51.c.h .o 几点说明 kernel_liteos_a_note | 中文注解鸿蒙内核 ...
- Linux内核单链表
主要说明Linux内核中单链表操作的关键思想,需要注意的地方 1. 假设 为了说明关键思想,对数据结构进行了精简 2. 数据结构定义 struct ListNode { int val; ListNo ...
- 24小时学通Linux内核--内核探索工具类
寒假闲下来了,可以尽情的做自己喜欢的事情,专心待在实验室里燥起来了,因为大二的时候接触过Linux,只是关于内核方面确实是不好懂,所以十天的时间里还是希望能够补充一下Linux内核相关知识,接下来继续 ...
- Linux内核-内核线程
线程分类:内核线程.用户线程(指不需要内核支持而完全建立在用户空间的线程库,这种线程效率高,由于Linux内核没有轻量级进程(线程)的概念,因此不能独立的对用户线程进行调度,而是由一个线程运行库来组织 ...
随机推荐
- ios中第三方库归结
1:uiscrollview 折叠 展开中不包含tablecell. 展开列表效果 Collapse Click () https://github.com/bennyguitar/Collapse ...
- springmvc是如何和前端页面联系起来的
springmvc的使用,在controller中通过注解的形式,获取从前端jsp页面传过来的action参数. 方法/步骤 使用springmvc必须在web.xml中配置(Dispatcher ...
- boost boost::asio::read socket.read_some 区别
boost boost::asio::read 尝试读一定数量的字节,直到读到为止,或者出错 socket.read_some 读一下socket,读到多少算多少 带async的类似
- DMA直接内存存取原理
DMA是指外部设备不通过CPU而直接与系统内存交换数据的接口技术. 要把外设的数据读入内存或把内存的数据传送到外设,一般都要通过CPU控制完成,如CPU程序查询或中断方式.利用中断进行数据传送,可以大 ...
- Entity Framework中实体模型命名空间的问题
在添加一个实体数据模型的时候(就是扩展名为edmx那位)属性里明明设置了自己的命名空间,但是后台的Designer.cs命名空间生成规则却是项目的默认命名空间加edmx文件所在文件夹的名称, 是BUG ...
- bootstrap fileinput 文件上传
最近因为项目需要研究了下bootstrap fileinput的使用,来记录下这几天的使用心得吧. 前台html页面的代码 <form role="form" id=&quo ...
- 【MongoDB】MongoDB的一些操作命令
我们首先应该知道MongoDB的数据结构:MongoDB:库-->集合-->JSON对象 查看 show dbs //查看有哪些库 show collections //查看库中有哪 ...
- python md5 问题(TypeError: Unicode-objects must be encoded before hashing)
import hashlib import sys def md5s(): m=hashlib.md5() strs=sys.argv[1] m.update(strs.encode("ut ...
- iphone5 jail break
dfu恢复恢复备份越狱afc2add删除2个文件,如果只有1个也没问题/var/mobile/Library/Caches/com.apple.mobile.installation.plist/va ...
- 是时候用PerconaDB替换MySQL了
Percona数据库服务器是MySQL的增强版,替代MySQL并不复杂. 一.PerconaDB的特性 1)查询速度更快,数据的一致性更好 2)服务器运行及其稳定 3)可以延迟分片,或者避免分片 4) ...