虽然孩子返回0,但WEXITSTATUS返回1(在父母中)

时间:2016-02-04 09:59:29

标签: c linux fork

我使用以下代码来使用父/子运行一些命令:

int nStatus = 0;
int nRet = 0;
pid_t pid = -1;

char *envp[] =
    {
        "LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/tmp",
        0
    };



if(pnChildExitStatus == NULL || pcBuf == NULL)
{
    nRet = -EINVAL;
    goto returnHandler;
}
*pnChildExitStatus = 0;
pid = fork();
switch(pid)
{
    case -1:
        nRet = -errno;                           //can't fork
        break;
    case 0: //child
        nRet = execl("/bin/sh","sh","-c", pcBuf, envp,NULL);
        if (-1 == nRet) {
            nRet = -errno;
            goto returnHandler;
        }
        break;
    default: //parent
            /*After this call 'nStatus' is an encoded exit value. WIF macros will extract how it exited*/
            if( waitpid(pid, &nStatus, 0) < 0 ) 
            {
                nRet = -errno;
                *pnChildExitStatus = errno;
            }
            if(WIFEXITED(nStatus))
            {
                nRet = EXIT_SUCCESS;
                *pnChildExitStatus = WEXITSTATUS(nStatus);
            }
            goto returnHandler;
        break;
}
returnHandler:
    return nRet;
}

我的问题如下:

在某些情况下,Parent收到WEXITSTATUS(nStatus)!= 0,虽然我的子进程总是返回0(我用调试打印验证了它)。

有人可以就这怎么可能提供任何想法?

提前谢谢大家。

1 个答案:

答案 0 :(得分:3)

您对waitpid()的使用存在缺陷。

如果waitpid()被中断,它将返回-1,
nStatus中的值可能未定义, 因此if (WIFEXITED(nStatus))可能仍然是真实的 WEXITSTATUS(nStatus)可以是任何东西。

什么可以中断系统调用,(如waitpid)? 一个信号,如SIGCHLD,为一个退出的孩子。

正常模式类似于:

while ((wpid = waitpid(pid, &nStatus, 0)) != pid) {
    if (wpid == -1) {                    /* see below */
        if (errno == EINTR) continue;
        /* else handle the other error (pretty unlikely) */
        /* probably by returning something */
    }
}
if (wpid == -1) { /* error */ }    /* if you choose to `break' from the loop on error */
else { /* process exited */ }      /* you need to check the situation here */

if (wpid == -1)在这里有点多余,因为此循环中唯一的值wpid可能是-1,但此模式的其他变体不会约束wpid这么紧,所以它是针对改变的防御性编程。

if (errno == EINTR)类似,因为大多数(全部?)errno中只有3 waitpid是:EINTR,ECHILD(没有孩子)和EFAULT(你得到了第二个arg)错误)。但是,再次,防御性编程。