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为链表头的实体链表,对实体链表中的数据结构进行处理。