private function resolveFuture($key, Future $future) { $result = $future->resolve(); $master = $this->getMaster(); $master->write(array('type' => 'RSLV', 'key' => $key, 'err' => $result[0], 'stdout' => $result[1], 'stderr' => $result[2])); unset($this->exec[$key]); }
public final function loadFileContentFromFuture(Future $future) { if ($this->timeout) { $future->setTimeout($this->timeout); } if ($this->getByteLimit()) { $future->setStdoutSizeLimit($this->getByteLimit()); } try { $file_content = $this->executeQueryFromFuture($future); } catch (CommandException $ex) { if (!$future->getWasKilledByTimeout()) { throw $ex; } $message = pht('<Attempt to load this file was terminated after %s second(s).>', $this->timeout); $file_content = new DiffusionFileContent(); $file_content->setCorpus($message); } $this->fileContent = $file_content; $repository = $this->getRequest()->getRepository(); $try_encoding = $repository->getDetail('encoding'); if ($try_encoding) { $this->fileContent->setCorpus(phutil_utf8_convert($this->fileContent->getCorpus(), 'UTF-8', $try_encoding)); } return $this->fileContent; }
protected function executeQueryFromFuture(Future $future) { list($corpus) = $future->resolvex(); $file_content = new DiffusionFileContent(); $file_content->setCorpus($corpus); return $file_content; }
protected function resolveFuture($path, Future $future) { list($rc, $stdout) = $future->resolve(); $lines = explode("\n", $stdout); $messages = array(); foreach ($lines as $line) { $matches = null; if (!preg_match('/^(.*?):(\\d+):(\\d+): (\\S+) (.*)$/', $line, $matches)) { continue; } foreach ($matches as $key => $match) { $matches[$key] = trim($match); } if (!$this->isMessageEnabled($matches[4])) { continue; } $message = new ArcanistLintMessage(); $message->setPath($path); $message->setLine($matches[2]); $message->setChar($matches[3]); $message->setCode($matches[4]); $message->setName('PEP8 ' . $matches[4]); $message->setDescription($matches[5]); $message->setSeverity(ArcanistLintSeverity::SEVERITY_WARNING); $this->addLintMessage($message); } }
public function then($onComplete, $onError = null) { if (!is_callable($onComplete)) { $onComplete = null; } if (!is_callable($onError)) { $onError = null; } if ($onComplete !== null || $onError !== null) { if ($onComplete !== null && $this->status === Future::FULFILLED) { $x = $this->result; if ($x instanceof Future) { if ($x === $this) { throw new \Exception('Self resolution'); } return $x->then($onComplete, $onError); } return Future::create($onComplete, $x); } if ($onError !== null && $this->status === Future::REJECTED) { return Future::create($onError, $this->error); } $this->callbacks[] = array($onComplete, $onError); } return $this; }
protected function executeQueryFromFuture(Future $future) { try { list($corpus) = $future->resolvex(); } catch (CommandException $ex) { $stderr = $ex->getStdErr(); if (preg_match('/path not found$/', trim($stderr))) { // TODO: Improve user experience for this. One way to end up here // is to have the parser behind and look at a file which was recently // nuked; Diffusion will think it still exists and try to grab content // at HEAD. throw new Exception(pht('Failed to retrieve file content from Subversion. The file may ' . 'have been recently deleted, or the Diffusion cache may be out of ' . 'date.')); } else { throw $ex; } } $file_content = new DiffusionFileContent(); $file_content->setCorpus($corpus); return $file_content; }
public function __construct($executor = null) { parent::__construct(); if (is_callable($executor)) { $self = $this; call_user_func($executor, function ($value) use($self) { $self->resolve($value); }, function ($reason) use($self) { $self->reject($reason); }); } }
public function completeError($error) { if ($this->future->status === Future::PENDING) { $this->future->status = Future::REJECTED; $this->future->error = $error; while (count($this->future->callbacks) > 0) { $callback = array_shift($this->future->callbacks); if ($callback[1] !== null) { $result = Future::create($callback[1], $error); break; } } if (count($this->future->callbacks) > 0) { do { $callback = array_shift($this->future->callbacks); $result = $this->resolve($callback[0], $callback[1], $result); } while (count($this->future->callbacks) > 0); } } }
/** * @task iterator */ public function next() { $this->key = null; if (!count($this->wait)) { return; } $read_sockets = array(); $write_sockets = array(); $start = microtime(true); $timeout = $this->timeout; $this->isTimeout = false; $check = $this->getWorkingSet(); $resolve = null; do { $read_sockets = array(); $write_sockets = array(); $can_use_sockets = true; $wait_time = 1; foreach ($check as $wait => $key) { $future = $this->futures[$key]; try { if ($future->getException()) { $resolve = $wait; continue; } if ($future->isReady()) { if ($resolve === null) { $resolve = $wait; } continue; } $got_sockets = false; $socks = $future->getReadSockets(); if ($socks) { $got_sockets = true; foreach ($socks as $socket) { $read_sockets[] = $socket; } } $socks = $future->getWriteSockets(); if ($socks) { $got_sockets = true; foreach ($socks as $socket) { $write_sockets[] = $socket; } } // If any currently active future had neither read nor write sockets, // we can't wait for the current batch of items using sockets. if (!$got_sockets) { $can_use_sockets = false; } else { $wait_time = min($wait_time, $future->getDefaultWait()); } } catch (Exception $ex) { $this->futures[$key]->setException($ex); $resolve = $wait; break; } } if ($resolve === null) { // Check for a setUpdateInterval() timeout. if ($timeout !== null) { $elapsed = microtime(true) - $start; if ($elapsed > $timeout) { $this->isTimeout = true; return; } else { $wait_time = $timeout - $elapsed; } } if ($can_use_sockets) { Future::waitForSockets($read_sockets, $write_sockets, $wait_time); } else { usleep(1000); } } } while ($resolve === null); $this->key = $this->wait[$resolve]; unset($this->wait[$resolve]); $this->updateWorkingSet(); }
/** * {@inheritdoc} */ public function reject(\Throwable $reason) { parent::reject($reason); }
/** * {@inheritdoc} */ public function reject($reason = null) { parent::reject($reason); }
function settle($array) { return toFuture($array)->then(function ($array) { $keys = array_keys($array); $n = count($array); $result = array(); if ($n === 0) { return value($result); } $future = new Future(); $oncomplete = function ($index, $f) use($future, &$result, &$n, $keys) { return function () use($index, $f, $future, &$result, &$n, $keys) { $result[$index] = $f->inspect(); if (--$n === 0) { $array = array(); foreach ($keys as $key) { $array[$key] = $result[$key]; } $future->resolve($array); } }; }; foreach ($array as $index => $element) { $f = toFuture($element); $f->whenComplete($oncomplete($index, $f)); } return $future; }); }
/** * {@inheritdoc} */ public function cancel(Throwable $reason = null) { if (null === $reason) { $reason = new TerminatedException(); } if (null !== $this->generator) { try { do { if ($this->current instanceof Awaitable) { $this->current->cancel($reason); } $this->current = $this->generator->throw($reason); } while ($this->generator->valid()); } catch (Throwable $exception) { $reason = $exception; } } parent::cancel($reason); }
protected final function resolveFuture($path, Future $future) { list($err, $stdout, $stderr) = $future->resolve(); if ($err) { $future->resolvex(); } $messages = $this->parseLinterOutput($path, $err, $stdout, $stderr); if ($messages === false) { if ($err) { $future->resolvex(); } else { throw new Exception(sprintf("%s\n\nSTDOUT\n%s\n\nSTDERR\n%s", pht('Linter failed to parse output!'), $stdout, $stderr)); } } foreach ($messages as $message) { $this->addLintMessage($message); } }
} public function getResult() { return $this->synchronized(function () { while (!$this->result) { $this->wait(); } return $this->result; }); } public static function of(Closure $closure, array $args = []) { $future = new self($closure, $args); $future->start(); return $future; } protected $owner; protected $closure; protected $args; protected $result; } /* some data */ $test = ["Hello", "World"]; /* a closure to execute in background and foreground */ $closure = function ($test) { return $test; }; /* make call in background thread */ $future = Future::of($closure, [$test]); /* get result of background and foreground call */ var_dump($future->getResult(), $closure($test));
/** * Resolve a command, returning its exit code, stdout, and stderr. See also * @{function:exec_manual}. For stronger error-checking behavior, see * @{method:resolvex} and @{method:resolveJSON}. * * list($err, $stdout, $stderr) = $future->resolve(); * * @param float Optional timeout after which resolution will pause and * execution will return to the caller. * @return list <$err, $stdout, $stderr> list. * @task resolve */ public function resolve($timeout = null) { if (null === $timeout) { $timeout = $this->timeout; } return parent::resolve($timeout); }
protected function resolveFuture(HarbormasterBuild $build, HarbormasterBuildTarget $target, Future $future) { $futures = new FutureIterator(array($future)); foreach ($futures->setUpdateInterval(5) as $key => $future) { if ($future === null) { $build->reload(); if ($this->shouldAbort($build, $target)) { throw new HarbormasterBuildAbortedException(); } } else { return $future->resolve(); } } }
protected function resolveFileContentFuture(Future $future) { list($corpus) = $future->resolvex(); return $corpus; }
protected function resolveFuture($package, Future $future) { list($err, $stdout, $stderr) = $future->resolve(); $parser = new ArcanistGoTestResultParser(); $messages = $parser->parseTestResults($package, $stdout, $stderr); if ($messages === false) { if ($err) { $future->resolvex(); } else { throw new Exception(sprintf("%s\n\nSTDOUT\n%s\n\nSTDERR\n%s", pht('GoTestEngine failed to parse result!'), $stdout, $stderr)); } } return $messages; }
/** * {@inheritdoc} */ public function cancel(Throwable $reason = null) { if (!$this->isPending()) { return; } if (null === $reason) { $reason = new TerminatedException(); } parent::cancel($reason); if ($this->current instanceof Awaitable) { $this->current->cancel($reason); // Will continue execution by throwing into the generator. } }
protected final function resolveFuture($path, Future $future) { list($err, $stdout, $stderr) = $future->resolve(); if ($err && !$this->shouldExpectCommandErrors()) { $future->resolvex(); } $messages = $this->parseLinterOutput($path, $err, $stdout, $stderr); if ($messages === false) { if ($err) { $future->resolvex(); } else { throw new Exception("Linter failed to parse output!\n\n{$stdout}\n\n{$stderr}"); } } foreach ($messages as $message) { $this->addLintMessage($message); } }
/** * {@inheritdoc} */ public function cancel(Throwable $reason = null) { if (null === $reason) { $reason = new TerminatedException(); } if ($this->current instanceof Awaitable) { $this->current->cancel($reason); } try { $this->generator = null; // finally blocks may throw from force-closed Generator. } catch (Throwable $exception) { $reason = $exception; } parent::cancel($reason); }
public function getDefaultWait() { $wait = parent::getDefaultWait(); if ($this->timeout) { if (!$this->start) { $this->start = microtime(true); } $elapsed = microtime(true) - $this->start; $wait = max(0, min($this->timeout - $elapsed, $wait)); } return $wait; }
/** * {@inheritdoc} */ public function cancel($reason = null) { if (null !== $this->generator) { $current = $this->generator->current(); // Get last yielded value. if ($current instanceof Awaitable) { $current->cancel($reason); // Cancel last yielded awaitable. } try { $this->close(); // Throwing finally blocks in the Generator may cause close() to throw. } catch (Throwable $exception) { $reason = $exception; } } parent::cancel($reason); }
public function publish($topic, array $options = array()) { $this->checkPushService(); if (is_array($topic)) { foreach ($topic as $t) { $this->publish($t, $options); } return $this; } $self = $this; $timeout = isset($options['timeout']) ? $options['timeout'] : $this->timeout; $heartbeat = isset($options['heartbeat']) ? $options['heartbeat'] : $this->heartbeat; $this->topics[$topic] = new ArrayObject(); return $this->addFunction(function ($id) use($self, $topic, $timeout, $heartbeat) { $topics = $self->getTopics($topic); if (isset($topics[$id])) { if ($topics[$id]->count < 0) { $topics[$id]->count = 0; } $messages = $topics[$id]->messages; if (!$messages->isEmpty()) { $message = $messages->shift(); $message->detector->resolve(true); $self->resetTimer($topics, $topic, $id); return $message->result; } else { $self->delTimer($topics, $id); $topics[$id]->count++; } } else { $topics[$id] = new stdClass(); $topics[$id]->messages = new SplQueue(); $topics[$id]->count = 1; $topics[$id]->heartbeat = $heartbeat; $this->timer->setImmediate(function () use($self, $topic, $id) { $onSubscribe = $self->onSubscribe; if (is_callable($onSubscribe)) { call_user_func($onSubscribe, $topic, $id, $self); } }); } if (isset($topics[$id]->request)) { $topics[$id]->request->resolve(null); } $request = new Future(); $request->complete(function () use($topics, $id) { $topics[$id]->count--; }); $topics[$id]->request = $request; return $self->setRequestTimer($topic, $id, $request, $timeout); }, $topic); }
/** * Wait for activity on one of several sockets. * * @param list List of sockets expected to become readable. * @param list List of sockets expected to become writable. * @param float Timeout, in seconds. * @return void */ public static function waitForSockets(array $read_list, array $write_list, $timeout = 1) { if (!self::$handlerInstalled) { // If we're spawning child processes, we need to install a signal handler // here to catch cases like execing '(sleep 60 &) &' where the child // exits but a socket is kept open. But we don't actually need to do // anything because the SIGCHLD will interrupt the stream_select(), as // long as we have a handler registered. if (function_exists('pcntl_signal')) { if (!pcntl_signal(SIGCHLD, array('Future', 'handleSIGCHLD'))) { throw new Exception('Failed to install signal handler!'); } } self::$handlerInstalled = true; } $timeout_sec = (int) $timeout; $timeout_usec = (int) (1000000 * ($timeout - $timeout_sec)); $exceptfds = array(); $ok = @stream_select($read_list, $write_list, $exceptfds, $timeout, $timeout_usec); if ($ok === false) { // Hopefully, means we received a SIGCHLD. In the worst case, we degrade // to a busy wait. } }
protected function resolveFuture(Future $future) { list($stdout) = $future->resolvex(); $all_results = json_decode($stdout); foreach ($all_results as $results) { if ($results === null || $results->Issues === null) { return; } foreach ($results->Issues as $issue) { $message = new ArcanistLintMessage(); $message->setPath($results->FileName); $message->setLine($issue->LineNumber); $message->setCode($issue->Index->Code); $message->setName($issue->Index->Name); $message->setChar($issue->Column); $message->setOriginalText($issue->OriginalText); $message->setReplacementText($issue->ReplacementText); $desc = @vsprintf($issue->Index->Message, $issue->Parameters); if ($desc === false) { $desc = $issue->Index->Message; } $message->setDescription($desc); $severity = ArcanistLintSeverity::SEVERITY_ADVICE; switch ($issue->Index->Severity) { case 0: $severity = ArcanistLintSeverity::SEVERITY_ADVICE; break; case 1: $severity = ArcanistLintSeverity::SEVERITY_AUTOFIX; break; case 2: $severity = ArcanistLintSeverity::SEVERITY_WARNING; break; case 3: $severity = ArcanistLintSeverity::SEVERITY_ERROR; break; case 4: $severity = ArcanistLintSeverity::SEVERITY_DISABLED; break; } $severity_override = $this->getLintMessageSeverity($issue->Index->Code); if ($severity_override !== null) { $severity = $severity_override; } $message->setSeverity($severity); $this->addLintMessage($message); } } }
protected final function resolveFuture($path, Future $future) { list($err, $stdout, $stderr) = $future->resolve(); if ($err && !$this->shouldExpectCommandErrors()) { $future->resolvex(); } $messages = $this->parseLinterOutput($path, $err, $stdout, $stderr); if ($err && $this->shouldExpectCommandErrors() && !$messages) { // We assume that if the future exits with a non-zero status and we // failed to parse any linter messages, then something must've gone wrong // during parsing. $messages = false; } if ($messages === false) { if ($err) { $future->resolvex(); } else { throw new Exception(sprintf("%s\n\nSTDOUT\n%s\n\nSTDERR\n%s", pht('Linter failed to parse output!'), $stdout, $stderr)); } } foreach ($messages as $message) { $this->addLintMessage($message); } }