首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在设置子收割器时,有没有一些简短的使用prctl()的例子?

在设置子收割器时,有没有一些简短的使用prctl()的例子?
EN

Stack Overflow用户
提问于 2019-07-03 00:00:54
回答 2查看 495关注 0票数 3

我目前正在尝试学习如何使用Linux prctl(PR_SET_CHILD_SUBREAPER)prctl(PR_GET_CHILD_SUBREAPER)

不幸的是,当我使用这些函数时,我似乎不知道发生了什么。有人能帮我找出我理解中的一个疏漏吗?

我已经将主进程设置为subreaper。然后,我尝试使用fork()创建子进程,并再次尝试创建子进程。然后我杀死了子进程,看看孙子进程发生了什么,但我无法检查它。

代码语言:javascript
复制
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;
}

输出:

代码语言:javascript
复制
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部分)在运行时没有被调用。原因是什么?

EN

回答 2

Stack Overflow用户

发布于 2021-04-06 13:57:03

下面是一个演示PR_SET_CHILD_SUBREAPER工作原理的小程序

代码语言:javascript
复制
#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;
}

输出:

代码语言:javascript
复制
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

观察:

通过设置PR_SET_CHILD_SUBREAPER,父进程(4002)已成为子收割器

父进程(4002)已经派生并创建子进程(4003)

子进程(4003)已经派生并创建了孙进程(4004)

子进程(4003)尝试使用PR_GET_CHILD_SUBREAPER并接收0。因为prctl()只有一个实例,它不会保留在派生的进程中。Does the CHILD_SUBREAPER bit persist across fork()?

子进程(4003)终止使孙进程(4004)成为孤立进程

由于父进程(4002)被设置为SUBREAPER孙进程(4004)成为父进程(4002)的子进程,并且孙进程(4004)的退出状态被父进程(4002)接收,子进程已经终止

票数 1
EN

Stack Overflow用户

发布于 2021-07-12 01:09:51

这里有一个更长的PR_SET_CHILD_SUBREAPER工作原理的例子(基于Sunil Kumar的简短回答):

代码语言:javascript
复制
#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;
}

编译和运行:

代码语言:javascript
复制
griscom@nob:~/tmp$ cc -Wall subreaper_test.c -o subreaper_test
griscom@nob:~/tmp$ echo "My PID is $$"
My PID is 1001
griscom@nob:~/tmp$ ./subreaper_test 
PARENT(1002): parent is 1001
PARENT(1002): ===== Run test with CHILD_SUBREAPER set to 1 =====
PARENT(1002): forked child 1003
PARENT(1002): waiting for descendents to exit
  CHILD(1003): parent is 1002
  CHILD(1003): forked grandchild 1004
    GRANDCHILD(1004): before sleep, parent is 1003
  CHILD(1003): exiting
PARENT(1002): pid 1003 exited
    GRANDCHILD(1004): after sleep, parent is 1002
    GRANDCHILD(1004): exiting
PARENT(1002): pid 1004 exited
PARENT(1002): no more descendants
PARENT(1002): ===== Run test with CHILD_SUBREAPER set to 0 =====
PARENT(1002): forked child 1005
PARENT(1002): waiting for descendents to exit
  CHILD(1005): parent is 1002
  CHILD(1005): forked grandchild 1006
GRANDCHILD(1006): before sleep, parent is 1005
  CHILD(1005): exiting
PARENT(1002): pid 1005 exited
PARENT(1002): no more descendants
PARENT(1002): ===== Exiting =====
griscom@nob:~/tmp$     GRANDCHILD(1006): after sleep, parent is 1
    GRANDCHILD(1006): exiting

顺序:

  • 父代将其CHILD_SUBREAPER设置为1
  • 父代派生一个子代,子代作为父代
  • 子代退出,留下孙子作为孤儿,父代作为父代
  • 孙辈退出,并通知父代其最后一个子代已退出
  • 父代将其CHILD_SUBREAPER设置为0
  • 父代派生一个子代,以子代为父代
  • 子代退出,留下孙子作为孤儿进程1( init进程)作为父代
  • 父代看到其最后一个子代已退出和本身退出
  • 在主程序返回

之后,孙子进程退出。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56856275

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档