将项添加到Linux内核链表

Vis*_*ahu 5 c list linux-kernel

linux/list.h在我的代码中用于实现队列/堆栈行为.用于添加头/尾的API如下:

static inline void list_add(struct list_head *new, struct list_head *head)
{
         __list_add(new, head, head->next);
}
Run Code Online (Sandbox Code Playgroud)

类似的是list_add_tail.令人惊讶的是,它不返回任何内容(void),因此它意味着使用此API在内核中添加列表总是成功的.我知道这里没有完整的概念,但如果新节点的内存分配不可用以及其他可能的原因怎么办?

小智 11

listAPI并不动态分配的内存.我发现这件事有点令人费解,我自己.这里的问题是Linux是用C语言编写的,而不是用C++编写的,但是以一种非常面向对象的方式实现了东西,但在C语言中,它看起来像是在里面.它的工作原理如下(这也适用于其他几个Linux API,例如kobj):

您定义了一些struct,它应该是列表的成员.与您通常会想到链接列表的方式相反,此对象不会通过分配一些不透明的列表项并且指针指向您的实际对象而放入列表中,您struct list_head实际成为您的成员struct:

struct something {
    struct list_head list;
    uint8_t some_datum;
    uint16_t some_other_datum;
    void *a_pointer;
};
Run Code Online (Sandbox Code Playgroud)

您的列表将是一些独立的 struct list_head:

static LIST_HEAD(list_of_somethings);
Run Code Online (Sandbox Code Playgroud)

list_of_somethings现在添加元素就可以了

struct something *s = kmalloc(sizeof(*s), GFP_KERNEL);
s->some_datum = 23;
s->some_other_datum = 0xdeadbeef;
s->a_pointer = current;
list_add(&s->list, &list_of_somethings);
Run Code Online (Sandbox Code Playgroud)

换句话说,您已经分配了元素.这看起来很奇怪,但是像f*ck一样优雅.这种"设计模式"允许在C中使用类型不透明的列表,这在另一种方式下不容易做到:一个列表本身就是一堆struct list_heads指向彼此.如你所知,struct作为一名程序员,你知道哪些struct是实际的,你知道这是实际的哪个元素,list_head并且可以使用container_of宏来获取指向最终struct放入列表的指针:

struct list_head *p = &list_of_somethings.next;
struct something *s = container_of(p, struct something, list);
pr_notice("some data = %i\n", s->some_data);
Run Code Online (Sandbox Code Playgroud)

请注意,struct list_head表示列表本身的实际内容是由定义的迭代宏专门处理的<linux/list.h>,即

#define list_for_each(pos, head) \
        for (pos = (head)->next; pos != (head); pos = pos->next)
Run Code Online (Sandbox Code Playgroud)

地址list_of_somethings将用于确定迭代是否到达列表的末尾(或实际上是列表对象).这也是为什么将空列表定义为具有nextprev指向其struct list_head自身的原因.

我也需要一些时间来解决这个问题.;)