繁体   English   中英

如何同时等待文件描述符和子 state 更改?

[英]How can I wait for both a file-descriptor and child state change simultanously?

在 Linux 中,可以使用selectpollepoll等待任何 FD。 也可以使用waitwaitpidwaitid 但是,我想不出一种方法来组合这些操作,即阻止调用进程,直到某些 FD 准备好或进程更改 state。

我可以通过反复调用非阻塞epoll然后waitid来使用轮询,但这很浪费。

可以为子进程创建一个pidfd (被epoll接受),但pidfd仅支持等待子终止,而我希望等待任何 state 更改(特别是对于 ptrace 停止)。

这在 Linux 中是不可能的吗?

您可以使用 signalfd() 等待任何子状态更改并进行虚拟读取,然后使用 waitpid() 获取实际状态:

sigset_t mask, old_set;
sigemptyset(&mask);
sigaddset(&mask, SIGCHLD);
sigprocmask(SIG_BLOCK, &mask, &old_set);

int sigfd = signalfd(-1, &mask, SFD_CLOEXEC);
if (sigfd == -1) {
    perror("signalfd");
    return 1;
}

for (int i = 0; i < 10; ++i) {
    pid_t pid = fork();
    if (pid == -1) {
        perror("fork");
    }
    if (pid == 0) {
        // Child process: restore blocked signals before exec() etc
        sigprocmask(SIG_SETMASK, &old_set, NULL);
        sleep(i % 3);
        switch (i % 3) {
            case 0:
                raise(SIGSTOP);
                break;
            case 1:
                raise(SIGABRT);
                break;
        }
        exit(i);
    }
    printf("Spawned child %i with pid %u\n", i, pid);
}

for (;;) {
    struct pollfd fds[] = {
        { .fd = STDIN_FILENO, .events = POLL_IN },
        { .fd = sigfd,        .events = POLL_IN }
    };
    if (poll(fds, sizeof(fds)/sizeof(*fds), -1) == -1) {
        perror("poll");
        break;
    }

    if (fds[0].revents & POLL_IN) {
        char buf[4096];
        int ret = read(STDIN_FILENO, buf, sizeof(buf));
        printf("Data from stdin: ");
        fflush(stdout);
        write(STDOUT_FILENO, buf, ret);
    }

    if (fds[1].revents & POLL_IN)
    {
        struct signalfd_siginfo fdsi;
        read(sigfd, &fdsi, sizeof(fdsi));

        for (;;) {
            int status;
            pid_t pid = waitpid(-1, &status, WNOHANG | WUNTRACED | WCONTINUED);
            if (pid == -1) {
                if (errno != ECHILD) {
                    perror("waitpid");
                }
                break;
            }
            if (pid == 0) {
                break;
            }

            printf("Child %u ", pid);
            if (WIFEXITED(status)) {
                printf("exited with status %i\n", WEXITSTATUS(status));
            } else if (WIFSIGNALED(status)) {
                printf("terminated by signal %i\n", WTERMSIG(status));
            } else if (WIFSTOPPED(status)) {
                printf("stopped by signal %i\n", WSTOPSIG(status));
            } else if (WIFCONTINUED(status)) {
                printf("continued\n");
            } else {
                printf("status unknown\n");
            }
        }
    }
}

close(sigfd);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM