【问题标题】:Why do most linked list looping macros in the kernel skip the first element? [duplicate]为什么内核中的大多数链表循环宏都会跳过第一个元素? [复制]
【发布时间】:2020-05-12 20:18:40
【问题描述】:

我可能错了,但继续查看 <linux/list.h> 中的代码,我发现像 list_for_each_entry_safe 这样的宏从第二个元素开始:

#define list_for_each_entry_safe(pos, n, head, member)          \
    for (pos = list_entry((head)->next, typeof(*pos), member),  \
        n = list_entry(pos->member.next, typeof(*pos), member); \
         &pos->member != (head);                    \
         pos = n, n = list_entry(n->member.next, typeof(*n), member))

注意循环以pos = list_entry((head)->next开头。

我知道这可能听起来很挑剔,但在 Python 中的“真正”foreach 中你从第一个或第 0 个元素开始。

在内核中违反这个约定有什么特别的原因吗? 是出于性能原因吗?

还是我对上述代码的理解完全错误?

【问题讨论】:

  • 避免使用特殊代码处理空列表的一种常用技术是使用与列表中的数据不对应的 header 节点。
  • 也避免了删除列表第一个元素时出现的问题。
  • @0andriy:是什么让你认为这是一个双向链表?
  • @ScottHunter,你读过 OP 中的文字吗?您是否通过链接阅读了答案?我怀疑“不”和“不”。

标签: c linux foreach linked-list linux-kernel


【解决方案1】:

内核的列表类型是侵入式数据结构,其中列表元素结构包含在列表的数据元素中,而不是包含数据元素(或指向的指针)的外部列表它们)在列表元素中。

但是,列表的第一个(头)元素不包含在数据元素中。相反,它包含在拥有列表的数据结构中(可能与数据元素的类型不同)。这意味着在迭代列表的数据元素时,您不包括列表头(因为它根本不包含在数据元素中)。

例如,struct device(在linux/device.h 中定义)包含一个字段struct list_head msi_list;。这是struct msi_desc(在linux/msi.h 中定义)列表的头部,struct msi_desc 包含对应的字段struct list_head list;。 MSI 描述符列表由struct list_head 元素的链表组成,但头元素是struct devicemsi_list 字段,而其他元素是struct msi_desc 的每个list 元素。在迭代列表时,我们只想迭代 struct msi_desc 数据元素(我们已经有了 struct device - 这就是我们首先获得列表头部的方式)。

【讨论】:

    【解决方案2】:

    head 是列表本身的head,而不是列表的第一个元素。而head->next实际上是一种引用列表第一个元素的方式。

    例如,下面是返回列表第一个条目的宏的定义:

    #define list_first_entry(ptr, type, member) \
        list_entry((ptr)->next, type, member)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-11-23
      • 2022-01-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-08
      • 2017-07-28
      • 2014-01-08
      相关资源
      最近更新 更多