list - 说明list_for_each_entry和list_for_each_entry_safe

标签 list linux-kernel linux-device-driver

谁能解释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)
所有这些参数的作用是什么,以及如何使用它们遍历列表。

提前致谢

最佳答案

编辑:对不起,一定要晚了,我犯了很多错字。

他们真有趣! :)区别在于,如果您在迭代列表时删除某些内容,则list_for_each_entry会中断,而list_for_each_entry_safe不会中断(当然,这要花一些额外的CPU指令)。

尽管list.h中有一个歌唱的链表实现,但内核已经确定了双链表(我想您理解了)。您的 list 是:

struct list_head {
    struct list_head *next;
    struct list_head *prev;
};

注意,相同的结构用于列表的“头”以及每个节点。当列表为空时, header 的nextprev成员仅指向 header 自身。因此,迭代列表只是从头的next成员开始并调用该节点的过程,除非它与prev相同的地址(停止时)。否则,将调用for主体,并且可以使用container_of()宏获取指向实际结构的指针并对其进行处理。然后,在for的第3个字段中,我们只是移至下一个next

编辑:糟糕,我很抱歉,您要求对参数进行解释。好吧,如果我是您,我会直接检查出来,而不是相信别人。对于那些,我建议Kernel API docs本身,至少在链表库中存在。我正在尝试获得一个补丁集,该补丁集也将它们添加到红黑树库中,但是要完成任务可能是一个相当大的过程。

还要注意: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
}
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 */
    }

}

Now go read! :)

关于list - 说明list_for_each_entry和list_for_each_entry_safe,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16230524/

相关文章:

c - 使用 O_SYNC 时 mmap 非常慢

html - 对齐 li 内容底部的列表样式类型

javascript - 将字符串列表作为参数从 native java 代码传递给 javascript 函数

linux - 在 X 视频驱动程序中,调用驱动程序探测函数时使用的 PROBE_TRYHARD 标志是什么?

c - 内核用户 I/O 应用程序开发

linux-kernel - 如何找到/dev/console 连接到哪个物理设备?

python - 将项目附加到列表

python - 我的元组中的那些小 "u"是什么? ( python 2.7)

c++ - libpcap:接收帧和调用回调函数之间的延迟

linux - Linux 如何对待( protected )内存区域?