来自孩子的C信号父进程

时间:2010-04-27 07:42:27

标签: c unix process

我正在尝试解决我在子进程运行execvp()时遇到的问题,并且需要让父进程知道它是否返回。因此,在execvp()返回之后(因为出现了错误),如何告诉父节点这个特定事件已经发生,以便它可以处理它。

有一种方法可以通过我正在使用的管道写入一串文本,然后从父级读取它......但它似乎有点草率。还有更好的方法吗?

谢谢!

编辑:这是我正在尝试的一些代码,我似乎无法将读取返回。

int errorPipe[2];
signal( SIGPIPE, SIG_IGN );

int oldflags = fcntl (errorPipe[0], F_GETFD, 0);
oldflags |= FD_CLOEXEC;
fcntl (errorPipe[0], F_SETFD, oldflags);
oldflags = fcntl (errorPipe[1], F_GETFD, 0);
oldflags |= FD_CLOEXEC;
fcntl (errorPipe[1], F_SETFD, oldflags);

pipe( errorPipe );

// in the child..
char *error_message = "exec failed";
write( errorPipe[1], error_message, strlen(error_message)+1 );
exit(-1);

// in the parent
printf("read gives: %d\n", read(errorPipe[0], error_read, MAX_LINE_LENGTH) );

3 个答案:

答案 0 :(得分:4)

最简单的方法是设置FD_CLOEXEC标志的管道,因为您可以像失败一样轻松地检测到成功的exec。如果发生故障,我会通过管道将错误消息写回父级,但您可以编写状态代码或其他任何有意义的代码。 (绝对写某些东西;没有任何写入必须是成功启动其他可执行文件的标志。)

[编辑]:如何利用这个:

如果父母需要等到它知道孩子是否成功运行execve()(unlying syscall),那么它应该在管道上执行阻塞read()。结果为零表示成功。 (确保您已忽略SIGPIPE。)

如果父级有某种基于非阻塞IO和select()(或poll()kqueue()或...)的事件处理框架,那么等待管道变为可读之前试图阅读消息(如果孩子正确地完成了execve(),那将是零长度。)

答案 1 :(得分:2)

execvp()永远不会返回,除非它甚至无法启动可执行文件。如果它可以启动可执行文件,它将不会返回,无论可执行文件做什么(即无论可执行文件是否成功执行其任务)。

您的父进程将收到SIGCHLD信号,您可以为其安装信号处理程序。

或者你可以wait(2)进行子进程。

int child_pid = fork();
if (child_pid == 0) {
    execvp("/path/to/executable", ...);
    exit(123); /* this happens only if execvp() fails to invoke executable */
}

/* ... */

int status = 0;
int exit_pid = waitpid(-1, &status, WNOHANG);
if (exit_pid == child_pid && WIFEXITED(status)) {
    if (WEXITSTATUS(status) == 0) {
        /* child process exited fine */
    } else if (WEXITSTATUS(status) == 123)
        /* execvp() itself failed */
    } else {
        /* executed child process failed */
    }
}

答案 2 :(得分:0)

缓存要检查父级状态的(子)进程的pid。 在父级中添加SIGCHLD的处理程序。在子调用exit中,您选择一些状态值表示execvp失败。收到父母的信号后,您现在有2个选项 a)使用pid为-1调用waitpid(即等待任何子进程),检查返回值,如果匹配缓存的pid,则使用WEXITSTATUS之类的宏检查状态。
b)使用缓存的pid调用waitpid,然后在返回时检查退出状态。

为了使这个功能强大,您应该在通过WEXITSTATUS检查退出状态之前调用WIFEXITED(status)。如果孩子正常终止,即通过调用exit或_exit而不是由于seg故障,未处理信号等,则WIFEXITED返回true。 另见man wait(2)。