Process group for child processes of a library

1.1k views Asked by At

I'm working on a library (C++) that will be integrated into clients code. This lib will spawn a few child processes and must monitor them to respawn them as soon as they die (for any reason). I need to use vfork and exec to spawn those child processes.

I know I must use a signal handler to handle SIGCHLD and call waitpid to detect which child is dead. However, the user code may be using the same idea to handle its own child processes.

If I call waitpid, I'll retrieve information regarding any child process that may died (mine or not). If the dying process is mine, no problem... happy case. However, if it is from the user, he is not getting any information about that because I've already called waitpid.

How can I work around that?

My first idea is to use process groups. The first time I fork, I'd get the child pid and save it as a process group id. Each child that I'd create, I'd set it's group to this pid. Do you guys think that's a good choice? (I'm having trouble with that).

My second idea would be to reset the signal handler to the original one (or just call it). If I reraise the signal, the original handler would be able to get it. I'd have to reinstall my signal handler after that. Would it be a good choice?

My third choice would be using INFO (extended signal handler). I believe the pid of the dying process will be available in the info structure. If this is one of mine children, I'd call waitpid for that and that's ok. If that is not one of mine, I'd call the original signal handler. Would it be a good choice?

Just one last side question. To be able to call original signal handlers, should I always restore them and reraise the signal or just calling that as a function call is enough?

Thanks very much for your help.

3

There are 3 answers

2
Greg Hewgill On BEST ANSWER

Another option might be to spawn one child process first, which communicates with your main process through whatever IPC mechanism you like. Then, spawn the multiple child processes from within that new process, which gives you full control over the way the child processes terminate.

0
Marcus On

This post is just to clarify my solution.

I decided not to use signal handlers in the main process anymore. A lib shouldn't deal with signals unless necessary.

From the main process, I create a pipe calling a separate binary that will turn itself into a deamon. This way, the process spawn by that won't be children of the main process.

To turn it into a deamon, I just fork it. The parent of the fork just prints the PID of the child so the main process can get it back (through the pipe). The child process sets the umask to zero, create a new SID, change the current directory to "/" and reopen the STDIN, STDOUT and STDERR (all to /dev/null). This way the child is now a deamon.

This deamon is responsible to spawn all my processes. All of them (including the deamon) comunicate back to the main process using sockets.

The main processes sends signals to the deamon (SIGINT to close it and all its children, SIGUSER1 and 2 to predefined actions).

Thanks for everyone that helped here.

1
mity On

If it is a general purpose library (for any 3rd party), you should try avoid such construct. If its use cannot be avoided, document the signal handling very very carefully.

If a program linking with the lib plays with signals, many complex situations can occur, and the lib just have no chance handle them all correctly, without affecting the program in unexpected ways. Consider the program may have multiple threads or handle other signals you don't: In either case it may change the signal handling of SIGCHILD concurrently and break your logic.

Perhaps it might be better to provide a function in the lib and you let it on the program responsibility to call it when the signal SIGCHILD (for PIDs you have created) comes so the program has liberty still handle its signals how it wishes.