Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing posix_spawn on Linux

Tags:

c

linux

posix

I am curious to see if it would be possible to implement posix_spawn in Linux using a combination of vfork+exec. In a very simplified way (leaving out most optional arguments) this could look more or less like this:

int my_posix_spawn(pid_t *ppid, char **argv, char **env)
{
    pid_t pid;

    pid = vfork();
    if (pid == -1)
        return errno;

    if (pid == 0)
    {
        /* Child */
        execve(argv[0], argv, env);

        /* If we got here, execve failed. How to communicate this to
         * the parent? */
        _exit(-1);
    }

    /* Parent */
    if (ppid != NULL)
        *ppid = pid;

    return 0;
}

However I am wondering how to cope with the case where vfork succeeds (so the child process is created) but the exec call fails. There seems to be no way to communicate this to the parent, which would only see that it could apparently create a child process successfully (as it would get a valid pid back)

Any ideas?

like image 909
Grodriguez Avatar asked Aug 14 '14 14:08

Grodriguez


1 Answers

As others have noted in the comments, posix_spawn is permitted to create a child process that immediately dies to due to exec failure or other post-fork failures; the calling application needs to be prepared for this. But of course it's preferable not to do so.

The general procedure for communicating exec failure to the parent is described in an answer I wrote on this question: What can cause exec to fail? What happens next?.

Unfortunately, however, some of the operations you need to perform are not legal after vfork due to its nasty returns-twice semantics. I've covered this topic in the past in an article on ewontfix.com. The solution for making a posix_spawn that avoids duplicating the VM seems to be using clone with CLONE_VM (and possibly CLONE_VFORK) to get a new process that shares memory but doesn't run on the same stack. However, this still requires a lot of care to avoid making any calls to libc functions that might modify memory used by the parent. My current implementation is here:

http://git.musl-libc.org/cgit/musl/tree/src/process/posix_spawn.c?id=v1.1.4

and as you can see it's rather complicated. Reading the git history may be informative regarding some of the design decisions that were made.

like image 102
R.. GitHub STOP HELPING ICE Avatar answered Sep 23 '22 14:09

R.. GitHub STOP HELPING ICE