0

I have come across a problem with my application and the spawnProcess. If the main application for some reason dies/is killed then the spawned processes seem to live on and I can't reach them unless I use terminal to kill them via their PIDs. My goal is if the main application dies then the spawned processes should be killed also, somehow.

My code is like this

auto appPid = spawnProcess("path/to/process");
scope(exit){ auto exitcode = wait(appPid); 
stderr.writeln(...);}

And if I use the same approach when the main process dies, using wait(thisProcessID) I get an error. "No overload matches". Any ideas how to solve this problem?

dda
  • 6,030
  • 2
  • 25
  • 34
Anders S
  • 187
  • 11
  • By same approach I mean 'scope(exit){wait(thisProcessID); kill (appPID) ...' – Anders S Jan 02 '17 at 14:22
  • Do you want it to kill them forcibly or just cause the main program to stay alive until the children close naturally? http://stackoverflow.com/a/23587108/1457000 is an answer for the kill (the same function can be used from D.... oh poop you are using the high level functions so you can't inject that call in the right place. i need to rethink this before posting as an answer). Your wait won't work since spawnProcess returns a magic class and thisProcessId just returns an int. wait expects the class. But besides, wait only works on children I think, not parents... – Adam D. Ruppe Jan 02 '17 at 15:27
  • Hi Adam, I don't care how the close, but soft is better. – Anders S Jan 02 '17 at 15:29
  • Hi Adam, I don't care how they close, though soft is better. Yes it seems that spawnProcess returns Pid to children, but the children doesn't seem to be connected to parent so hard that there is any relation when it comes to running or dieing. I found a thread aboud implementing a getThis nut no solution to it. Can imagine that going through 'ps' and list all processes and extracting the pid that way is possible. However I only want to react when /if main crashes/is killed like using Ctrl + C in terminal. If wait doesn't work on parents, what does/how to do? – Anders S Jan 02 '17 at 15:36
  • Yeah, right after forking, but before execing, you can do that prctl call from the link, that's the best way. You could also get the parent pid and open its /proc file and wait for changes from inside teh child... but if you are writing the child anyway, you might as well just make that prctl call yourself. I'll write an answer eventually, gotta work around the house first tho. – Adam D. Ruppe Jan 02 '17 at 17:39
  • blargh prctl isn't included in the D headers. but i'll show you an answer in a minute. – Adam D. Ruppe Jan 05 '17 at 03:02

1 Answers1

0

Here's some code that will do it on Linux. It doesn't have all the features of the stdlib's spawnProcess, it just shows the bare basics, but expanding it from here isn't hard if you need more.

import core.sys.posix.unistd;

version(linux) {
        // this function is Linux-specific
        import core.stdc.config;
        import core.sys.posix.signal;
        // we can tell the kernel to send our child process a signal
        // when the parent dies...
        extern(C) int prctl(int, c_ulong, c_ulong, c_ulong, c_ulong);
        // the constant I pulled out of the C headers
        enum PR_SET_PDEATHSIG = 1;
}

pid_t mySpawnProcess(string process) {
        if(auto pid = fork()) {
                // this branch is the parent, it can return the child pid
                // you can:
                // import core.sys.posix.sys.wait;
                // waitpid(this_ret_value, &status, 0);
                // if you want the parent to wait for the child to die
                return pid;
        } else {
                // child

                // first, tell it to terminate when the parent dies
                prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0);

                // then, exec our process
                char*[2] args;
                char[255] buffer;
                // gotta copy the string into another buffer
                // so we zero terminate it and have a C style char**...
                buffer[0 .. process.length] = process[];
                buffer[process.length] = 0;
                args[0] = buffer.ptr;

                // then call exec to run the new program
                execve(args[0], args.ptr, null);
                assert(0); // never reached
        }
}

void main() {
        mySpawnProcess("/usr/bin/cat");
        // parent process sleeps for one second, then exits
        usleep(1_000_000);
}

So the lower level functions need to be used, but Linux does have a function that does what you need.

Of course, since it sends a signal, your child might want to handle that to close more gracefully than the default termination, but try this program and run ps while it sleeps to see cat running, then notice the cat dies when the parent exits.

Adam D. Ruppe
  • 25,382
  • 4
  • 41
  • 60
  • Thks Adam, this is really interesting, though somewhat over my linux knowledge today. If i understand your example code, use mySpawnedProcess to get my own pid, however i don't have the child's pid so that I can communicate between the threads. However if I have a local variable above the fork() line and after the fork I assign it parent pid, are that accessable to be used by child to inform/signal parent of its pid? Then a new thing to me, the prctl( ..) and also as I understand the thing I can use, ...the answer to my question. Shall dig into your code and test more – Anders S Jan 05 '17 at 15:12
  • `fork` returns the *child* pid, so the return value of `mySpawnProcess` is the child's PID to the parent process. So you already have it there.. – Adam D. Ruppe Jan 05 '17 at 15:24