function complete_exec($command, $stdin = NULL, $timeout = 20, $pass_through = false) { global $opt_verbose; if ($opt_verbose) { print "Running command: {$command}\n"; } $descriptorspec = array(0 => array("pipe", "r"), 1 => array("pipe", "w"), 2 => array("pipe", "w")); $pipes = array(); $handle = proc_open($command, $descriptorspec, &$pipes, getcwd()); # read stdin into the process if ($stdin !== NULL) { fwrite($pipes[0], $stdin); } fclose($pipes[0]); unset($pipes[0]); // set non blocking to avoid infinite loops on stuck programs stream_set_blocking($pipes[1], 0); stream_set_blocking($pipes[2], 0); $out = ""; $err = ""; $start_time = time(); do { $status = proc_get_status($handle); // It seems that with a large amount fo output, the process // won't finish unless the buffers are periodically cleared. // (This doesn't seem to be the case is async_test. I don't // know why). $new_out = stream_get_contents($pipes[1]); $new_err = stream_get_contents($pipes[2]); $out .= $new_out; $err .= $new_err; if ($pass_through) { print $new_out; file_put_contents("php://stderr", $new_err); } if ($timeout != 0 && time() > $start_time + $timeout) { $out = stream_get_contents($pipes[1]); $err = stream_get_contents($pipes[2]); kill_properly($handle, $pipes); return array("Timeout", $out, $err); } // Since we use non-blocking, the for loop could well take 100% // CPU. time of 1000 - 10000 seems OK. 100000 slows down the // program by 50%. usleep(10000); } while ($status["running"]); stream_set_blocking($pipes[1], 1); stream_set_blocking($pipes[2], 1); $out .= stream_get_contents($pipes[1]); $err .= stream_get_contents($pipes[2]); $exit_code = $status["exitcode"]; kill_properly($handle, $pipes); return array($out, $err, $exit_code); }
function check_running_procs() { // try to keep this really lightweight # inst ("Check running"); foreach ($this->running_procs as $index => $bundle) { $status = proc_get_status($bundle->handle); // read the streams in case they block $bundle->read_streams(); if ($status["running"] !== true) { $bundle->exit = $status["exitcode"]; unset($this->running_procs[$index]); // remove from the running list $bundle->continuation(); // start the next bit straight away } else { if ($this->max_time != 0 && time() > $bundle->start_time + $this->max_time) { kill_properly($bundle->handle, $bundle->pipes); $bundle->exits[] = "Timeout"; $bundle->out .= "\n--- TIMEOUT ---"; $bundle->outs[] = $bundle->out; $bundle->errs[] = $bundle->err; $this->async_timeout("Timeout", $bundle); unset($this->running_procs[$index]); // remove from the running list } else { // let it keep running } } } }