struct task_struct current的同级始终包含pid = 0的进程 [英] Siblings of `struct task_struct current` always include a process with `pid = 0`

查看:49
本文介绍了struct task_struct current的同级始终包含pid = 0的进程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在破解 linux 内核并与 struct task_struct current 的兄弟姐妹和孩子一起玩.

I'm hacking the linux kernel and playing with siblings and children of the struct task_struct current.

输出同胞的 pid 和命令名称时,似乎存在格式错误的进程,其中 pid = 0 ,命令名称为乱七八糟的.

When outputting the pid and command name of siblings, there appears to be a malformed process with pid = 0 and the command name is gibberish.

进程的父进程也会发生同样的事情.

The same thing occurs with the process' parents.

为什么在同级兄弟中出现 pid = 0 的进程?

Why is there a process with pid=0 showing up among the siblings? Isn't that process reserved for swapper?

// Loop over process and parents using something like:

/*
printk("--syscall ## Begin process results ##"); 

printk("--syscall // View children //");
my_list_head = &(current->children);

printk("--syscall // View siblings //");
my_list_head = &(current->sibling)

printk("--syscall results:  ...");
*/


if (my_list_head == NULL) {
  return 0;
}

list_for_each(tempNode, my_list_head) {
  tempTask = list_entry(tempNode, struct task_struct,
          sibling);
  printk("--syscall The %ld-th process's pid is %d and command %s",
         count, tempTask->pid, tempTask->comm);
 }

输出

带空格的格式

[ 2938.994084] --syscall ## Begin process results ##
[ 2938.994089] --syscall // View children //
[ 2938.994105] --syscall // View siblings //
[ 2938.994116] --syscall The 1-th process's pid is 0 and command \x80ݶE\x96\xff\xff
[ 2938.994133] --syscall results: pid=1400 name=process_ancesto state=0 uid=1000 nvcsw=1 nivcsw=0 num_children=0 num_siblings=1

[ 2938.994139] --syscall ## Begin process results ##
[ 2938.994144] --syscall // View children //
[ 2938.994149] --syscall The 1-th process's pid is 1400 and command process_ancesto
[ 2938.994158] --syscall // View siblings //
[ 2938.994163] --syscall The 1-th process's pid is 0 and command
[ 2938.994176] --syscall results: pid=1282 name=bash state=1 uid=1000 nvcsw=88 nivcsw=18 num_children=1 num_siblings=1

[ 2938.994180] --syscall ## Begin process results ##
[ 2938.994185] --syscall // View children //
[ 2938.994190] --syscall The 1-th process's pid is 1282 and command bash
[ 2938.994198] --syscall // View siblings //
[ 2938.994203] --syscall The 1-th process's pid is 1275 and command systemd
[ 2938.994210] --syscall The 2-th process's pid is 0 and command
[ 2938.994216] --syscall The 3-th process's pid is 117 and command systemd-journal
[ 2938.994222] --syscall The 4-th process's pid is 145 and command systemd-udevd
[ 2938.994227] --syscall The 5-th process's pid is 148 and command systemd-network
[ 2938.994233] --syscall The 6-th process's pid is 369 and command systemd-resolve
[ 2938.994239] --syscall The 7-th process's pid is 370 and command systemd-timesyn
[ 2938.994245] --syscall The 8-th process's pid is 412 and command accounts-daemon
[ 2938.994321] --syscall The 9-th process's pid is 413 and command dbus-daemon
[ 2938.994336] --syscall The 10-th process's pid is 417 and command irqbalance
[ 2938.994346] --syscall The 11-th process's pid is 418 and command rsyslogd
[ 2938.994352] --syscall The 12-th process's pid is 419 and command snapd
[ 2938.994359] --syscall The 13-th process's pid is 420 and command systemd-logind
[ 2938.994365] --syscall The 14-th process's pid is 439 and command cron
[ 2938.994372] --syscall The 15-th process's pid is 451 and command atd
[ 2938.994378] --syscall The 16-th process's pid is 456 and command agetty
[ 2938.994385] --syscall The 17-th process's pid is 461 and command sshd
[ 2938.994390] --syscall The 18-th process's pid is 491 and command unattended-upgr
[ 2938.994397] --syscall The 19-th process's pid is 501 and command polkitd
[ 2938.994413] --syscall results: pid=1200 name=login state=1 uid=0 nvcsw=31 nivcsw=33 num_children=1 num_siblings=19

推荐答案

以下是两个兄弟级子进程如何链接到其父级进程的子级列表中的说明:

