我目前正在尝试学习如何使用Linux prctl(PR_SET_CHILD_SUBREAPER)
和prctl(PR_GET_CHILD_SUBREAPER)
。
不幸的是,当我使用这些功能时,我似乎并不了解发生了什么。有人可以帮助我发现我的理解上的失误吗?
我已将主要流程设置为收割者。然后,我尝试使用fork()
创建一个子进程,然后再次使用它来获得一个子进程。然后我杀死了子进程,以查看孙子发生了什么,但我无法检查。
int main(void) {
int p = fork();
prctl(PR_SET_CHILD_SUBREAPER, 1);
if(p < 0)
return EXIT_FAILURE;
if(p > 0){
//Main process
printf("I am the MainProcess, My PID: %d and PPID: %d\n", getpid(), getppid());
}
else{
printf("I am the Child, My PID: %d and PPID: %d\n", getpid(), getppid());
int p2 = fork();
if(p2 < 0)
return EXIT_FAILURE;
if(p2 > 0){
//still Child process
}
else{
int *reaper = NULL;
prctl(PR_GET_CHILD_SUBREAPER, reaper);
printf("I am the Grandchild, My PID: %d and PPID: %d\n", getpid(), getppid());
printf("Reaper ID: %d\n", *reaper);
kill(getppid(), SIGKILL);
printf("I am the Grandchild, My PID: %d and PPID: %d\n", getpid(), getppid());
prctl(PR_GET_CHILD_SUBREAPER, reaper);
printf("Reaper ID: %d\n", *reaper);
}
return EXIT_SUCCESS;
}
return EXIT_SUCCESS;
}
输出:
I am the MainProcess, My PID: 9088 and PPID: 23010
I am the Child, My PID: 9089 and PPID: 9088
I am the Grandchild, My PID: 9090 and PPID: 9089
令我惊讶的是,在运行时未调用某些printf()
事件(在代码的granchild部分中)。是什么原因?
答案 0 :(得分:0)
这是一个关于 PR_SET_CHILD_SUBREAPER 工作原理的小程序
#include <stdio.h>
#include <sys/types.h>
#include <sys/prctl.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
int main(void)
{
int *status;
int i=0;
prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0);
perror("PARENT:Set");
printf("PARENT: %d : my dad : %d\n", getpid(), getppid());
if(fork() != 0)
{
while(1)
{
wait(status);
if(++i == 2)
{
break;
}
}
int p = 1;
prctl(PR_GET_CHILD_SUBREAPER, &p);
printf("PARENT : %d\n",p);
printf("PARENT Exiting\n");
}
else
{
printf("Before CHILD: %d: my dad %d\n",getpid(), getppid());
if(fork() == 0)
{
int p = 1;
printf("Before grandchild: %d: my dad %d\n",getpid(), getppid());
sleep(2);
printf("After grandchild: %d: my dad %d\n",getpid(), getppid());
prctl(PR_GET_CHILD_SUBREAPER, &p);
printf("After grandchild : %d\n",p);
printf("Grandchild Exiting\n");
exit(0);
}
else
{
int p = 1;
prctl(PR_GET_CHILD_SUBREAPER, &p);
printf("After CHILD : %d\n",p);
printf("After CHILD: %d: my dad %d\n",getpid(), getppid());
printf("CHILD Exiting\n");
exit(1);
}
}
return 0;
}
输出:
PARENT:Set: Success
PARENT: 4002 : my dad : 2222
Before CHILD: 4003: my dad 4002
After CHILD : 0
After CHILD: 4003: my dad 4002
CHILD Exiting
Before grandchild: 4004: my dad 4003
After grandchild: 4004: my dad 4002
After grandchild : 0
Grandchild Exiting
PARENT : 1
PARENT Exiting
观察:
PARENT 进程(4002)通过设置 PR_SET_CHILD_SUBREAPER 成为子收割者
PARENT 进程(4002) 已经分叉并创建了 CHILD 进程(4003)
CHILD 进程(4003)已经分叉并创建了孙子进程(4004)
CHILD 进程(4003) 尝试使用 PR_GET_CHILD_SUBREAPER 并收到 0。因为 prctl() 只有实例,它不会保留在分叉进程中。 Does the CHILD_SUBREAPER bit persist across fork()?
子进程(4003)终止使孙子进程(4004)成为孤儿进程
因为,PARENT进程(4002)已被设置为SUBREAPER孙子进程(4004)成为PARENT进程(4002)的子进程并且孙子进程(4004)的退出状态被PARENT进程(4002)接收,因为子进程已终止
答案 1 :(得分:0)
以下是 PR_SET_CHILD_SUBREAPER 工作原理的更长示例(基于 Sunil Kumar 的简短回答):
{
"status": "success",
"message": "successfully login",
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NywiaXNMb2dnZWRJbiI6dHJ1ZSwidGVuYW50SWQiOjEyLCJpYXQiOjE2MjU5OTE5MTAsImV4cCI6MTYyNjA3ODMxMH0.I0z9OIDnQS-MI1ya6usqycoryZ1TBwj3K52BRfrpMuY",
"user": {
"user_id": 7,
"email": "jd@gmail.com",
"first_name": "John",
"last_name": "Doe",
"phone": "",
"date_of_birth": "2015-08-06T00:00:00.000Z",
},
"accountData": {
"name": "Amazon",
"account_id": 1
},
"permissions": [
"ViewAllEmployee",
"AddNewEmployee"
]
}
}
编译运行:
#include <stdio.h>
#include <sys/prctl.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
// Make a grandchild process, which sleep(2)s and then exits
int doGrandchild(void) {
int pid;
if ((pid = fork()) != 0) {
return pid;
}
printf(" GRANDCHILD(%d): before sleep, parent is %d\n", getpid(), getppid());
sleep(2); // Wait for CHILD to report and exit
printf(" GRANDCHILD(%d): after sleep, parent is %d\n", getpid(), getppid());
printf(" GRANDCHILD(%d): exiting\n", getpid());
exit(0);
// Will never return
}
// Make a child process, which makes a grandchild process, sleep(1)s, and then exits
int doChild(void) {
int pid;
if ((pid = fork()) != 0) {
return pid;
}
sleep(1); // Wait for PARENT to report fork
printf(" CHILD(%d): parent is %d\n", getpid(), getppid());
pid = doGrandchild();
printf(" CHILD(%d): forked grandchild %d\n", getpid(), pid);
sleep(1); // Wait for GRANDCHILD to report
printf(" CHILD(%d): exiting\n", getpid());
exit(0); // Exit before GRANDCHILD exits
// Will never return
}
// Wait for all child descendents to exit
void waitDescendents(void) {
printf("PARENT(%d): waiting for descendents to exit\n", getpid());
while(1) {
// Wait for any descendant process to exit
int pid = wait(NULL);
if(pid == -1) {
printf("PARENT(%d): no more descendants\n", getpid());
break;
} else {
printf("PARENT(%d): pid %d exited\n", getpid(), pid);
}
}
}
// Run the test
int main(void) {
int pid;
printf("PARENT(%d): parent is %d\n", getpid(), getppid());
prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0);
printf("PARENT(%d): ===== Run test with CHILD_SUBREAPER set to 1 =====\n", getpid());
pid = doChild();
printf("PARENT(%d): forked child %d\n", getpid(), pid);
waitDescendents();
prctl(PR_SET_CHILD_SUBREAPER, 0, 0, 0, 0);
printf("PARENT(%d): ===== Run test with CHILD_SUBREAPER set to 0 =====\n", getpid());
pid = doChild();
printf("PARENT(%d): forked child %d\n", getpid(), pid);
waitDescendents();
printf("PARENT(%d): ===== Exiting =====\n", getpid());
return 0;
}
顺序: