簡體   English   中英

C: Linux 內核數據結構使用中內置鏈表

[英]C: Linux built in linked list in kernel data structures usage

我正在嘗試向我的 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”

我現在有一個包含這兩個字符串的用戶級代碼。 我調用一個系統調用,我將編寫(每個標簽一次)用這些系統調用“標記”進程。

在兩次調用之后,'abc' 的 task_struct 有一個列表

abc->task_struct->tag_list

此列表包含“WriteScreen”和“ReadKey”。

稍后我將使用這些標簽來打印調用了 WriteScreen、ReadKey 等的進程列表。在我找到如何使用列表來適當地存儲附加到進程的字符串后,將執行這些操作。

因此,您嘗試完成的不是創建進程列表 (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;
}

是的。 您會注意到這兩種情況(當流程屬於列表時,以及當列表屬於流程時)成員是相同的; 只是它的用途不同。

現在,當一個進程被創建時,你應該初始化列表頭(因為每個進程都會有一個新列表):

struct task_struct *new_process;
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"

在這種情況下,您應該注意緩沖區限制,不要讓它溢出。 另一方面,您不必負責分配和釋放列表的節點。

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 list_head的字段struct list_head的指針來獲得指向該struct node類型的指針。 這個魔法是由在list_entry調用的container_of宏完成的。

希望我有所幫助。

編輯:這個答案是在 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;
}

這種增強本身不會做任何事情,因為沒有人會更改或以其他方式訪問該成員。

您應該在其他地方聲明您的列表頭(例如全局),然后您可以開始向您的列表添加進程(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
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM