Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

why sibling list is used to get the task_struct while fetching the children of a process

Kernel task_struct looks like below.I am more interested in two members namely children and sibling , so i have removed other elements from this kernel structure .

  struct task_struct{
        // some data elements .


          struct list_head children;      
              /* list of my children */

          struct list_head sibling;
              /* linkage in my parent's children list */
        //some data members 
        };

"children" is a doubly circular linked list of task_struct of the children of process .If I want to access the children from current process , I have to iterate over "children" list using macro "list_for_each" as below :

struct task_struct *task; 
struct list_head *list;
list_for_each(list, &current->children) { 
task = list_entry(list, struct task_struct, sibling); /* task now points to one of current’s children */ 
}

list_for_each will eventually initialize "list " with next children .Now since we are iterating through children list , we should ideally subtract the offset of "children" list from "list" pointer to get the tast_struct address for the current process .What is the reason we are passing "sibling" here which eventually a different list with different offset? .

Please note : It is working code , all I want to understand is why sibling is used when children pointer should be used to calculate correct offset and hence task_struct address for the children .

Thanks in Advance .

like image 506
SACHIN GOYAL Avatar asked Jan 10 '16 11:01

SACHIN GOYAL


3 Answers

In order to organize data as linked list using struct list_head you have to declare list root and declare list entry for linkage. Both root and child entries are the same type (struct list_head). children entry of struct task_struct entry is a root. sibling entry of struct task_struct is a list entry. To see the differences, you have to read code, where children and sibling are used. Usage of list_for_each for children means what children is a root. Usage of list_entry for sibling means what sibling is a list entry.

You can read more about linux kernel lists here.

Question: What is the reason we are passing "sibling" here which eventually a different list with different offset?

Answer:

If the list was created this way:

list_add(&subtask->sibling, &current->children);

Then

list_for_each(list, &current->children)

Will initialize list pointers to sibling, so you have to use sibling as parameter to list_entry. That's how linux kernel lists API designed.

But, If the list was created in another (wrong) way:

list_add(&subtask->children, &current->sibling);

Then you have to iterate the list this (wrong) way:

list_for_each(list, &current->sibling)

And now you have to use children as parameter for list_entry.

Hope, this helps.

like image 50
alexander Avatar answered Oct 14 '22 09:10

alexander


Following is the pictorial representation that might help someone in future. The top box represents a parent, and the bottom two boxes are it's children

enter image description here

like image 26
Vivek Maran Avatar answered Oct 14 '22 08:10

Vivek Maran


Here is a picture in addition to the previous answers. The same process can be both a parent and a child (as Parent1 on the picture), and we need to distinguish between these two roles.

Intuitively, if children of Parent0 would point to children of Parent1, then Parent0.children.next->next (green circle on the picture), which is the same as Parent1.children.next, would point to a child of Parent1 instead of a next child of Parent0.

enter image description here

like image 3
juliet Avatar answered Oct 14 '22 09:10

juliet