当前位置: 首页 > news >正文

list_for_each_entry 详解

目录

一  概述:

二  list_for_each_entry用法:

三 代码展示:

四 代码分析:

 4.1:分析 containner_of

4.2:分析 offsetof

4.3:分析list_for_each_entry


一  概述:

linux很多用了list_for_each_entry 来遍历整个实体链表:

下面函数结构

/*** 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_first_entry(head, typeof(*pos), member);        \&pos->member != (head);                                    \pos = list_next_entry(pos, member))

list_for_each_entry作用
我们可以了解到list_for_each_entry的作用:所有包含 list_head 的数据结构,均可使用此方法遍历链表;list_head 结构体不包含数据部分,使用该函数进行遍历链表节点,然后在循环体中,对链表的数据部分进行读写操作,通过对链表中list成员的遍历,即可定位到链表的相关节点,进而访问链表节点中的数据部分

二  list_for_each_entry用法:

如下面用法:

eg1:struct input_handler {void *private;...const char *name;const struct input_device_id *id_table;struct list_head        h_list;struct list_head        node;};struct input_handle *handle;static LIST_HEAD(input_handler_list);    //定义list_add_tail(&dev->node, &input_dev_list);    //加入链表表list_for_each_entry(handler, &input_handler_list, node) //遍历input_attach_handler(dev, handler);                   //应用eg2:		struct rc_map_table {u32     scancode;u32     keycode;};struct rc_map {struct rc_map_table     *scan;unsigned int            size;   /* Max number of entries */unsigned int            len;    /* Used number of entries */unsigned int            alloc;  /* Size of *scan in bytes */enum rc_type            rc_type;const char              *name;spinlock_t              lock;};struct rc_map_list {struct list_head         list;struct rc_map map;};static LIST_HEAD(rc_map_list);     //定义static struct rc_map_list *seek_rc_map(const char *name){struct rc_map_list *map = NULL;spin_lock(&rc_map_lock);list_for_each_entry(map, &rc_map_list, list) { //list:the name of the list_struct within the struct. //遍历if (!strcmp(name, map->map.name)) {    //应用spin_unlock(&rc_map_lock);return map;}}spin_unlock(&rc_map_lock);return NULL;}int rc_map_register(struct rc_map_list *map){spin_lock(&rc_map_lock);list_add_tail(&map->list, &rc_map_list);    //加入链表表spin_unlock(&rc_map_lock);return 0;}static struct rc_map_list encore_enltv_map = {.map = {.scan    = encore_enltv,.size    = ARRAY_SIZE(encore_enltv),.rc_type = RC_TYPE_UNKNOWN,	/* Legacy IR type */.name    = RC_MAP_ENCORE_ENLTV,}};static int __init init_rc_map_encore_enltv(void){return rc_map_register(&encore_enltv_map);}

三 代码展示:

./kernel-3.18/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_first_entry(head, typeof(*pos), member);        \&pos->member != (head);                                    \pos = list_next_entry(pos, member))/*** list_first_entry - get the first element from a list* @ptr:        the list head to take the element from.* @type:       the type of the struct this is embedded in.* @member:     the name of the list_struct within the struct.** Note, that list is expected to be not empty.*/#define list_first_entry(ptr, type, member) \list_entry((ptr)->next, type, member)/*** list_next_entry - get the next element in list* @pos:        the type * to cursor* @member:     the name of the list_struct within the struct.*/#define list_next_entry(pos, member) \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)
./kernel-3.18/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 *)0)->member ) *__mptr = (ptr);    \(type *)( (char *)__mptr - offsetof(type,member) );})

四 代码分析:

从上面可以知道list_for_each_entry----list_first_entry----list_entry----container_of

                                                        ---list_next_entry----list_entry---container_of

 4.1:分析 containner_of

#define container_of(ptr, type, member) ({                      \
            const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
            (type *)( (char *)__mptr - offsetof(type,member) );})

的作用:通过已知的数据结构成员指针ptr、数据结构type、以及ptr在数据结构中的成员名,获取到指向数据结构type的指针

