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

Issue

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 .

Solution

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.

Answered By – alexander

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published