我正在尝试向我的linux内核添加一个系统调用,因为我正在修改task_struct(通过添加一个链表),使用内置链表是有利的,而task_struct已经有很多了struct list_head在那里用于其他目的。为了统一,我想坚持使用这种数据结构。
我的问题是我真的不完全了解如何使用这种结构。我看到他们有例如“struct list_head children”。但是,这种结构的实现很简单,即“* next”和“* last”。
我在线查看了一些示例,每个人都说,好吧
struct node{
int data;
struct list_head list;
};
但这不会表明我应该在task_struct中包含的数据结构应该是
struct node list;
我不太明白如果我使用list_head,我将如何初始化结构以包含我希望它包含的数据。
基本上我想添加一个系统调用的链接列表,并以char *(可读格式)的链接列表的形式将它们添加到进程中。
目前,获取系统调用信息的语义并不重要......我只需要弄清楚如何使链表与task_struct一起工作。
编辑:例如我要做的事情:
我已经获得了一个由函数执行的系统调用列表。我将它们保存在单独的char *变量中。我想在进程task_struct中添加一个列表来跟踪所有这些系统调用。
例如
处理'abc'调用 printf~>等同于“WriteScreen” getchar~>等同于“ReadKey”
我现在拥有一个包含这两个字符串的userland代码片段。我打电话给系统调用,我会写(每个标签一次)用这些系统调用“标记”过程。
两次调用后,'abc'的task_struct都有一个列表
ABC-> task_struct-> tag_list
此列表包含“WriteScreen”和“ReadKey”。
稍后我将使用这些标记来打印一个名为WriteScreen,ReadKey等的进程列表。在我找到如何使用该列表来正确存储附加到进程的字符串之后,将会实现这些。< / p>
答案 0 :(得分:4)
因此,您不是要创建一个进程列表(task_struct),而是要为每个进程创建一个列表。
这意味着每个进程都有自己的列表,即自己的列表头。
除了next / prev指针外,此列表还将存储单个数据,实际上是一个字符串(可以是字符串本身或指向其他地方的字符串的指针)。
因此列表节点将是:
struct my_node {
struct list_head list;
char data[100]; // arbitrarily set to 100; could be also char*
}
应该使用新的列表头扩充task_struct:
struct task_struct {
// many members that contains info about a process
...
struct list_head my_list;
}
是。您会注意到这两种情况(当进程属于列表时,以及列表属于进程时)成员将是相同的;只是它的用途不同。
现在,当创建进程时,您应该初始化列表头(因为每个进程都有一个新列表):
INIT_LIST_HEAD(&new_process.my_list);
要插入新节点(假设您已经创建了它,即分配了内存并初始化了其数据):
struct my_node *node;
struct task_struct *a_process;
[... my_node initialized ...]
[... a_proccess obtained somehow ...]
list_add_tail(&node->list, &a_process->my_list);
迭代元素:
struct my_node *p;
struct task_struct *a_process
// list is the member name (yes, the member name) of your list inside my_node
list_for_each_entry(p, &a_process->my_list, list) {
// do whatever you want with p
}
修改强>
但请注意,您可以通过其他方式执行您尝试执行的操作,而无需使用复杂的链接列表。
例如,您可以分配一个char数组并通过一些char(逗号,句点等)将它们分开来编码字符串列表。这样:
"WriteScreen,ReadKey\0"
在这种情况下,你应该照顾你的缓冲区限制,永远不要溢出它。另一方面,您不必负责分配和释放列表的节点。
答案 1 :(得分:2)
关于Linux内核链表的重要参考是http://www.makelinux.net/ldd3/chp-11-sect-5。
您可以像这样初始化结构:
struct node node_var = {
.data = 0,
.list = LIST_HEAD_INIT(node_var.list)
}
您可以像这样遍历列表:
struct list_head *phead;
list_for_each(phead, node_var.list)
{
struct node * pnode = list_entry(phead, struct node node_var, list);
// Do what you may with the pnode.
}
确实看起来很奇怪。我们通过使用指向该结构的字段struct node
的指针来获取指向struct list_head
类型的指针。这种魔法是由container_of
内部调用的list_entry
宏完成的。
希望我能帮忙。
答案 2 :(得分:2)
编辑:在OP提供更清楚的解释之前提供了这个答案。
您应该只使用新成员修改task_struct:
struct task_struct {
// many members that contains info about a process
...
// then come the lists that a process may participate
...
// then you amend with your new list
struct list_head my_list;
}
这种扩充本身不起作用,因为没有人会改变或以其他方式访问该成员。
您应该将列表头部声明为其他地方(例如全局),然后您可以将addind进程(task_struct)启动到列表中。
LIST_HEAD(my_list_head); // this will declare, define and initialize a new variable:
// an empty list.
Linux内核链接列表宏将为您处理所有事情。
task_struct *a_given_process; // assigned elsewhere, maybe passed as parameter to current function
list_add_tail(&a_given_process->my_list, my_list_head); // an example
修改强>
迭代项目:
struct task_struct *p;
// my_list_head is the head of your list (declared with LIST_HEAD)
// my_list is the member name (yes, the member name) of your list inside task_struct
list_for_each_entry(p, my_list_head, my_list) {
// do whatever you want with p
}