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.
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;
}
}