Is there any way to use the wait()
system call with a timeout, besides using a busy-waiting or busy-sleeping loop?
I\'ve got a parent process that
You can use waitpid
together with the WNOHANG
option and a sleep.
while(waitpid(pid, &status, WNOHANG) == 0) {
sleep(1);
}
But this will be an active sleeping. However I see no other way using the wait
type of functions.
On linux, you can also solve this problem using signalfd
. signalfd
essentially takes a set of signals and creates an fd which you can read; each block you read corresponds to a signal which has fired. (You should block these signals with sigprocmask so that they are not actually sent.)
The advantage of signalfd
is that you can use the fd with select
, poll
, or epoll
, all of which allow for timeouts, and all of which allow you to wait for other things as well.
One note: If the same signal fires twice before the corresponding struct signalfd_siginfo
is read, you'll only receive a single indication. So when you get a SIGCHLD
indication, you need to waitpid(-1, &status, &WNOHANG)
repeatedly until it returns -1.
On FreeBSD, you can achieve the same effect rather more directly using kqueue
and a kevent
of type EVFILT_PROC
. (You can also kqueue a SIGCHLD event, but EVFILT_PROC lets you specify the events by child pid instead of globally for all children.) This should also work on Mac OS X, but I've never tried it.
There's not a wait call that takes a timeout.
What you can do instead is install a signal handler that sets a flag for SIGCHLD, and use select() to implement a timeout. select() will be interrupted by a signal.
static volatile int punt;
static void sig_handler(int sig)
{
punt = 1;
}
...
struct timeval timeout = {10,0};
int rc;
signal(SIGCHLD, sig_handler);
fork/exec stuff
//select will get interrupted by a signal
rc = select(0, NULL,NULL,NULL, &timeout );
if (rc == 0) {
// timed out
} else if (punt) {
//child terminated
}
More logic is needed if you have other signal you need to handle as well though