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

99封情书 提交于 2021-02-07 03:18:33

问题


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 .


回答1:


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

Than

list_for_each(list, &current->children)

Will initialize list pointers to sibling, so you have to use subling 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);

Than 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.




回答2:


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




回答3:


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.




回答4:


But why not:

the list was created this way:

list_add(subtask, &current->children);

iterate in this way:

list_for_each(list, &current->children) {
  child = (struct task_struct *)list
}


来源:https://stackoverflow.com/questions/34704761/why-sibling-list-is-used-to-get-the-task-struct-while-fetching-the-children-of-a

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!