1、list_for_each_entry_rcu
#define list_for_each_entry_rcu(pos, head, member) \
for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
prefetch(pos->member.next), &pos->member != (head); \
pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
- pos对应的结构体成员地址
- head对应的是双链表头节点
- member对应的是结构体的成员变量,同时也是一个struct list_head类型
list_for_each_entry_rcu的作用:head为链表的头,它作为一个成员member被包含在pos指向的结构体中,从head开始遍历链表,直到pos又指向包含head的结构体,停止遍历。
2、list_entry_rcu
#define list_entry_rcu(ptr, type, member) \
container_of(rcu_dereference(ptr), type, member)
- typeof关键字是C语言中的一种新扩展,返回变量的类型
- prefetch(pos->member.next):通知CPU将()内的数据预取,以提高效率。
- 判断条件:&pos->member != (head)
list_entry_rcu作用:根据指向结构体type中成员member的指针ptr,返回指向该结构体的指针。
3、 container_of
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
container_of作用:根据一个结构体变量中的一个域成员变量的指针来获取指向整个结构体变量的指针。
(type *)0)
就是将0强转为一个地址,这个地址(0x0000)指向的是类型type的数据。当然,这里是一个技巧,并不是真的在地址0x0000存放了我们的数据。
((type *)0)->member
的作用,这里的‘->’很显然是通过指针指取结构体成员的操作。指针就是刚才通过0强转的地址。所以也就是相当于地址0x0000 是结构体类型type的首地址,通过->’取其中的成员变量member。
typeof( ((type *)0)->member ) *__mptr = (ptr)
知道member成员的类型,定义一个指针变量__mptr,指向的类型是member的类型,其初始化为ptr的值
offsetof(type,member)
求出member在结构体中的偏移量
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
根据优先级的顺序,最里面的小括号优先级最高,TYPE *将整型常量0强制转换为TYPE型的指针,且这个指针指向的地址为0,也就是将地址0开始的一块存储空间映射为TYPE型的对象,接下来再对结构体中MEMBER成员进行取址,而整个TYPE结构体的首地址是0,这里获得的地址就是MEMBER成员在TYPE中的相对偏移量。再将这个偏移量强制转换成size_t型数据(无符号整型)。
(char *)__mptr - offsetof(type,member)
就是__mptr - offset,即member类型的指针减去member在结构体中的偏移量。
这样我们就能通过container_of(ptr, type, member)的返回值,得到结构体的地址。
参考链接:
- https://blog.youkuaiyun.com/qq_35399548/article/details/122854824
- https://juejin.cn/s/list_for_each_entry_rcu%20example
- https://www.cnblogs.com/Caden-liu8888/p/7693508.html