Boost logo

Boost :

From: Rob Stewart (stewart_at_[hidden])
Date: 2004-06-22 15:16:09


From: Angus Leeming <angus.leeming_at_[hidden]>
>
> 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_at_[hidden]
Software Engineer                     http://www.sig.com
Susquehanna International Group, LLP  using std::disclaimer;

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk