list_for_each 详解
最近在学习linux内核,看到进程管理时,有这么一段代码,一脸懵逼;
struct task_struct *task;
struct list_head *list;
list_for_each(list, ¤t->children) {
task = list_entry(list, struct task_struct, sibling); /* task 现在指向某个子进程 */ }
其中task即为某个子进程的地址
于是求助大百度,现做些总结:
offsetof
//offsetof(/include/linux/stddef.h):相关宏在内核中的地址
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
为清楚了解list_for_each的含义,先从offsetof开始讲起,offsetof表示MEMBER类型在TYPE类型中的偏移位置;该宏写的很巧妙,将0地址强转为TYPE类型,在对其中的MEMBER进行取址,将该地址转为size_t类型就获得了MEMBER类型在TYPE类型中的偏移位置。
container_of
//container_of(include/linux/kernel.h):
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
typeof表示取对应参数的类型;
container_of的作用表示先求出结构体成员(即member)在结构体(即type)中的偏移量,然后再根据member的地址(即ptr)来求出其所在结构体的地址。
list_for_each
#define list_for_each(pos, head) \
for (pos = (head)->next; prefetch(pos->next), pos != (head); pos = pos->next)
表示遍历循环链表,起始值是pos = (head)->next,条件是pos != (head),条件不满足时遍历下一个值pos = pos->next
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
list_entry就表示ptr所在的结构体的地址,就是指针;
list_for_each(list, ¤t->children) {
task = list_entry(list, struct task_struct, sibling); /* task 现在指向某个子进程 */ }
因此上面代码的含义就是依次访问当前线程的所有子线程;
prefetch()的作用
有一个共识是:程序访问的变量如果都能在系统内存cache中则能提升性能,prefetch是内核中一个预热内存函数,这样下次遍历时就能高效命中内存cache,从而提升程序性能。上面的代码中遍历链表时下次访问的内存为pos->next,故在每次遍历时对pos->next进行预热,从而提升性能。