How to Spawn Child Processes that Don't Die with Parent?

zachd1_618 picture zachd1_618 · Jul 11, 2013 · Viewed 13.6k times · Source

I have a C++ program that acts as a watchdog over others. If it detects that a process is no longer running, it restarts it via system. The problem is, if I kill the watchdog process, any processes it has started up also die.

void* ProcessWatchdog::worker(void* arg)
{
    //Check if process is running
    if( !processRunning )
        system("processName /path/to/processConfig.xml &");
}

The new child process gets started correctly, and runs without any problems. But when the parent (now this ProcessWatchdog process) dies, the child dies too. How can I spawn a child process that is fully independent from the parent?

I've tried using pclose and popen, running shell scripts that start processes, and a few other tactics, but to no avail. I'm ignoring SIGHUP signals in the child processes, but they still die.

So ideally, I'd like to tell the system to start a process that is wholly independent from the parent. I want the child's trace to end with the child, and for it/the system to have no idea that ProcessWatchdog started it in the first place.

Is there a way I can do this?

I'm writing this in C++, on Linux.

Answer

grubs picture grubs · Feb 28, 2014

This one is a bit old but didn't get a complete answer. Here is what I have done on an embedded system to spawn a bash child with no relation to the parent. Note that I execl a bash shell and then run my command in another bash shell. This may not be necessary in your situation. For me it allowed me to do some I/O redirection that didn't work properly without it.

The two important concepts are the setsid() and the double fork(). The combination of these two prevents a zombie from being created when the orphaned child completes, as well as preventing the orphaned child from being killed if the parent completes.

There are many other issues that could come up, like inherited I/O handles, working directory, etc, but this code does the basic job.

int spawn_orphan(char* cmd) {
    char command[1024]; // We could segfault if cmd is longer than 1000 bytes or so
    int pid;
    int Stat;
    pid = fork();
    if (pid < 0) { perror("FORK FAILED\n"); return pid; }
    if (pid == 0) { // CHILD
        setsid(); // Make this process the session leader of a new session
        pid = fork();
        if (pid < 0) { printf("FORK FAILED\n"); exit(1); }
        if (pid == 0) { // GRANDCHILD
            sprintf(command,"bash -c '%s'",cmd);
            execl("/bin/bash", "bash", "-c", command, NULL); // Only returns on error
            perror("execl failed");
            exit(1);
        }
        exit(0); // SUCCESS (This child is reaped below with waitpid())
    }

    // Reap the child, leaving the grandchild to be inherited by init
    waitpid(pid, &Stat, 0);
    if ( WIFEXITED(Stat) && (WEXITSTATUS(Stat) == 0) ) {
        return 0; // Child forked and exited successfully
    }
    else {
        perror("failed to spawn orphan\n");
        return -1;
    }
}