struct list_head * next, * prev;
};
乍一看这定义,似乎很普通,但妙就妙在普通上。
data_type data;
list_node * next, * prev;
}
示意图如下:
container_of(ptr, type, member)
跟踪到container_of宏:
const typeof ( ((type * ) 0 ) -> member ) * __mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
这里面offsetof不需要跟踪,我们也能理解这个宏的意思了。先简单对宏的三个参数说明一下。ptr是指向list_head数据结构的指针,type是容器数据结构的类型,member是list_head在type中的名字。直接看下面的示例代码:
xxx;
list_head list1;
list_head list2;
xxx;
};
struct data vardat = {初始化};
list_head * p = & vardat.list1;
list_head * q = & vardat.list2;
list_entry(p, struct data, list1) == & vardat;
list_entry(q, struct data, list2) == &vardat;
从上面这个例子可以看出,vardat可以同时挂到两个(或更多)链表上,其中list1是第一个链表上的一个节点,list2是第二个链表上的节点,从&list1和&list2都可以得到vardat,上面提出的问题也就解决了。
看过之后恍然大悟,原来这么简单,把一个TYPE类型的指向0的指针,其MEMBER自然就是offset,妙哉!
list_add_tail( new , head); // 额,跟上面的区别就不用解释了,不过这里的head是真正的链表头
list_del(entry); // 删除entry节点
list_empty(head); // 检查是否为空链表
list_entry(ptr, type, member); // 前面解释过了
list_for_each(pos, head); // 遍历列表,每次循环是通过pos返回节点list_head指针
// 下面这个最有用!
list_for_each_entry(pos, head, member); //同上,但通过pos返回的是container数据结构的地址。
慢!发现一个问题了,list_entry中需要type,为啥list_for_each_entry不需要呢?简单,pos是你给的一个container数据结构的指针,在宏的实现中,用typeof(*pos)就得到type了!
// xxxxxxx
struct hlist_head preempt_notifiers;
struct list_head rcu_node_entry;
struct list_head tasks;
struct list_head children; /* list of my children */
struct list_head sibling; /* linkage in my parent's children list */
struct list_head ptraced;
struct list_head ptrace_entry;
struct list_head thread_group;
// 还有好多list,不抄了……
}
其中tasks是所有进程组成的链表,因此要遍历所有进程,可以用这个宏:
for (p = & init_task ; (p = next_task(p)) != & init_task ; )
#define next_task(p) \
list_entry((p)->tasks.next, struct task_struct, tasks)
{
int frobozz;
LIST_ENTRY(Frob) frob_link; /* this contains the list element pointers */
};
LIST_HEAD(Frob_list, Frob) /* defines struct Frob_list as a list of Frob */
struct Frob_list flist; /* declare a Frob list */
LIST_INIT( & flist); /* clear flist (globals are cleared anyway) */
flist = LIST_HEAD_INITIALIZER( & flist); /* alternate way to clear flist */
if (LIST_EMPTY( & flist)) /* check whether list is empty */
printf( " list is empty\n " );
struct Frob * f = LIST_FIRST( & flist); /* f is first element in list */
f = LIST_NEXT(f, frob_link); /* now f is next (second) element in list */
f = LIST_NEXT(f, frob_link); /* now f is next (third) element in list */
for (f = LIST_FIRST( & flist); f != 0 ; /* iterate over elements in flist */
f = LIST_NEXT(f, frob_link))
printf( " f %d\n " , f -> frobozz);
LIST_FOREACH(f, & flist, frob_link) /* alternate way to say that */
printf( " f %d\n " , f -> frobozz);
f = LIST_NEXT(LIST_FIRST( & flist)); /* f is second element in list */
LIST_INSERT_AFTER(f, g, frob_link); /* add g right after f in list */
LIST_REMOVE(g, frob_link); /* remove g from list (can't insert twice!) */
LIST_INSERT_BEFORE(f, g, frob_link); /* add g right before f */
LIST_REMOVE(g, frob_link); /* remove g again */
LIST_INSERT_HEAD( & flist, g, frob_link); /* add g as first element in list */