list_for_each_entry
2024-09-11 21:01:15
内核里面用list_for_each_entry实在太多了,定义在linux-3.10/include/linux/list.h:
/**
* list_for_each_entry - iterate over list of given type
* @pos: the type * to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member); \
&pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member)) /**
* 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) \
container_of(ptr, type, member)
要分析list_entry就得分析container_of,linux-3.10/include/linux/kernel.h:
/**
* container_of - cast a member of a structure out to the containing structure
* @ptr: the pointer to the member.
* @type: the type of the container struct this is embedded in.
* @member: the name of the member within the struct.
*
*/
#define container_of(ptr, type, member) ({ \
const typeof( ((type *))->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
宏定义的第一行:typeof(x)是gcc预处理,获取x的类型,这里((type *)0)->member利用p=0的指针指向相应结构体(type)的成员,typeof获取该成员的类型并定义__mptr。
第二行:#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER),跟第一行的((type *)0)->member一个样子,获取结构体(type)的偏移量,最后__mptr转换成(char *)减去自己在结构体(type)的偏移量得到结构体(type)的指针。
可以看出第一行在功能上是没有什么卵用,其实只是作为类型检测,实现一个给定成员类型(member)的指针(ptr)找到这个成员的结构体(type)功能的只在第二行。
返回看list_entry(ptr, type, member)其实就是通过ptr找到type。
再回到list_for_each_entry(pos, head, member)的实现可以知道,用list_head通过list_entry找到包含next list_head的结构体(pos)作为变量进行循环。可得要使用list_for_each_entry,struct pos里面的成员必须包含list_head。所以在linux里面的struct经常看到list_head这个成员就是这个道理
最新文章
- AndroidStudio关联svn并上传代码到svn服务器上
- 摄像头/光驱故障:由于其配置信息(注册表中的)不完整或已损坏,Windows 无法启动这个硬件设备。 (代码 19)
- 在MVC3中修改KindEditor实现图片删除
- Http协议之Get和Post的区别
- Cheatsheet: 2014 04.01 ~ 04.30
- SQL SERVER(MSSQLSERVER) 服务无法启用 特定服务错误:126
- SDKInitializer.initialize报错求助
- delphi 反射(原理)
- Bluetooth LE(低功耗蓝牙) - 第一部分
- win7 安装 redis +php扩展
- 远程方法调用(RMI)原理与示例 (转)
- 2.定义图形类Shape,该类中有获得面积的方法getArea();定义长方形类Rect,该类是Shape的子类,类中有矩形长和宽的变量double a,double b,设置长和宽的方法setWidth()、setHeight(),使用getArea()求矩形面积;利用getArea方法实现题1中圆面积的求解。
- Thuwc 2019 &; wc 2019 划水记
- SpringMVC的执行流程
- Docker中如何删除image(镜像)
- Confluence 6 缓存性能优化
- 701 C. They Are Everywhere
- python3 线程池-threadpool模块与concurrent.futures模块
- 盒子变形-盒子加padding后 变形问题,
- java学习第03天(运算符、语句)
热门文章
- yii框架模型操作
- 【转载】openwrt框架分析
- Shell编程基础及变量
- DNS 缓存机制原理
- POJ 1144 无向图求割点
- redis中文文档
- MYSQL limit用法
- Email-Ext Plugin install ------ Jenkins Plugins
- Caused by: org.apache.ibatis.binding.BindingException: Parameter 'parameter' not found.解决
- 字符在内存中最终的表示形式是什么?是某种字符编码还是码位(Code Point)?