2
votes

I'm looking to implement a function similar to CreateProcess but on Linux. I did a lot of research and found the "Fork off and die" approach which uses a double fork to run the child under init. That is, allow the child to operate independent of the parent.

Because the parent needs to return information about the newly created child process (i.e. pid, name, etc.) I need to know if I'm running into a race condition in my code. Currently, I fork and retrieve the second fork's pid via pipes then wait for the first fork to exit.

int child = 0;
int fd[2] = { 0, 0 };

if (pipe (fd) != 0)
    return Process();

int pid = fork();
if (pid < 0)
    return Process();

if (pid == 0) // Child
{
    if (setsid() != -1)
    {
        child = fork();
        if (child == 0)
        {
            umask (0); // Reset umask
            close (0); // Close stdin
            close (1); // Close stdout
            close (2); // Close stderr

            execvp ( ... );
            _exit (0);
        }

        // Do I need waitpid (child) here?
    }

    // Write the child PID using the pipe
    write (fd[1], &child, sizeof (child));
    _exit (0);
}

else // Parent
{
    // Read the child PID using the pipe
    read (fd[0], &child, sizeof (child));

    // Remove zombie process
    waitpid (pid, nullptr, 0);

    // Child must finish exec by this point

    return Process (child);
        // Also gets name
}

Questions:

  • Do I need a second waitpid to wait for the child to finish the exec?
  • Does waitpid return upon a call to exec?
  • Does waitpid return even if exit or exec were called before waitpid?
2
Why do you want to double-fork? Double-forking is done when the new process should not be a child of the original process, quite the opposite of what you want to do. - fuz
That's exactly what I want to do. I want to create a process that has nothing to do with the parent process. So even when the parent dies the child continues. I return the child's PID so that I can debug it later if I wanted to. This is what the CreateProcess function does on Windows and I need to replicate it on Linux. - Dave
In the double-forking approach, the new process is not a child of the original process. You can't have cake and eat it, too, unless you hack something in a horrible fashion. - fuz
Why do you want to create a process that is not the child of your original process anyway? - fuz
I know it's not a child. I don't want it to be a child I want it to be independent, running off Init. I'm launching a daemon here. This new process will be just like any other process, I will be able to "attach" to it like I can any remote process. This is a remote process analysis library I'm building here. - Dave

2 Answers

0
votes

You do not need to waitpid() on the second child. When a process's parent dies, the child will be adopted by the init process, so there will not be a zombie process.

waitpid() only returns after the child it waits on exits. A call to execvp() in the child means the waiter waits until the program that was executed dies, since that is when the child would die.

waitpid() will get the exit status of the process. It doesn't matter when the process actually exited.

0
votes

(A little clarification: what you're calling child, is actually your grandchild. It's the child of the process that just forked off and died.)

Do I need a second waitpid to wait for the child to finish the exec?

You can't. It's your grandchild and you can only wait on your direct children. Additionally, because your grandchild's parent has died, your grandchild has now been reparented to init (so it's actually your ex-grandchild).

Does waitpid return upon a call to exec?

Waitpid returns when the given pid dies/exits or immediately if it's already a zombie. The exec is called in the grandchild. Your waitpid calls are not at all not concerned with processes that aren't your direct children (unless you're using the Linux-only child-subreaper feature).

Does waitpid return even if exit or exec were called before waitpid?

Waitpid only ever returns when the waited on pid (which must be your direct child) is dead. If that's not yet the case, it will block.