【发布时间】:2019-10-31 07:04:26
【问题描述】:
我正在尝试在用户空间中使用https://github.com/torvalds/linux/blob/master/include/linux/list.h 中提到的 linux 内核双向链表实现,它的用户空间实现可以在 https://gist.github.com/roychen/1710968 中找到
以下是我最初使用的代码,它运行良好:)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "list.h"
struct Node
{
int data;
char name[10];
struct list_head mylist;
};
int main()
{
LIST_HEAD(plist);
struct Node node1 = {.data = 10, .name = "node1", .mylist = LIST_HEAD_INIT(node1.mylist)};
struct Node node2;
node2.data = 20;
strcpy(node2.name, "node2");
INIT_LIST_HEAD(&node2.mylist);
list_add_tail(&node1.mylist, &plist);
list_add_tail(&node2.mylist, &plist);
struct Node* iter;
list_for_each_entry(iter, &plist, mylist)
{
printf("name = %s, data = %d\n", iter->name, iter->data);
}
return 0;
}
上面代码的输出是
name = node1, data = 10
name = node2, data = 20
符合预期。
现在假设我想添加node1 两次
场景一:
list_add_tail(&node1.mylist, &plist);
list_add_tail(&node1.mylist, &plist);
输出 1:
name = node1, data = 10
name = node1, data = 10
name = node1, data = 10
name = node1, data = 10
name = node1, data = 10
name = node1, data = 10
name = node1, data = 10
name = node1, data = 10
name = node1, data = 10
name = node1, data = 10
name = node1, data = 10
name = node1, data = 10
name = node1, data = 10
name = node1, data = 10
... -> non-stopping loop (to infinity)
场景二:
list_add_tail(&node1.mylist, &plist);
list_add_tail(&node2.mylist, &plist);
list_add_tail(&node1.mylist, &plist);
输出 2:
name = node1, data = 10 (-> just one node is added to the list instead of 3 nodes)
以上输出表明 list.h 实现存在错误,至少在它的一个函数宏中。
不知道在链表中不能两次添加节点的bug在哪里。
有什么想法吗?! :|
***** 编辑 ***** 场景 3:
list_add_tail(&node1.mylist, &plist);
list_add_tail(&node2.mylist, &plist);
list_add_tail(&node1.mylist, &plist);
struct Node* iter;
list_for_each_entry_reverse(iter, &plist, mylist)
{
printf("name = %s, data = %d\n", iter->name, iter->data);
}
输出 3:
name = node2, data = 20
name = node1, data = 10
name = node2, data = 20
name = node1, data = 10
name = node2, data = 20
name = node1, data = 10
name = node2, data = 20
name = node1, data = 10
name = node2, data = 20
name = node1, data = 10
... -> non-stopping loop (to infinity)
【问题讨论】:
-
这不是 Linux 中的错误。这是您的程序中的一个错误,您希望同一块内存可以在列表中出现多次而不会创建循环。
-
列表中单个元素的next指针只能指向一个位置,但是添加两次时需要同时指向两个不同的位置(不能做)。您看到的是这种内在限制的副作用。
-
考虑哪种可能性更大——(1) 数百甚至数千甚至数百万的 Linux 黑客使用了双向链表机制,却没有发现你突然遇到的问题,但他们都是错误并且应该注意到你发现了什么,或者 (2) 你正在滥用一个经过良好测试和已知在未滥用时可以工作的系统。总的来说,我认为你犯错的可能性比其他人都大。抱歉,但在与此类似的情况下,其他人都错的可能性微乎其微,甚至可以忽略不计。这几乎(但不完全)总是你正在做的事情。
-
您可能会在您首先链接到的主实现中观察到
list_add_tail()之前的cmets: ——/** * list_add_tail - add a new entry * @new: new entry to be added * @head: list head to add it before * * Insert a new entry before the specified head. * This is useful for implementing queues. */—— 注意多次出现“新条目”。您的代码没有创建新条目;它正在尝试重用现有条目。 -
我很佩服你的自信,但请记住,傲慢会导致克星。
标签: c linux linked-list linux-kernel