fork + wait gets EINTR on OSX

折月煮酒 提交于 2020-01-03 18:50:53

问题


I fail at fork 101. I expect this to fork a child process, and output both child and parent printfs:

pid_t fpid;

if ((fpid = fork()) < 0)
{
    printf("fork: %s\n", strerror(errno));
    exit(-1);
}

if (0 == fpid) // child
{
    printf("\nI am the child\n");
}
else
{
    printf("\nI am the parent\n");
    pid_t wpid;
    while ((wpid = waitpid(WAIT_ANY, NULL, 0)))
    {
        if (errno == ECHILD)
            break;
        else if (wpid < 0)
            printf("wait: %s\n", strerror(errno));
    }
}

Instead, I get this output:

I am the parent

wait: Interrupted system call

So my question is: why doesn't the child get a chance to live and run? Won't someone please think of the children! Also, where does the EINTR come from? Obviously, this is somehow related to my first question.

Furthermore, when I run that code in a standalone program, it works correctly, but not when inside a larger program of mine; what could the larger program do to upset waitpid?

FWIW this is on OSX 10.9.


回答1:


On OSX, it's not legal to do much on the child side of a fork before/without execing. See the caveat at the bottom of the fork man page. The list of safe functions is on the sigaction(2) man page. printf() is not among them.

Also, stdout is likely buffered. The results of the printf() may not be being flushed. It would be flushed if you called exit(), but that's also not legal on the child side of a fork. (It's appropriate to use _exit() but that doesn't flush open streams.) As it is, you don't appear to be exiting your child process, which means flow of execution continues to the caller of the code you've shown, presumably returning to the rest of your program. It may be getting stuck there because of the limitations on the child side of a fork.

You may have more luck if you do something like this in the child:

const char msg[] = "\nI am the child\n";
write(STDOUT_FILENO, msg, sizeof(msg) - 1);
_exit(0);

Finally, I think you should pass fpid rather than WAIT_ANY to waitpid(). You have a specific child process you want to wait for. In the context of a larger program, you don't want to steal the notification of the termination of a child spawned by some other subcomponent. And you always need to loop around interruptible syscalls until they return something other than EINTR.




回答2:


Only check errno if a failure was indicated, for example by a system call returning -1.

The code should look like this:

pid_t fpid;

if ((fpid = fork()) < 0)
{
    printf("fork: %s\n", strerror(errno));
    exit(-1);
}

if (0 == fpid) // child
{
    printf("\nI am the child\n");
}
else
{
    printf("\nI am the parent\n");

    pid_t wpid;
    while ((wpid = waitpid(WAIT_ANY, NULL, 0)))
    {
        if (-1 == wpid)
        {
            perror("waitpid() failed");
        }
        else if (wpid == fpid)
        {
            /* My child ended, so stop waiting for it. */
            break;
        }
    }
}


来源:https://stackoverflow.com/questions/20555550/fork-wait-gets-eintr-on-osx

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!