我正在尝试解决我在子进程运行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) );
答案 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)。