1
0
mirror of https://github.com/danog/amp.git synced 2024-12-12 09:29:45 +01:00
amp/lib/Loop/TracingDriver.php

245 lines
6.4 KiB
PHP
Raw Normal View History

2019-10-01 21:01:44 +02:00
<?php
namespace Amp\Loop;
use function Amp\Internal\formatStacktrace;
2020-11-01 16:43:21 +01:00
final class TracingDriver implements Driver
2019-10-01 21:01:44 +02:00
{
private Driver $driver;
2020-03-28 22:20:44 +01:00
/** @var true[] */
private array $enabledWatchers = [];
2020-03-28 22:20:44 +01:00
/** @var true[] */
private array $unreferencedWatchers = [];
2020-03-28 22:20:44 +01:00
/** @var string[] */
private array $creationTraces = [];
2020-03-28 22:20:44 +01:00
/** @var string[] */
private array $cancelTraces = [];
2019-10-01 21:01:44 +02:00
public function __construct(Driver $driver)
{
$this->driver = $driver;
}
public function run(): void
2019-10-01 21:01:44 +02:00
{
$this->driver->run();
}
public function stop(): void
2019-10-01 21:01:44 +02:00
{
$this->driver->stop();
}
2020-11-01 16:43:21 +01:00
public function isRunning(): bool
{
return $this->driver->isRunning();
}
2019-10-01 21:01:44 +02:00
public function defer(callable $callback, $data = null): string
{
$id = $this->driver->defer(function (...$args) use ($callback) {
$this->cancel($args[0]);
return $callback(...$args);
}, $data);
$this->creationTraces[$id] = formatStacktrace(\debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS));
$this->enabledWatchers[$id] = true;
2019-10-01 21:01:44 +02:00
return $id;
}
public function delay(int $delay, callable $callback, $data = null): string
{
$id = $this->driver->delay($delay, function (...$args) use ($callback) {
$this->cancel($args[0]);
return $callback(...$args);
}, $data);
$this->creationTraces[$id] = formatStacktrace(\debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS));
$this->enabledWatchers[$id] = true;
2019-10-01 21:01:44 +02:00
return $id;
}
public function repeat(int $interval, callable $callback, $data = null): string
{
$id = $this->driver->repeat($interval, $callback, $data);
2019-10-01 21:01:44 +02:00
$this->creationTraces[$id] = formatStacktrace(\debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS));
$this->enabledWatchers[$id] = true;
2019-10-01 21:01:44 +02:00
return $id;
}
public function onReadable($stream, callable $callback, $data = null): string
{
$id = $this->driver->onReadable($stream, $callback, $data);
2019-10-01 21:01:44 +02:00
$this->creationTraces[$id] = formatStacktrace(\debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS));
$this->enabledWatchers[$id] = true;
2019-10-01 21:01:44 +02:00
return $id;
}
public function onWritable($stream, callable $callback, $data = null): string
{
$id = $this->driver->onWritable($stream, $callback, $data);
2019-10-01 21:01:44 +02:00
$this->creationTraces[$id] = formatStacktrace(\debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS));
$this->enabledWatchers[$id] = true;
2019-10-01 21:01:44 +02:00
return $id;
}
public function onSignal(int $signo, callable $callback, $data = null): string
{
$id = $this->driver->onSignal($signo, $callback, $data);
2019-10-01 21:01:44 +02:00
$this->creationTraces[$id] = formatStacktrace(\debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS));
$this->enabledWatchers[$id] = true;
2019-10-01 21:01:44 +02:00
return $id;
}
public function enable(string $watcherId): void
2019-10-01 21:01:44 +02:00
{
try {
$this->driver->enable($watcherId);
$this->enabledWatchers[$watcherId] = true;
} catch (InvalidWatcherError $e) {
throw new InvalidWatcherError(
$watcherId,
$e->getMessage() . "\r\n\r\n" . $this->getTraces($watcherId)
2019-10-01 21:01:44 +02:00
);
}
}
public function cancel(string $watcherId): void
2019-10-01 21:01:44 +02:00
{
$this->driver->cancel($watcherId);
if (!isset($this->cancelTraces[$watcherId])) {
$this->cancelTraces[$watcherId] = formatStacktrace(\debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS));
}
2019-10-01 21:01:44 +02:00
unset($this->enabledWatchers[$watcherId], $this->unreferencedWatchers[$watcherId]);
}
public function disable(string $watcherId): void
2019-10-01 21:01:44 +02:00
{
$this->driver->disable($watcherId);
unset($this->enabledWatchers[$watcherId]);
}
public function reference(string $watcherId): void
2019-10-01 21:01:44 +02:00
{
try {
$this->driver->reference($watcherId);
unset($this->unreferencedWatchers[$watcherId]);
} catch (InvalidWatcherError $e) {
throw new InvalidWatcherError(
$watcherId,
$e->getMessage() . "\r\n\r\n" . $this->getTraces($watcherId)
2019-10-01 21:01:44 +02:00
);
}
}
public function unreference(string $watcherId): void
2019-10-01 21:01:44 +02:00
{
$this->driver->unreference($watcherId);
$this->unreferencedWatchers[$watcherId] = true;
}
public function setErrorHandler(callable $callback = null): ?callable
2019-10-01 21:01:44 +02:00
{
return $this->driver->setErrorHandler($callback);
}
/** @inheritdoc */
public function getHandle()
{
$this->driver->getHandle();
}
public function dump(): string
{
$dump = "Enabled, referenced watchers keeping the loop running: ";
foreach ($this->enabledWatchers as $watcher => $_) {
if (isset($this->unreferencedWatchers[$watcher])) {
continue;
}
$dump .= "Watcher ID: " . $watcher . "\r\n";
$dump .= $this->getCreationTrace($watcher);
$dump .= "\r\n\r\n";
}
return \rtrim($dump);
}
public function getInfo(): array
{
return $this->driver->getInfo();
}
public function __debugInfo(): array
{
return $this->driver->__debugInfo();
}
public function now(): int
{
return $this->driver->now();
}
protected function error(\Throwable $exception): void
{
$this->driver->error($exception);
}
private function getTraces(string $watcherId): string
{
return "Creation Trace:\r\n" . $this->getCreationTrace($watcherId) . "\r\n\r\n" .
"Cancellation Trace:\r\n" . $this->getCancelTrace($watcherId);
}
2019-10-01 21:01:44 +02:00
private function getCreationTrace(string $watcher): string
{
if (!isset($this->creationTraces[$watcher])) {
return 'No creation trace, yet.';
2019-10-01 21:01:44 +02:00
}
return $this->creationTraces[$watcher];
}
private function getCancelTrace(string $watcher): string
{
if (!isset($this->cancelTraces[$watcher])) {
return 'No cancellation trace, yet.';
2019-10-01 21:01:44 +02:00
}
return $this->cancelTraces[$watcher];
}
2020-11-01 16:43:21 +01:00
public function setState(string $key, mixed $value): void
{
$this->driver->setState($key, $value);
}
public function getState(string $key): mixed
{
return $this->driver->getState($key);
}
public function clear(): void
{
$this->driver->clear();
}
2019-10-01 21:01:44 +02:00
}