
From: Angus Leeming <angus.leeming@btopenworld.com>
I am in the process of writing a little library to control the interaction of a parent program with any child processes that it spawns. Would there be any interest in such a library here?
I wanted to comment on a question you raised, but don't construe this as interest. I actually don't have a need for such a library, but I can see the value in it.
Under unix, I've defined a handler for SIGCHLD signals. The handler does two things only: * reaps the zombie * stores the return status in a std::map<pid_t, int> completed_children; variable. Each time a new child is spawned, the pid of the child process is registered in the map, so the handler needs do nothing other than find the entry.
namespace {
std::map<pid_t, int> completed_children;
int status; sig_atomic_t pid;
}
extern "C" void child_handler(int) { pid = wait(&status); std::map<pid_t, int>::iterator it = completed_children.find(pid); if (it != completed_children.end()) it->second = status; }
I'm pretty sure that the above is safe code. It does the absolute minimum in the handler routine. wait() is guaranteed to be async-safe. Moreover, the handler receives only SIGCHLD signals and so cannot receive multiple calls simultaneaously. However, I'm unsure whether it Ok to search the map like this. Any advice?
The code does very little work. The map is not likely to every be very large; not many applications create and track a large number of child processes. That means that finding the child will be fast; creating the map entry ahead of time saves some work in the signal handler, which is good. The range of PIDs is limited, so maybe a std::deque or std::vector would be better. Once created, accessing the status would be a simple indexing operation. (That requires initializing elements to some sentinel value to indicate no value.) Another scheme to handle large numbers of child processes would be to put a std::pair<pid_t, int> into a queue or stack and let non-signal-handler code populate the data structure from the queued pair.
My one other worry is that the SIGCHLD handler could be redefined elsewhere in the code, but AFAICS there's nothing that I can do about that. Furthermore, it means only that the user of my Child library won't be able to ascertain the exit status of child processes launched using it.
The proper way to install a signal handler is to chain to any previous signal handler for the same signal. Therefore, a library client should write code that ensures that your handler gets called. You could also go the other way around. You could provide a mechanism for clients to install their own handler (a boost::function<void, int>?) for your handler to call. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;