Esempio n. 1
0
function pleac_Running_Another_Program()
{
    // Run a simple command and retrieve its result code.
    exec("vi {$myfile}", $output, $result_code);
    // -----------------------------
    // Use the shell to perform redirection.
    exec('cmd1 args | cmd2 | cmd3 >outfile');
    exec('cmd args <infile >outfile 2>errfile');
    // -----------------------------
    // Run a command, handling its result code or signal.
    $pid = pcntl_fork();
    if ($pid == -1) {
        die('cannot fork');
    } elseif ($pid) {
        pcntl_waitpid($pid, $status);
        if (pcntl_wifexited($status)) {
            $status = pcntl_wexitstatus($status);
            echo "program exited with status {$status}\n";
        } elseif (pcntl_wifsignaled($status)) {
            $signal = pcntl_wtermsig($status);
            echo "program killed by signal {$signal}\n";
        } elseif (pcntl_wifstopped($status)) {
            $signal = pcntl_wstopsig($status);
            echo "program stopped by signal {$signal}\n";
        }
    } else {
        pcntl_exec($program, $args);
    }
    // -----------------------------
    // Run a command while blocking interrupt signals.
    $pid = pcntl_fork();
    if ($pid == -1) {
        die('cannot fork');
    } elseif ($pid) {
        // parent catches INT and berates user
        declare (ticks=1);
        function handle_sigint($signal)
        {
            echo "Tsk tsk, no process interruptus\n";
        }
        pcntl_signal(SIGINT, 'handle_sigint');
        while (!pcntl_waitpid($pid, $status, WNOHANG)) {
        }
    } else {
        // child ignores INT and does its thing
        pcntl_signal(SIGINT, SIG_IGN);
        pcntl_exec('/bin/sleep', array('10'));
    }
    // -----------------------------
    // Since there is no direct access to execv() and friends, and
    // pcntl_exec() won't let us supply an alternate program name
    // in the argument list, there is no way to run a command with
    // a different name in the process table.
}
 /**
  * Analyzes the passed status code of a process and sets properties accordingly.
  * 
  * @param int $status
  * @author Dan Homorodean <*****@*****.**>
  */
 public function __construct($status)
 {
     if (pcntl_wifexited($status)) {
         $this->status = self::STATUS_EXITED;
         $this->exitCode = pcntl_wexitstatus($status);
     } elseif (pcntl_wifsignaled($status)) {
         $this->status = self::STATUS_SIGNALED;
         $this->reasonSignal = pcntl_wtermsig($status);
     } elseif (pcntl_wifstopped($status)) {
         $this->status = self::STATUS_STOPPED;
         $this->reasonSignal = pcntl_wstopsig($status);
     }
 }
Esempio n. 3
0
function test_stop_signal()
{
    print "\n\nTesting pcntl_wifstopped and pcntl_wstopsig....";
    $pid = pcntl_fork();
    if ($pid == 0) {
        sleep(1);
        exit;
    } else {
        $options = WUNTRACED;
        posix_kill($pid, SIGSTOP);
        pcntl_waitpid($pid, $status, $options);
        if (pcntl_wifstopped($status)) {
            $signal_print = pcntl_wstopsig($status);
            if ($signal_print == SIGSTOP) {
                $signal_print = "SIGSTOP";
            }
            print "\nProcess was stoped by signal : " . $signal_print;
        }
        posix_kill($pid, SIGCONT);
    }
}
Esempio n. 4
0
 /**
  * Checks whether the child process is currently stopped.
  *
  * @return bool
  */
 public function isStopped()
 {
     return pcntl_wifstopped($this->status);
 }