Here is an illustration of how two sibling child processes are linked into their parent process's list of children:

     PARENT              CHILD 1             CHILD 2
     ======              =======             =======

                         task_struct         task_struct
                        +-------------+     +-------------+
                        |             |     |             |
     task_struct        ~             ~     ~             ~
    +-------------+     |             |     |             |
    |             |     |-------------|     |-------------|
    ~             ~     | children    |     | children    |
    |             |     |             |     |             |
. . |-------------| . . |-------------| . . |-------------| . .
    | children    |     | sibling     |     | sibling     |
X==>| prev | next |<===>| prev | next |<===>| prev | next |<==X
. . |-------------| . . |-------------| . . |-------------| . .
    | sibling     |     |             |     |             |
    |             |     ~             ~     ~             ~
    |-------------|     |             |     |             |
    |             |     +-------------+     +-------------+
    ~             ~
    |             |     'X's are joined together, making
    +-------------+     a doubly linked, circular list.

尽管 children 兄弟姐妹均为 struct list_head 类型,但 children 被用作实际列表头(链接到其子进程列表),而 sibling 被用作列表项.

Although children and sibling are both of type struct list_head, children is being used as an actual list head (linking to its list of child processes), whereas sibling is being used as a list entry.

父级的 children.next 链接指向子级1的 sibling 成员,子级1的 sibling.next 链接指向子级2的同级成员,子级2的 sibling.next 链接指向父级的 children 成员(列表头).同样,父级的 children.prev 链接指向子级2的 sibling 成员,子级2的 sibling.prev 链接指向子级1的 sibling成员,并且子级1的 sibling.prev 链接指向父级的 children 成员.

The parent's children.next link points to child 1's sibling member, child 1's sibling.next link points to child 2's sibling member, and child 2's sibling.next link points back to the parent's children member (the list head). Similarly, the parent's children.prev link points to child 2's sibling member, child 2's sibling.prev link points to child 1's sibling member, and child 1's sibling.prev link points back to the parent's children member.

list_for_each(pos,head)宏从 head-> next 开始访问列表中的每个节点 pos ,而 pos!= head .

The list_for_each(pos, head) macro visits each node pos in the list, starting at head->next, while pos != head.

通常, list_for_each(pos,head) head 参数应该是实际的列表头,但是宏无法区分列表头和列表之间的区别入口.它们都是相同的类型,并且所有节点都循环链接在一起.(整个列表由一个带有零个或多个列表项的列表头组成,这些列表项链接成一个圆圈.对于一个空列表,列表头仅链接回其自身.) list_for_each 宏将仅在双向链表,直到它回到起点为止.

Normally, the head parameter of list_for_each(pos, head) should be an actual list head, but the macro cannot tell the difference between a list head and a list entry. They are both the same type and all the nodes are linked together circularly. (The whole list consists of a list head with zero or more list entries linked in a circle. For an empty list, the list head just links back to itself.) The list_for_each macro will just iterate around the doubly linked list until it get back to where it started.

如果调用 list_for_each(pos,head)并用 head 指向父母的 children 成员,则 pos 将在第一次迭代中指向子1的 sibling 成员,并在第二次迭代中指向子2的 sibling 成员,并使用 pos终止循环指向父母的 children 成员.在循环内部, list_entry(pos,struct task_struct,sibling)会正确指向子进程的 struct task_struct 的开头.

If list_for_each(pos, head) was called with head pointing to the parent's children member, then pos would point to child 1's sibling member in the first iteration, and would point to child 2's sibling member in the second iteration, and would terminate the loop with pos pointing back to the parent's children member. Inside the loop, list_entry(pos, struct task_struct, sibling) would correctly point to the beginning of the struct task_struct for the child process.

让我们说孩子1是 current 进程.OP的代码使用 list_for_each(pos,head),其中 head 指向子级1的 sibling 成员.因此, pos 将在第一次迭代中指向子代2的 sibling 成员,并在第二次迭代中指向父代的 children 成员,并且将以 pos 指向子1的 sibling 成员终止循环.在循环内, list_entry(pos,struct task_struct,sibling)将在第一次迭代中正确指向子代2的 struct task_struct 的开头,但是 pos 会指向父对象的 struct task_struct 开头之前的某个位置.那就是问题出在OP的代码中.

Let us say that child 1 is the current process. OP's code is using list_for_each(pos, head) with head pointing to child 1's sibling member. Therefore, pos would point to child 2's sibling member in the first iteration, and would point to the parent's children member in the second iteration, and would terminate the loop with pos pointing back to child 1's sibling member. Inside the loop, list_entry(pos, struct task_struct, sibling) would correctly point to the beginning of child 2's struct task_struct in the first iteration, but pos would point to somewhere before the beginning of the parent's struct task_struct in the second iteration. That is the where the problem lies in OP's code.

这篇关于struct task_struct current的同级始终包含pid = 0的进程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