首先可以看出container_of被预定义成一个函数,

函数的第一句话,通过((type*)0)->member定义一个 MEMBER 型的指针__mptr,这个指针指向ptr,所以第一句话获取到了我们要求的结构体, 它是成员member的地址,(将0地址强制转换为数据结构type类型)

函数的第一句话用这个地址减去成员member在结构体中的相对偏移量,就可以获取到所求结构体的地址,最后再把这个地址强制转换成type型指针,就获取到了所求结构体指针,define预定义返回最后一句话的值,将所求结构体指针返回。   

4.2:分析 offsetof

#define offsetof(TYPE, MEMBER) ((size_t)&((TYPE*)0)->MEMBER) 

TYPE*将整型常量0强制转换为TYPE型的指针,且这个指针指向的地址为0,也就是将地址0开始的一块存储空间映射为TYPE型的对象,接下来再对结构体中MEMBER成员进行取址,而整个TYPE结构体的首地址是0,这里获得的地址就是MEMBER成员在TYPE中的相对偏移量。再将这个偏移量强制转换成size_t型数据(无符号整型)
  所以整个offsetof的功能就是获取 MEMBER 成员在 TYPE 型数据中的偏移量。

4.3:分析list_for_each_entry

        #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))
  

理解list_for_each_entry。list_for_each_entry被预定义成一个for循环语句
list_for_each_entry被预定义成一个for循环语句,for循环的第一句话获取list_first_entry—list_entry((ptr)->next, type, member)【ptr)->next,】指向的member成员的数据结构指针,
也就是将pos初始化为除链表头之外的第一个实体链表成员,for的第三句话通过list_next_entry----list_entry((pos)->member.next, typeof(*(pos)), member)【pos->member.next】指针遍历整个实体链表,
当pos->member.next再次指向我们的链表头的时候跳出for循环。整个过程没有对链表头进行遍历(不需要被遍历),
所以使用list_for_each_entry遍历链表必须从链表头开始。因此可以看出,list_for_each_entry的功能就是遍历以head为链表头的实体链表,对实体链表中的数据结构进行处理。

http://www.dtcms.com/a/389893.html

相关文章:

  • Perplexity AI Agent原生浏览器Comet
  • 颈椎按摩器方案开发,智能按摩仪方案设计
  • Sui 学习日志 1
  • 六、Java—IO流
  • 数据库 事务隔离级别 深入理解数据库事务隔离级别:脏读、不可重复读、幻读与串行化
  • 从“纸面”到“人本”:劳务合同管理的数字化蜕变
  • ARM架构——学习时钟7.2
  • VS Code 调试配置详解:占位符与语言差异
  • 锁 相关知识总结
  • caffeine 发生缓存内容被修改以及解决方案-深度克隆
  • rust编写web服务06-JWT身份认证
  • 《怪猎:荒野》制作人:PC平台对日本游戏非常重要
  • 大模型训练框架(二)FSDP
  • MySQL——系统数据库、常用工具
  • 蓝桥杯题目讲解_Python(转载)
  • 性能测试监控实践(九):性能测试时,监控docker微服务资源利用率和分析
  • TCP,UDP和ICMP
  • Python语法学习篇(七)【py3】
  • 网页控制鼠标 查看鼠标位置
  • PIT 定时器
  • 【题解】 [蓝桥杯 2019 省 B] 特别数的和
  • 数字隔离器,串口通信的安全之“芯”
  • 山脊图 (Ridgeline Plot):使用 joypy 库,优雅地比较多组数据的分布情况
  • Linux 进程同步以及僵尸进程等知识介绍
  • Python进程和线程
  • 斐波那契数列的递归和迭代实现
  • 时空预测论文分享:规则知识 因果预测框架 面向研究的评估体系 主动适应漂移
  • 《WINDOWS 环境下32位汇编语言程序设计》第18章 ODBC数据库编程
  • linux入门(3)
  • 任意版本GitLens vscode插件破解邪修秘法