public function execute()
{
$nodes = $this->getNodes();
// TODO: support different keys for each node.
/*
if (Env::get("server.passphrase") === null) {
// Check whether passphrase is required.
$hasPassphrase = false;
$validatingKey = null;
foreach ($nodes as $node) {
if (!$node->useAgent() && $node->isUsedWithPassphrase()) {
$hasPassphrase = true;
$validatingKey = $node->getKeyOrDefault();
}
}
// ask passphrase.
if ($hasPassphrase) {
$passphrase = $this->askPassphrase($validatingKey);
Env::set("server.passphrase", $passphrase);
}
}
*/
foreach ($nodes as $node) {
if (!$node->useAgent() && $node->isUsedWithPassphrase() && !KeyPassphraseMap::getSharedInstance()->hasPassphraseAtKey($node->getKeyOrDefault())) {
$passphrase = $this->askPassphrase($node->getKeyOrDefault());
KeyPassphraseMap::getSharedInstance()->setPassphraseAtKey($node->getKeyOrDefault(), $passphrase);
}
}
// If target nodes count <= 1, It doesn't need to fork processes.
if (count($nodes) === 0) {
$this->doExecute(null);
return;
} elseif (count($nodes) === 1) {
$this->doExecute(reset($nodes));
return;
}
if (!$this->isParallel) {
if ($this->runtimeTask->getOutput()->isVeryVerbose()) {
$this->runtimeTask->getOutput()->writeln("<info>Running serial mode.</info>");
}
foreach ($nodes as $node) {
$this->doExecute($node);
}
return;
}
// Fork process
declare (ticks=1);
pcntl_signal(SIGTERM, array($this, "signalHandler"));
pcntl_signal(SIGINT, array($this, "signalHandler"));
foreach ($nodes as $node) {
$pid = pcntl_fork();
if ($pid === -1) {
// Error
throw new \RuntimeException("Fork Error.");
} else {
if ($pid) {
// Parent process
$this->childPids[$pid] = $node;
} else {
// Child process
if ($this->runtimeTask->getOutput()->isVeryVerbose()) {
$this->runtimeTask->getOutput()->writeln("<info>Forked process for node: </info>" . $node->getName() . " (pid:<comment>" . posix_getpid() . "</comment>)");
}
$this->doExecute($node);
exit(0);
}
}
}
// At the following code, only parent precess runs.
while (count($this->childPids) > 0) {
// Keep to wait until to finish all child processes.
$status = null;
$pid = pcntl_wait($status);
if (!$pid) {
throw new \RuntimeException("pcntl_wait error.");
}
if (!array_key_exists($pid, $this->childPids)) {
throw new \RuntimeException("pcntl_wait error." . $pid);
}
// When a child process is done, removes managed child pid.
$node = $this->childPids[$pid];
unset($this->childPids[$pid]);
}
}