使用setpgid将父级设置为子进程组失败

时间:2017-11-27 22:35:56

标签: c linux process fork

我试图将进程的pgrp更改为子进程的pgrp,以便我可以在父进程上setsid。唯一的问题是我不断收到EPERM错误代码。根据htop,两个进程都有相同的会话组。

我基于此blog post,所以我可以更改定向到哪个终端输出。

void sig_exit(int signum)
{
    _Exit(0);
}

pid_t change_process_group()
{
    pid_t child_pid;
    if ((child_pid = fork()) < 0)
    {
        perror("fork failed while attaching to term");
        exit(1);
    }
    if (child_pid == 0)
    {
        pid_t parent = getppid();
        setpgid(0, getpid());

        signal(SIGUSR1, sig_exit); // wait till parent tells child to exit

        //sleep(5);
        //kill(parent, SIGUSR2);
        pause();
        printf("Shouldn't reach this\n");
    }

    //sleep(5);
    //signal(SIGUSR2, sig_wait);
    //pause();
    int parent_pid = getpid();
    int code = setpgid(parent_pid, child_pid); // need child process group
    printf("%s\n", strerror(errno));
    setsid();

    return  child_pid;
}

main()
{
   pid_t child = change_process_group();

   kill(child, SIGUSR1);
}

注释掉的行是我认为流程可能没有以正确的顺序执行,但那些似乎没有解决问题。 我如何正确使用setpgid将父进程的pgrp更改为子进程?

1 个答案:

答案 0 :(得分:0)

这是竞争条件,如果您取消注释父级中的sleep(5)行,它就会起作用。致电setpgid(parent_pid, child_pid)时,child_pid 流程组必须存在。仅存在具有PID child_pid的进程是不够的:setpgid需要现有进程组,除非进程将自己置于其自己的组中。如果父级中的setpgid(parent_pid, child_pid)在子级中setpgid(0, getpid())之后运行,则可以正常运行。

睡觉既低效又脆弱,所以父母不应该等待来自孩子的通知。信号很脆弱,因为没有太多不同的信号,它们可能来自任何地方。在相关流程之间进行通信的好方法是管道。由于此处所需的只是一次性通知,因此您可以设置管道并在父级中读取它(写入端在父级中关闭)。父级将等待,直到孩子写入管道或关闭它。在孩子中,当你完成准备工作时,只需关闭管道的写入端。父母的read电话(或select如果你需要同时做其他事情)将会返回。

概念证明代码:

pid_t change_process_group()
{
    pid_t child_pid;
    int child_ready_pipe[2];
    if (pipe(child_ready_pipe) < 0)
    {
        perror("pipe");
        exit(1);
    }
    if ((child_pid = fork()) < 0)
    {
        perror("fork failed while attaching to term");
        exit(1);
    }
    if (child_pid == 0)
    {
        close(child_ready_pipe[0]);
        sleep(1); // mimic slow start of the child
        if (setpgid(0, 0))
            perror("child setpgid to create group");
        close(child_ready_pipe[1]);

        signal(SIGUSR1, sig_exit); // wait till parent tells child to exit
        pause();
        printf("Shouldn't reach this\n");
    }

    close(child_ready_pipe[1]);
    int parent_pid = getpid();
    char ignored;
    read(child_ready_pipe[0], &ignored, 1);
    close(child_ready_pipe[0]);
    if (setpgid(parent_pid, child_pid) < 0) // need child process group
        perror("parent setpgid");
    if (setsid() < 0)
        perror("parent setsid");

    return  child_pid;
}