posix_spawn() :使用 posix_spawn() 时的错误处理问题

Posted

技术标签:

【中文标题】posix_spawn() :使用 posix_spawn() 时的错误处理问题【英文标题】:posix_spawn() : Problem with error handling when using posix_spawn() 【发布时间】:2020-10-28 11:00:36 【问题描述】:

我正在尝试使用 posix_spawn() 创建一个新的子进程。 子进程启动后,调用者进程应该继续运行。

TLDR:为什么即使子可执行文件的路径无效(不存在),posix_spawn() 也会返回 0(成功)?在这种情况下以及 posix_spawn 实际失败但返回成功的任何其他情况下,如何正确检测错误?

我尝试了以下代码。

/* The CALLER process*/
int main(int argc, char *argv) 
    int status, pid;

    printf("CALLER - Start\n");

    char *args[] = "/home/<user>/child_exec", NULL;

    status = posix_spawn(&pid, args[0], NULL, NULL, args, environ);
    printf("Status: %d; PID: %d\n", status, pid);

    printf("CALLER - End\n");

    return 0;

/* The CHILD process */
int main() 
    printf("From CHILD\n");
    return 0;

当我使用正确子可执行文件的路径运行调用程序时,它会按预期运行。 posix_spawn 的状态为 0,子进程的字符串被打印出来。

CALLER - Start
Status: 0; PID: 5110
CALLER - End
From CHILD

现在,当我使用无效的子可执行路径(例如 /home/user/child_exec123)运行同一程序时,即使子进程尚未执行,它仍然返回状态 0。

CALLER - Start
Status: 0; PID: 5251
CALLER - End

对于这种子路径不存在的情况,我可以在调用 posix_spawn() 之前检查文件是否存在。 但是,如果还有其他类似的错误,其中 posix_spawn() 实际失败但返回 0 怎么办?我如何发现是否有错误?

【问题讨论】:

奇怪的是 IBM 的 AIX 中的实现是理智的——它会在例如以下情况下返回失败。可执行文件不存在。我非常希望(对于 LINUX)最终不再需要克隆调用进程只是为了立即浪费结果。但出于某种我无法理解的原因,这仍然是 2021 年的标准做法! 【参考方案1】:

来自手册页(特别是第二段):

RETURN VALUE
       Upon successful completion, posix_spawn() and posix_spawnp() place  the
       PID  of  the  child process in pid, and return 0.  If there is an error
       before or during the fork(2), then no child is created, the contents of
       *pid are unspecified, and these functions return an error number as de‐
       scribed below.

       Even when these functions return a success status,  the  child  process
       may still fail for a plethora of reasons related to its pre-exec() ini‐
       tialization.  In addition, the exec(3)  may  fail.   In  all  of  these
       cases, the child process will exit with the exit value of 127.

您需要使用wait* 函数之一来检查您的子进程的结果。无论如何,这将是一个好主意,否则你就会有一个僵尸。

【讨论】:

但是由于 wait* 函数正在阻塞调用,我怎样才能在子进程运行时继续运行调用者进程?我不想等待孩子完成,因为孩子可能需要很长时间才能完成。 waitpid 接受选项。你要的是WNOHANG 谢谢。如果 posix_spawn() 返回的状态为 0,我只是尝试写这个:rc = waitpid(pid, &amp;status, WNOHANG);。但是即使子文件路径错误,waitpid 也会返回 0。如果我在调用 waitpid 之前睡了 2 秒钟,它会给出正确的错误。如何摆脱睡眠并仍然能够捕获错误? 您受调度程序的支配,因为无法保证您的子进程何时会尝试调用execve。我不知道您可以等待的任何事件会告诉您进程已成功执行(SIGCHLD 会告诉您它已停止,但出于任何原因已停止)。 奇怪的是,IBM AIX 中的实现是正常的——它返回一个失败,例如可执行文件不存在。我非常希望(对于 LINUX)最终不再需要克隆调用进程并立即浪费结果。但出于某种我无法理解的原因,这仍然是 2021 年的标准做法!【参考方案2】:

posix_spawn 在子进程启动之前返回,将检测到不正确的路径。因此,子进程启动期间的任何错误,您只能通过其退出值来检查。

如documentation中所述:

返回值

   Upon successful completion, posix_spawn() and posix_spawnp() place
   the PID of the child process in pid, and return 0.  If there is an
   error during the fork() step, then no child is created, the contents
   of *pid are unspecified, and these functions return an error number
   as described below.

   Even when these functions return a success status, the child process
   may still fail for a plethora of reasons related to its pre-exec()
   initialization.  In addition, the exec(3) may fail.  In all of these
   cases, the child process will exit with the exit value of 127. 

错误

   The posix_spawn() and posix_spawnp() functions fail only in the case
   where the underlying fork(2), vfork(2) or clone(2) call fails;  in
   these cases, these functions return an error number, which will be
   one of the errors described for fork(2), vfork(2) or clone(2).

   In addition, these functions fail if:

   ENOSYS Function not supported on this system.

【讨论】:

以上是关于posix_spawn() :使用 posix_spawn() 时的错误处理问题的主要内容,如果未能解决你的问题,请参考以下文章

解决 Sourcetree 报错 Couldn't posix_spawn: error 2 问题

开始过程中的Kauth事件。 - 预防能力

测试使用

第一篇 用于测试使用

在使用加载数据流步骤的猪中,使用(使用 PigStorage)和不使用它有啥区别?

今目标使用教程 今目标任务使用篇