在前面的文章《linux内核中的双向链表-01》中描述了双向链表的定义以及常用API,其中有个非常重要的宏定义:list_entry(ptr, type, member)。它可以在已知结构体成员地址的情况下,还原出结构体的首地址。
input子系统的事件处理层对应的内核对象为:struct input_handler
,input_handler的node成员串在一起,组成了双向链表,表头节点为:input_handler_list
。如下图所示:
思考一个问题:在已知input_handler_list
的情况下,如何打印出所有input_handler
对象的name
成员?
方法一
第一步,遍历以input_handler_list
为头节点的双向链表,则每一个节点都是struct list_head node
结构,我们定义一个变量pos
来接收。遍历双向链表可以使用内核API:list_for_each_safe()
。则:
c
struct list_head *pos; // 接收遍历到的当前节点
struct list_head *tmp; // 临时变量
list_for_each_safe(pos, tmp, &input_handler_list);
第二步,根据获取到的struct list_head node
成员,求出其所在的input_handler
结构体的首地址,并定义一个变量item
来接收。通过成员地址求所在结构体首地址的内核API:list_entry()
。则:
c
struct input_handler *item;
item = list_entry(pos, struct input_handler, node);
第三步,打印各个input_handler
对象的name
属性:
c
pr_info("handler name: %s\n", item->name);
方法二
直接使用内核API:list_for_each_entry()
,其等效于先使用list_for_each_safe()
获得各个结构体成员,再使用list_entry()
获取各个结构体首地址。
c
struct input_handler *item;
list_for_each_entry(item, &input_handler_list, node) {
pr_info("handler name: %s\n", item->name);
}