Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C: Linux built in linked list in kernel data structures usage

I am attempting to add a system call to my linux kernel and it would be advantageous to use the built-in linked list as I am modifying the task_struct (by adding a linked list), and the task_struct already has quite a few struct list_head's in there for other purposes. For uniformity, I would like to stick with this data structure.

My issue is that I really don't fully understand how to use this structure. I see that they have "struct list_head children" for example. However, the implementation of this structure is simple a "*next" and "*last".

I've looked into examples online and every single one says, well make

struct node{
    int data;
    struct list_head list;
}; 

But wouldn't this indicate that the data structure I should be including in my task_struct should be

struct node list;

?

I don't quite understand how I would initialize the structure to contain the data I would like it to contain if I use list_head.

Essentially I want to add a linked list of system calls and tack them on to the process in the form of a linked list of char* (readable format).

For now, the semantics of obtaining the system call information is unimportant... I just need to figure out how to get the linked list working with the task_struct.

Edit: For example of what I am trying to do:

I've obtained a list of system calls performed by a function. I am keeping these in separate char* variables. I would like to add a list within the processes task_struct that keeps track of all of these system calls.

For example

Process 'abc' calls printf ~> equates to "WriteScreen" getchar ~> equates to "ReadKey"

I now have a userland piece of code that has these two strings. I call a system call that I will write (once per tag) to "tag" the process with these system calls.

After both calls, the task_struct of 'abc' has a list

abc->task_struct->tag_list

This list contains "WriteScreen" and "ReadKey".

Later I will use these tags to print a list of processes that have called WriteScreen, ReadKey, etc. The implementation of these will happen after I find out how to use the list to appropriately store the strings attached to a process.

like image 929
Aserian Avatar asked Feb 12 '23 15:02

Aserian


1 Answers

So instead of creating a list of processes (task_struct) what you're trying to accomplish is a list per process.

This means that each process will have its own list, i.e. its own list head.

This list will store, in addition to next/prev pointers, a single piece of data, actually a string (could be the string itself or a pointer to a string elsewhere).

The list node will be therefore:

struct my_node {
    struct list_head list;
    char data[100]; // arbitrarily set to 100; could be also char*
}

The task_struct should be augmented with a new list head:

struct task_struct {
  // many members that contains info about a process
  ...

  struct list_head my_list;
}

Yes. You'll notice that both cases (when the process belongs to a list, and when the list belongs to the process) the member will be the same; only its use is different.

Now, when a process is created you should initialize the list head (as each process will have a new list):

struct task_struct *new_process;
INIT_LIST_HEAD(&new_process->my_list);

To insert a new node (supposing you already created it, that is, allocated memory and initialized its data):

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);

To iterate over the elements:

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
}

EDIT:

Note, however, that you have other ways to do what you are trying to do, without resorting to complex linked lists.

For instance, you could allocate a single char array and encode a list of strings by means of separating them by some char (commas, periods, and so on). This way:

"WriteScreen,ReadKey\0"

In this case you should look after your buffer limits, to never overflow it. On the other hand you do not have to take care of allocating and freeing nodes of a list.

like image 119
rslemos Avatar answered Feb 16 '23 02:02

rslemos