解释list_for_each_entry和list_for_each_entry_safe

goo*_*ies 17 list linux-device-driver linux-kernel

谁能解释一下linux中list_for_each_entry和... entry_safe循环的工作原理.它像是

list_for_each_entry(type *cursor, struct list_head *list, member)

list_for_each_entry_safe(type *cursor, type *next, struct list_head *list,member)

所有这些参数的作用是什么以及它们如何用于遍历列表.

提前致谢

Dan*_*tos 17

编辑:对不起,一定是迟到了,我做了很多错别字.

他们很有趣!:)不同之处在于,list_for_each_entry如果在迭代列表时删除某些内容将会中断,而list_for_each_entry_safe不会(当然,以牺牲一些额外的CPU指令为代价).

虽然在list.h中有一个单独的链表实现,但内核已经确定了双链表(我假设您理解).你的清单只是:

struct list_head {
    struct list_head *next;
    struct list_head *prev;
};
Run Code Online (Sandbox Code Playgroud)

请注意,相同的结构用于列表的"头部"以及每个节点.当列表为空时,头部nextprev成员只指向头部自己.因此,迭代列表只是一个从头部next成员开始并调用该节点的过程,除非它与prev(当你停止时)相同的地址.否则,您的for身体被调用,您可以使用container_of()宏来获取指向您的实际结构的指针并使用它.然后,在第3个字段中for,我们只是移动到下一个next.

编辑:哎呀,我道歉,你要求解释参数.好吧,如果我是你,我会直接检查出来,而不是采取别人的话.对于那些,我会建议自己的内核API文档,至少存在于链表库中.我正在尝试获得一个补丁集,它将为红黑树库添加它们,但是获取内容可能是一个相当大的过程.

另请注意:http://kernelnewbies.org/FAQ/LinkedLists

这是一个简单的例子:

struct list_head my_actual_list;
struct my_struct {
    struct list_head node;
    /* some other members */
};

/* in a function body somewhere... */
struct list_head *i;
list_for_each(i, &my_actual_list) {
    struct my_struct *obj = list_entry(i, struct my_struct, node);
    // do something with obj
}
Run Code Online (Sandbox Code Playgroud)

list_entry 只是一个别名 container_of

编辑#2

好的,所以在评论中回答你的问题时,我只想扩展我的答案.我真的很感激掌握这个概念的困难,因为它与C++ STL容器,C数组等相比确实有一些奇怪的东西,但是一旦你习惯了习语,它看起来很自然.仍然在未来,我真的敦促你自己开始研究这些结构,函数和宏的定义,并尝试拼凑一个理解,然后提出问题.

所以第一关,在列表中的每个节点是包含类型的成员的结构struct list_head和列表自身的类型struct list_head.因此,谁是容器并且在这种情况下包含谁,仅仅取决于它们的使用方式,但通常,它将以这些成员给出的名称表示.迭代器的类型是struct list_head *.这是一个例子,我将用它们的等效代码替换普通函数和宏调用:

struct my_container {
    struct list_head list;
    int some_member;
    /* etc. */
};

struct my_obj {
    struct list_head node;
    int some_member;
    /* etc. */
};

void func() {
    struct my_container container;
    struct my_obj obj1, obj2;
    struct list_head *i;

    /* INIT_LIST_HEAD(&container.list); */
    container.list.next = &container.list;
    container.list.prev = &container.list;

    /* list_add_tail(&obj1.node); */
    container.list.prev = &obj1.node;
    obj1.node.next = &container.list;
    obj1.node.prev = &container.list;
    container.list.next = &obj1.node;

    /* list_add_tail(&obj2.node); */
    container.list.prev = &obj2.node;
    obj2.node.next = &container.list;
    obj2.node.prev = &obj1.node;
    obj1.node.next = &obj2.node;

    /* list_for_each(i, &container.list) { */
    for (i = container.list.next; i != &container.list; i = i->next) {
        struct my_obj *obj = list_entry(i, struct my_obj, node);
        /* do stuff */
    }

}
Run Code Online (Sandbox Code Playgroud)

现在去看看!:)