Esempio n. 5
0
 /**
  * Execute a command.
  *
  * @param $command Command to be run.
  * @param $args Arguments of the command to be run.
  * @param $env Environment variables to be set before running the command.
  * @param $input Data to be sent (piped) to the process. Default to null (no data will be sent to the process).
  * If a string, it will be sent to the process as text. If it is a file or filename, data will be read from the file and
  * sent to the process through the pipe.
  * @param $output Output data. Default to null (no output data will be saved). If it is a filename,
  * output data will be written to the file.
  * @param $timeout Seconds before timing out and aborting execution.
  *
  * @returns Zero if ok, anything else on error.
  */
 function execute($command, $args = NULL, $env = NULL, $input = NULL, $output = NULL, $timeout = Runner::DEFAULT_TIMEOUT)
 {
     if ($input != NULL) {
         $pipe_filename = '/tmp/inpipe';
         posix_mkfifo($pipe_filename, 0600);
     }
     $pid = pcntl_fork();
     if ($pid == 0) {
         // Child
         // Redirects stdin to pipe (the client will read data from pipe while the parent will write to it)
         fclose(STDIN);
         if ($input != NULL) {
             $STDIN = fopen($pipe_filename, 'r');
         }
         // Redirects stdout to file
         if ($output != NULL) {
             if (is_resource($output) || is_string($output)) {
                 fclose(STDOUT);
                 fclose(STDERR);
                 if (!is_resource($output)) {
                     $output_file = fopen($output, 'w');
                 } else {
                     $output_file = $output;
                 }
                 $STDOUT = $output_file;
                 $STDERR = $output_file;
             } else {
                 // fwrite($output, );
             }
         }
         pcntl_signal(SIGALRM, function ($signal) {
             fflush(STDOUT);
             fclose(STDOUT);
             fflush(STDERR);
             fclose(STDERR);
             posix_kill(posix_getpid(), SIGTERM);
         });
         pcntl_alarm($timeout);
         if ($args == NULL) {
             pcntl_exec($command);
         } else {
             if ($env == NULL) {
                 pcntl_exec($command, $args);
             } else {
                 pcntl_exec($command, $args, $env);
             }
         }
     } else {
         // Parent
         if ($input != NULL) {
             $pipe = fopen($pipe_filename, 'w');
             if (is_resource($input) || is_file($input)) {
                 if (is_file($input)) {
                     $input_file = fopen($input, 'r');
                 } else {
                     $input_file = $input;
                 }
                 $input_data = fread($input_file, filesize($input));
                 fclose($input_file);
             } else {
                 $input_data = $input;
             }
             fwrite($pipe, $input_data);
             fclose($pipe);
         }
     }
     if ($input != NULL) {
         unlink($pipe_filename);
     }
     pcntl_waitpid($pid, $status);
     if (pcntl_wifexited($status)) {
         return pcntl_wexitstatus($status);
     }
     if (pcntl_wifsignaled($status) || pcntl_wifstopped($status)) {
         return -1;
     }
 }
