【问题标题】:Return status of execveexecve 的返回状态
【发布时间】:2013-03-19 10:42:24
【问题描述】:

我想将退出状态 0 从 execve 进程发送到启动它的进程。 因为在 Success execve 永远不会返回,所以在那之后我无法做任何事情。但我想如果 execve 运行成功。

【问题讨论】:

  • 这个链接可以帮助你stackoverflow.com/questions/13532391/…
  • OP 希望家长知道孩子的exec 已成功进行。 exec 失败可以通过多种方式报告给父进程(通过管道,或具有特殊的退出状态),但 exec 成功更难确认,因为成功 exec 定义意味着我们的进程不再运行。
  • @user4815162342:“...一个孩子的exec ...”是指创建孩子本身的exec或由exec完成的一个孩子(哪个回合是由父母 exec 创建的)?
  • @alk exec 不会创建孩子,fork 会。 “孩子的exec”是指“在子进程中执行的exec”。
  • @user4815162342:哦,是的,当然,脑部临时晕了……对不起。

标签: c process exec


【解决方案1】:

您可以使用FD_CLOEXEC 验证 exec 成功

  • 创建管道。

  • 分叉。

  • 在子进程中,关闭管道的读取端并在管道的写入端设置FD_CLOEXEC 标志。然后继续exec。如果exec成功,则管道会因为FD_CLOEXEC而自动关闭。如果exec 失败,则向管道写入一个字节并退出。

  • 在parent中,关闭管道的写端,从读端读取。如果读取到 0 个字节(EOF),则表示exec 成功。如果读取管道中的一个字节,则表示exec 失败。

在失败的情况下通过管道写入的数据可用于传输错误信息,例如exec之后的errno的值。

为简洁起见省略了错误检查,代码如下所示:

int pipe_fds[2];
pipe(pipe_fds);
if (!fork()) {
  close(pipe_fds[0]);
  fcntl(pipe_fds[1], F_SETFD, F_CLOEXEC);
  execve(...);
  write(pipe_fds[1], "", 1);
  _exit(1);
}
else {
  int n;
  char out;
  close(pipe_fds[1]);
  n = read(pipe_fds[0], &out, 1);
  if (n == 0)
    printf("exec successful\n");
  else
    printf("exec failed\n");
  close(pipe_fds[0]);
}

请注意,如果其他线程可以并行执行自己的进程,则此技术可能是不安全的。问题是在创建管道和设置 close-on-exec 标志之间存在延迟。如果在该关键窗口期间不相关的线程分叉和执行,则子线程将继承 pipe_fds[1] 并且不会关闭它,从而导致父线程挂起。这可以使用特定于 Linux 的 pipe2 调用来解决,该调用允许使用 close-on-exec 标志集自动创建管道。

【讨论】:

  • exec 失败时,是否保证 SIGCHLD 信号将在 EOF 通知之前传递,因为孩子死亡关闭了管道?我喜欢这项技术背后的想法;我只是想知道是否存在竞争条件。
  • @JonathanLeffler 我不认为有任何这样的保证,但它不应该是必要的。如果exec 失败,很容易通过管道发送一些数据来消除歧义。
  • @JonathanLeffler 我现在编辑了答案,不再依赖SIGCHLD
  • @user4815162342 如果这段代码从两个线程执行会发生什么。我猜 CLOEXEC 会在第一个成功的 exec 上关闭文件描述符。如果那个 exec 从另一个线程发生,它看起来就像 exec 成功了。
  • @user877329 我不确定这是否真的是一个问题。从另一个线程发生的 exec 必须首先分叉,并且它只会关闭其文件描述符视图。第一个线程的父级只会在 两个 子级都关闭管道后观察到 EOF,所以一切都会正常工作。
【解决方案2】:

等待fork()启动的进程完成,可以使用wait()

/* parent */
int status;
while (wait(&status) != uproc.pid) {
    printf("waiting for child to exit");
    }

并基于此question

孩子的退出状态由wait函数提供,在status变量中。

您可以使用WEXITSTATUS 宏获得退出状态,但前提是程序正常退出(即调用exit 或从其main 函数返回):

if (WIFEXITED(status))
    printf("Child exit status: %d\n", WEXITSTATUS(status));
else
    printf("Child exited abnormally\n");

【讨论】:

  • 这不会验证exec 成功,只会验证程序以成功状态退出。当执行一个长时间运行的程序时,这会有所作为。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-09
  • 2020-11-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多