Waitpid equivalent with timeout?
The function can be interrupted with a signal, so you could set a timer before calling waitpid() and it will exit with an EINTR when the timer signal is raised. Edit: It should be as simple as calling alarm(5) before calling waitpid().
Is there a version of the wait() system call that sets a timeout?
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
Killing child process after timeout, with multiple children?
I was about to recommend polling with waitpid()
, using the WNOHANG
flag to prevent that from blocking, but I think I came up with something better: a pipe from the child, and select()
in the parent.
Specifically,
- the parent creates a pipe before forking.
- after (successfully) forking, the parent closes its copy of the write end of the pipe.
- the parent then uses
select()
, with the wanted timeout, to wait for the pipe to become available for reading. The child does not need actually to write to the pipe, or even to know about it. The write end will be closed when the child terminates, and that will make the read end available for reading (the EOF signal). - If the timeout expires then the parent sends a
SIGTERM
to the child. - Either way, the parent collects the child with
waitpid()
.
Be sure to check the status code provided by waitpid
if you care whether the child terminated normally, because there is a chance that it terminates normally between the timeout expiring and the SIGTERM
being delivered, in which case I think waitpid
will (properly) show it as having terminated normally. Of course, it can also terminate on account of receiving a signal from another source or for another reason -- a SIGSEGV
, for example.
Here are the bones of such an approach. You'll need to add details to make it work for you, and error-handling to make it robust:
pid_t child_pid;
int term_pipe[2];
pipe(term_pipe);
child_pid = fork();
switch (child_pid) {
case -1:
// handle error
break;
case 0:
// child
// ... whatever ...
exit(0);
}
close(term_pipe[1]); // essential
fd_set read_fds;
struct timeval timeout = { /* timeout */ };
int result;
FD_ZERO(read_fds);
FD_SET(term_pipe[0], read_fds);
result = select(term_pipe[0] + 1, &read_fds, NULL, NULL, &timeout);
if (result == 0) {
// timeout
kill(child_pid, SIGTERM);
} else if (result < 0) {
// handle error
// in particular, you may need to resume waiting if the error is EINTR
} else {
// the child terminated within the timeout
assert(result == 1);
}
// don't forget to close the read end of the pipe
close(term_pipe[0]);
int status;
pid_t collected_pid = waitpid(child_pid, &status, 0);
if (collected_pid < 0) {
// handle error
} else {
assert(collected_pid == child_pid);
// ... test the status to see how the child terminated ...
// ...
}
Note that you want normal handling of child termination with this, so do not block SIGCHLD
as your code presently does.
(PHP) wait for child process to exit with timeout
I'm just curious, is it necessary to use proc_open()? Because as your example code it is possible to do it with exec() function but it need a simple CLI tool to use with, its timeout
.
timeout - run a command with a time limit Start COMMAND, and kill it
if still running after DURATION
So this code is alternative for your code, unless you want to do something else with the child.
$starttime = microtime(true);
exec("timeout " . MAX_RUNTIME_SECONDS . " $cmd");
$terminated = false;
if (! $terminated && microtime(true) - $starttime > MAX_RUNTIME_SECONDS) {
$terminated = true;
echo 'max runtime reached (' . MAX_RUNTIME_SECONDS . ' seconds), terminating...';
}
This trick I've been using for years with multiprocessing in PHP. And its work perfectly for me.
Related Topics
Connected Components in Opencv
Tackling Class Imbalance: Scaling Contribution to Loss and Sgd
Is Left and Right Shifting Negative Integers Defined Behavior
Copy Constructor of Template Class
What Happens If You Increment an Iterator That Is Equal to the End Iterator of an Stl Container
How Can an Incomplete Type Be Used as a Template Parameter to Vector Here
What Is Forward Declaration in C++
Cout or Printf Which of the Two Has a Faster Execution Speed C++
Conversion from String Literal to Char* Is Deprecated
Linux Equivalent for Conio.H Getch()
Unsequenced Value Computations (A.K.A Sequence Points)
Why Don't the C or C++ Standards Explicitly Define Char as Signed or Unsigned
What Is the Precision of Long Double in C++
Repeated Multiple Definition Errors from Including Same Header in Multiple Cpps
Std::List<>::Sort()' - Why the Sudden Switch to Top-Down Strategy
Why Is Protected Constructor Raising an Error This This Code