Esempio n. 6
0
 private function processSignalChild()
 {
     $childrenQty = 0;
     while (true) {
         $exitedWorkerPid = pcntl_waitpid(-1, $status, WNOHANG);
         if ($exitedWorkerPid === 0) {
             Logger::getLogger('queue')->debug("process SIGCHLD complete, childrenQty={$childrenQty}");
             return;
         }
         if ($exitedWorkerPid === -1) {
             $error_number = pcntl_get_last_error();
             $error = "[{$error_number}] " . pcntl_strerror($error_number);
             $message = "Can't wait pid, error: '{$error}'";
             if ($error_number === PCNTL_ECHILD) {
                 Logger::getLogger('queue')->debug($message);
             } else {
                 Logger::getLogger('queue')->error($message);
             }
             return;
         }
         Logger::getLogger('queue')->debug("exitedWorkerPid={$exitedWorkerPid}");
         if (!isset($this->childrenInfo[$exitedWorkerPid])) {
             Logger::getLogger('queue')->error('pcntl_waitpid return unknown pid:' . var_export($exitedWorkerPid, true), new Exception());
             continue;
         }
         $isExited = false;
         $queueNick = $this->childrenInfo[$exitedWorkerPid]['queueNick'];
         if (pcntl_wifexited($status)) {
             $isExited = true;
             $code = pcntl_wexitstatus($status);
             Logger::getLogger('queue')->debug("exitCode={$code}");
             if (!isset($this->workersErrorsQty[$queueNick])) {
                 $this->workersErrorsQty[$queueNick] = 0;
             }
             if ($code) {
                 ++$this->workersErrorsQty[$queueNick];
                 Logger::getLogger('queue')->error("worker pid={$exitedWorkerPid} for queue {$queueNick} exit with code {$code}");
             } else {
                 $this->workersErrorsQty[$queueNick] = 0;
             }
             if ($this->workersErrorsQty[$queueNick] > $this->maxWorkersQty * 0.5) {
                 $message = "queue {$queueNick} worker errors qty = {$this->workersErrorsQty[$queueNick]}. Disable this queue.";
                 $this->queuesInfo[$queueNick]['state'] = 'error';
                 $this->queuesInfo[$queueNick]['message'] = $message;
                 Logger::getLogger('queue')->error($message);
                 if (isset($this->queues[$queueNick])) {
                     $this->queues[$queueNick]->unlockTasks();
                     unset($this->queues[$queueNick]);
                 }
             }
         }
         if (pcntl_wifsignaled($status)) {
             $isExited = true;
             $errorSignal = pcntl_wtermsig($status);
             Logger::getLogger('queue')->error("{$exitedWorkerPid} terminate by signal {$errorSignal}");
         }
         if (pcntl_wifstopped($status)) {
             $stopSignal = pcntl_wstopsig($status);
             Logger::getLogger('queue')->error("{$exitedWorkerPid} stop by signal {$stopSignal}");
         }
         if ($isExited) {
             --$this->workersQty;
             if (isset($this->queuesInfo[$queueNick])) {
                 --$this->queuesInfo[$queueNick]['activeWorkersQty'];
                 Logger::getLogger('queue')->debug("worker complete, workersQty={$this->workersQty},queue={$queueNick},activeWorkersQty={$this->queuesInfo[$queueNick]['activeWorkersQty']}");
             }
             $this->freeWorkersNumbers[] = $this->childrenInfo[$exitedWorkerPid]['workerNumber'];
             unset($this->childrenInfo[$exitedWorkerPid]);
         }
         ++$childrenQty;
     }
 }
                            if (!mysqli_query($plink, sprintf($parent_sql, 'continue'))) {
                                printf("[017] Parent cannot inform child to continue.\n", mysqli_errno($plink), mysqli_error($plink));
                            }
                            break;
                    }
                }
                mysqli_free_result($pres);
            }
            usleep(100);
        } while (time() - $start < 5 && $num_rows < 3);
        mysqli_close($plink);
        $wait_id = pcntl_waitpid($pid, $status);
        if (pcntl_wifexited($status) && 0 != ($tmp = pcntl_wexitstatus($status))) {
            printf("Exit code: %s\n", pcntl_wifexited($status) ? pcntl_wexitstatus($status) : 'n/a');
            printf("Signal: %s\n", pcntl_wifsignaled($status) ? pcntl_wtermsig($status) : 'n/a');
            printf("Stopped: %d\n", pcntl_wifstopped($status) ? pcntl_wstopsig($status) : 'n/a');
        }
        break;
}
mysqli_free_result($res);
mysqli_close($link);
if (!($link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket))) {
    printf("[018] Cannot connect to the server using host=%s, user=%s, passwd=***, dbname=%s, port=%s, socket=%s\n", $host, $user, $db, $port, $socket);
}
if (!($res = mysqli_query($link, "SELECT sender, msg FROM messages ORDER BY msg_id ASC"))) {
    printf("[019] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
}
while ($row = mysqli_fetch_assoc($res)) {
    printf("%10s %s\n", $row['sender'], substr($row['msg'], 0, 5));
}
mysqli_free_result($res);
Esempio n. 8
0
VS(pcntl_wexitstatus($status), 0x80);
$pid = pcntl_fork();
if ($pid == 0) {
    exit(0x12);
}
pcntl_waitpid(0, $status);
VERIFY(pcntl_wifexited($status));
$pid = pcntl_fork();
if ($pid == 0) {
    exit(0x12);
}
pcntl_waitpid(0, $status);
VERIFY(!pcntl_wifsignaled($status));
$pid = pcntl_fork();
if ($pid == 0) {
    exit(0x12);
}
pcntl_waitpid(0, $status);
VERIFY(!pcntl_wifstopped($status));
$pid = pcntl_fork();
if ($pid == 0) {
    exit(0x12);
}
pcntl_waitpid(0, $status);
VS(pcntl_wstopsig($status), 0x12);
$pid = pcntl_fork();
if ($pid == 0) {
    exit(0x12);
}
pcntl_waitpid(0, $status);
VS(pcntl_wtermsig($status), 0);
Esempio n. 9
0
 /**
  * W If Stopped
  *
  * @param $status The status parameter is the status parameter supplied to a successful call to pcntl_waitpid().
  *
  * @return bool Returns TRUE if the child process which caused the return is currently stopped, FALSE otherwise.
  */
 public function wIfStopped($status)
 {
     return pcntl_wifstopped($status);
 }
Esempio n. 10
0
 /**
  * PHP_Fork::wait()
  * Wait for the current thread to exit.
  *
  *
  * <code>
  *   ...
  *       $executeThread1->wait();
  *     ...
  * </code>
  *
  * After the relative process exited he disappears automaticly from the processes list.
  *
  * @return boolean true if the process is succesfully exited, false otherwise.
  */
 public function wait()
 {
     $success = false;
     if ($this->_pid > 0 && $this->_running) {
         try {
             pcntl_waitpid($this->_pid, $temp = 0, WNOHANG);
             if (!($success = pcntl_wifexited($temp))) {
                 if (pcntl_wifstopped($temp)) {
                     throw new PHP_ForkException("Signal: " . pcntl_wstopsig($temp) . " caused this child to stop.", pcntl_wstopsig($temp));
                 } else {
                     if (pcntl_wifsignaled($temp)) {
                         throw new PHP_ForkException("Signal: " . pcntl_wtermsig($temp) . " caused this child to exit with return code: " . pcntl_wexitstatus($temp), pcntl_wexitstatus($temp));
                     }
                 }
             }
             $this->_cleanThreadContext();
         } catch (Exception $e) {
             throw new PHP_ForkException($e->getMessage(), $e->getCode());
         }
     }
     return $success;
 }
Esempio n. 11
0
     } elseif (0 === $pid) {
         echo "Spawned child\n";
         $task();
     }
 }
 while (true) {
     $pid = pcntl_waitpid(-1, $status, WNOHANG | WUNTRACED);
     if ($pid === 0) {
         echo "No children exited\n";
         break;
     } elseif ($pid === -1) {
         echo "Failed something\n";
         echo "Status '" . $status . "'\n";
         if (pcntl_wifexited($status)) {
             echo "pcntl_wifexited\n";
         } elseif (pcntl_wifstopped($status)) {
             echo "pcntl_wifstopped\n";
         } elseif (pcntl_wifsignaled($status)) {
             echo "pcntl_wifsignaled\n";
         } elseif (pcntl_wexitstatus($status)) {
             echo " pcntl_wexitstatus\n";
         } elseif (pcntl_wtermsig($status)) {
             echo " pcntl_wtermsig\n";
         } elseif (pcntl_wstopsig($status)) {
             echo " pcntl_wstopsig\n";
         }
         exit;
     } else {
         echo "Child #" . $pid . " exited\n";
         $exit = true;
     }
Esempio n. 12
0
 /**
  * Supervise the children and react on finished processes.
  *
  * @param callback $ticker callback to call during each loop
  */
 public function supervise($ticker = NULL, $respawnChecker = NULL)
 {
     // loop and monitor children
     while (!empty($this->children)) {
         $start = time();
         // Check if a child exited
         foreach ($this->children as $pid => $fork) {
             $exited = pcntl_waitpid($pid, $status, WNOHANG);
             switch ($exited) {
                 case $pid:
                     $fork->setStop();
                     unset($this->children[$pid]);
                     switch (TRUE) {
                         // signal which was not caught
                         case pcntl_wifsignaled($status):
                             self::log(sprintf('Child %d, %s terminated from signal %d after running %d seconds.', $pid, $fork->description, pcntl_wtermsig($status), $fork->getDurationSeconds()), ezcLog::INFO);
                             break;
                         case pcntl_wifexited($status):
                             $exitstatus = pcntl_wexitstatus($status);
                             self::log(sprintf('Child %d, %s exited with status %d after running %d seconds.', $pid, $fork->description, $exitstatus, $fork->getDurationSeconds()), ezcLog::INFO);
                             //@TODO make reforking configurable
                             $respawn = $this->respawn;
                             if ($respawn && is_callable($respawnChecker)) {
                                 $respawn = call_user_func($respawnChecker, $pid, $exitstatus);
                             }
                             if ($respawn) {
                                 self::log('refork ' . $fork->description, ezcLog::INFO);
                                 $this->fork($fork);
                             }
                             break;
                         case pcntl_wifstopped($status):
                             self::log(sprintf('Child %d, %s stopped from signal %d after running %d seconds.', $pid, $fork->description, pcntl_wstopsig($status), $fork->getDurationSeconds()), ezcLog::INFO);
                             break;
                     }
                     break;
                 case -1:
                     self::log(sprintf('Got -1 when checking pid %d', $pid), ezcLog::ERROR);
                     break;
                 case 0:
                     break;
                 default:
                     throw new Exception('pcntl_waitpid returned ' . $exited . ' for pid ' . $pid);
             }
         }
         // save CPU cycles
         // sleep( 5 );
         $this->runServer();
         if (is_callable($ticker)) {
             call_user_func($ticker);
         }
         self::log(sprintf('fork runner supervise loop took %d seconds.', time() - $start), ezcLog::DEBUG);
     }
     self::log('Leaving fork runner supervise function', ezcLog::DEBUG);
 }
Esempio n. 13
0
 /**
  * @param $status
  *
  * @return bool
  */
 private function watchdogProcessStatus($status)
 {
     switch (true) {
         case pcntl_wifexited($status):
             $code = pcntl_wexitstatus($status);
             $this->handleProcessExitStatus($this->watchdogPID, self::PROCESS_TYPE_WATCHDOG, $code);
             return true;
         case pcntl_wifsignaled($status):
             $sig = pcntl_wtermsig($status);
             if ($sig !== SIGKILL) {
                 $this->logger->warn(sprintf("watchdog %d terminated with unhandled signal %s\n", $this->watchdogPID, pcntl_sig_name($sig)));
             }
             return true;
         case pcntl_wifstopped($status):
             $sig = pcntl_wstopsig($status);
             $this->logger->warn(sprintf("watchdog %d was stopped with signal %s\n", $this->watchdogPID, pcntl_sig_name($sig)));
             return false;
         default:
             $this->logger->error(sprintf("unexpected status for watchdog %d; exiting\n", $this->childPID));
             exit(1);
     }
 }
Esempio n. 14
0
 /**
  * @param int $childPid
  */
 private function handleQueuedChildSignals(int $childPid)
 {
     if (!isset($this->childSignalHandlers[$childPid], $this->childSignalQueue[$childPid])) {
         return;
     }
     $status = array_shift($this->childSignalQueue[$childPid]);
     if (pcntl_wifexited($status)) {
         $exitCode = pcntl_wexitstatus($status);
         $this->childSignalHandlers[$childPid]($exitCode);
     } elseif (pcntl_wifsignaled($status)) {
         $this->childSignalHandlers[$childPid](0);
     } elseif (pcntl_wifstopped($status)) {
         posix_kill($childPid, SIGCONT);
     }
 }
Esempio n. 15
0
 protected function onSIGCHLD($pid, $status)
 {
     if ($pid <= 0) {
         $this->logger->warn(sprintf('process PID is negative (pid: %s)', $pid));
         return;
     }
     $this->logger->info(sprintf("Childs: (%s)", join(", ", array_keys($this->childs))));
     if (key_exists($pid, $this->childs)) {
         unset($this->childs[$pid]);
         $this->logger->debug(sprintf("Child termination options. " . "wifexited: %d, wifsignaled: %d, wifstopped: %d, stopForking: %d", pcntl_wifexited($status), pcntl_wifsignaled($status), pcntl_wifstopped($status), $this->stopForking));
         // In case of unnormal exit fork new child process
         // 1. status=65280 when child process died with fatal error (set by PHP)
         // 2. exit=9 when child was terminated by parent or by unhandled exception (set by ProcessPool)
         // 3. stopeed by signal
         $crashed = pcntl_wifexited($status) && $status == 65280 || pcntl_wifexited($status) && pcntl_wexitstatus($status) == self::$termExitCode || pcntl_wifsignaled($status);
         if ($crashed) {
             $this->logger->info(sprintf("Child PID: %s crashed (status: %s, wifexited: %s, wifsignaled: %s)", $pid, $status, pcntl_wifexited($status), pcntl_wifsignaled($status)));
         } else {
             $this->logger->info(sprintf("Child PID: %s seems normally terminated (status: %s, wifexited: %s, wifsignaled: %s)", $pid, $status, pcntl_wifexited($status), pcntl_wifsignaled($status)));
         }
         $numTasks = $this->workQueue ? $this->workQueue->capacity() : 0;
         if ($numTasks) {
             $this->logger->info(sprintf("Work queue still has %d unhandled tasks", $numTasks));
         }
         if ($crashed || $numTasks) {
             try {
                 if (!$this->stopForking) {
                     $this->logger->info("Forking new worker process");
                     $this->forkChild(false);
                 } else {
                     $this->logger->info("Flag stopForking=1 prevents new process forking");
                 }
             } catch (Scalr_System_Ipc_Exception $e) {
                 $this->logger->error(sprintf("Cannot fork child. Caught: <%s> %s", get_class($e), $e->getMessage()));
             }
         }
     } else {
         $this->logger->info(sprintf("Child PID: %s is unknown. Known childs: (%s)", $pid, join(",", array_keys($this->childs))));
     }
 }
Esempio n. 16
0
 /**
  * Checks whether the child process is currently stopped
  *
  * @param int $status
  *
  * @return bool
  */
 public function wifstopped(int $status) : bool
 {
     return pcntl_wifstopped($status);
 }
Esempio n. 17
0
 public function isStopped()
 {
     return null !== $this->status && pcntl_wifstopped($this->status);
 }
Esempio n. 18
0
 /**
  *
  * @return boolean
  */
 public function isStopped()
 {
     return \pcntl_wifstopped($this->_code);
 }
Esempio n. 19
0
 /**
  * update the process status
  *
  * @param bool $block
  */
 protected function updateStatus($block = false)
 {
     if ($this->running !== true) {
         return;
     }
     if ($block) {
         $res = pcntl_waitpid($this->pid, $status);
     } else {
         $res = pcntl_waitpid($this->pid, $status, WNOHANG | WUNTRACED);
     }
     if ($res === -1) {
         throw new \RuntimeException('pcntl_waitpid failed. the process maybe available');
     } elseif ($res === 0) {
         $this->running = true;
     } else {
         if (pcntl_wifsignaled($status)) {
             $this->term_signal = pcntl_wtermsig($status);
         }
         if (pcntl_wifstopped($status)) {
             $this->stop_signal = pcntl_wstopsig($status);
         }
         if (pcntl_wifexited($status)) {
             $this->errno = pcntl_wexitstatus($status);
             $this->errmsg = pcntl_strerror($this->errno);
         } else {
             $this->errno = pcntl_get_last_error();
             $this->errmsg = pcntl_strerror($this->errno);
         }
         if (pcntl_wifsignaled($status)) {
             $this->if_signal = true;
         } else {
             $this->if_signal = false;
         }
         $this->running = false;
     }
 }
Esempio n. 20
0
 /**
  * update the process status
  * @param bool $block
  */
 public function updateStatus($block = false)
 {
     if (empty($this->pid)) {
         $message = "the process pid is null, so maybe the process is not started";
         throw new \RuntimeException($message);
     }
     if ($this->running === false) {
         return;
     }
     if ($block) {
         $res = pcntl_waitpid($this->pid, $status);
     } else {
         $res = pcntl_waitpid($this->pid, $status, WNOHANG | WUNTRACED);
     }
     if ($res === -1) {
         $message = "pcntl_waitpid failed. the process maybe available";
         throw new \RuntimeException($message);
     } elseif ($res === 0) {
         $this->running = true;
     } else {
         if (pcntl_wifsignaled($status)) {
             $this->term_signal = pcntl_wtermsig($status);
         }
         if (pcntl_wifstopped($status)) {
             $this->stop_signal = pcntl_wstopsig($status);
         }
         if (pcntl_wifexited($status)) {
             $this->exit_code = pcntl_wexitstatus($status);
         } else {
             $this->errno = pcntl_get_last_error();
             $this->errmsg = pcntl_strerror($this->errno);
         }
         $this->running = false;
     }
 }
Esempio n. 21
0
<?php

$pid = pcntl_fork();
if ($pid == 1) {
    die("failed");
} else {
    if ($pid) {
        $status = 0;
        pcntl_wait($status, WUNTRACED);
        var_dump(pcntl_wifexited($status));
        posix_kill($pid, SIGCONT);
        pcntl_wait($status);
        var_dump(pcntl_wifsignaled($status));
        var_dump(pcntl_wifstopped($status));
        var_dump(pcntl_wexitstatus($status));
        var_dump(pcntl_wait($status, WNOHANG | WUNTRACED));
        var_dump(pcntl_wait());
        var_dump(pcntl_waitpid());
        var_dump(pcntl_wifexited());
        var_dump(pcntl_wifstopped());
        var_dump(pcntl_wifsignaled());
        var_dump(pcntl_wexitstatus());
        var_dump(pcntl_wtermsig());
        var_dump(pcntl_wstopsig());
    } else {
        posix_kill(posix_getpid(), SIGSTOP);
        exit(42);
    }
}
 /**
  * Execute a command.
  *
  * @param $command Command to be run.
  * @param $args Arguments of the command to be run.
  * @param $env Environment variables to be set before running the command.
  * @param $input Data to be sent (piped) to the process. Default to null (no data will be sent to the process).
  * If a string, it will be sent to the process as text. If it is a file or filename, data will be read from the file and
  * sent to the process through the pipe.
  * @param $output Output data. Default to null (no output data will be saved). If it is a filename,
  * output data will be written to the file.
  * @param $timeout Seconds before timing out and aborting execution.
  *
  * @returns Zero if ok, anything else on error.
  */
 function execute($command, $args = NULL, $env = NULL, $input = NULL, $output = NULL, $timeout = ExecutableRunner::DEFAULT_TIMEOUT)
 {
     if ($input != NULL) {
         $pipe_filename = tempnam(sys_get_temp_dir(), 'boca-');
         posix_mkfifo($pipe_filename, 0600);
     }
     $pid = pcntl_fork();
     if ($pid == 0) {
         // Child
         // Redirects stdin to pipe (the client will read data from pipe while the parent will write to it)
         fclose(STDIN);
         if ($input != NULL) {
             $STDIN = fopen($pipe_filename, 'r');
         }
         // Redirects stdout to file
         if ($output != NULL) {
             if (is_resource($output) || is_string($output)) {
                 fclose(STDOUT);
                 fclose(STDERR);
                 if (!is_resource($output)) {
                     $output_file = fopen($output, 'w');
                 } else {
                     $output_file = $output;
                 }
                 $STDOUT = $output_file;
                 $STDERR = $output_file;
             } else {
                 // fwrite($output, );
             }
         }
         // Setup timeout mechanism
         pcntl_signal(SIGALRM, function ($signal) {
             fflush(STDOUT);
             fclose(STDOUT);
             fflush(STDERR);
             fclose(STDERR);
             posix_kill(posix_getpid(), SIGTERM);
         });
         pcntl_alarm($timeout);
         // Configure environment
         $env = array();
         if (!$this->resetEnv) {
             foreach ($_ENV as $key => $value) {
                 $env[$key] = $value;
             }
         }
         foreach ($this->env as $key => $value) {
             $env[$key] = $value;
         }
         // Run command
         if ($args == NULL) {
             pcntl_exec($command);
         } else {
             if ($env == NULL) {
                 // TODO: check what PHP does when pcntl_exec has $args or $env as NULL
                 pcntl_exec($command, $args);
             } else {
                 pcntl_exec($command, $args, $env);
             }
         }
     } else {
         // Parent
         if ($input != NULL) {
             $pipe = fopen($pipe_filename, 'w');
             if (is_resource($input) || is_file($input)) {
                 if (is_file($input)) {
                     $input_file = fopen($input, 'r');
                 } else {
                     $input_file = $input;
                 }
                 $input_data = fread($input_file, filesize($input));
                 fclose($input_file);
             } else {
                 $input_data = $input;
             }
             fwrite($pipe, $input_data);
             fclose($pipe);
         }
     }
     if ($input != NULL) {
         unlink($pipe_filename);
     }
     pcntl_waitpid($pid, $status);
     if (pcntl_wifexited($status)) {
         return pcntl_wexitstatus($status);
     }
     if (pcntl_wifsignaled($status) || pcntl_wifstopped($status)) {
         return -1;
     }
 }