Skip to content

Commit

Permalink
Add stack trace to all current suspensions on early exit (#46)
Browse files Browse the repository at this point in the history
  • Loading branch information
kelunik authored Feb 3, 2022
1 parent 487dfb4 commit 985d239
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 3 deletions.
3 changes: 2 additions & 1 deletion src/EventLoop/Internal/AbstractDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,8 @@ public function getSuspension(): Suspension
return $this->suspensions[$fiber ?? $this] ??= new DriverSuspension(
$this->runCallback,
$this->queueCallback,
$this->interruptCallback
$this->interruptCallback,
$this->suspensions
);
}

Expand Down
39 changes: 37 additions & 2 deletions src/EventLoop/Internal/DriverSuspension.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,22 @@ final class DriverSuspension implements Suspension

private bool $pending = false;

private \WeakReference $suspensions;

/**
* @param \Closure $run
* @param \Closure $queue
* @param \Closure $interrupt
*
* @internal
*/
public function __construct(\Closure $run, \Closure $queue, \Closure $interrupt)
public function __construct(\Closure $run, \Closure $queue, \Closure $interrupt, \WeakMap $suspensions)
{
$this->run = $run;
$this->queue = $queue;
$this->interrupt = $interrupt;
$this->fiber = \Fiber::getCurrent();
$this->suspensions = \WeakReference::create($suspensions);
}

public function resume(mixed $value = null): void
Expand Down Expand Up @@ -87,7 +90,22 @@ public function suspend(): mixed
$this->pending = false;
$result && $result(); // Unwrap any uncaught exceptions from the event loop

throw new \Error('Event loop terminated without resuming the current suspension');
$info = '';
$suspensions = $this->suspensions->get();
if ($suspensions) {
\gc_collect_cycles();

foreach ($suspensions as $suspension) {
if ($suspension->fiber === null) {
continue;
}

$reflectionFiber = new \ReflectionFiber($suspension->fiber);
$info .= "\n\n" . $this->formatStacktrace($reflectionFiber->getTrace(\DEBUG_BACKTRACE_IGNORE_ARGS));
}
}

throw new \Error('Event loop terminated without resuming the current suspension:' . $info);
}

return $result();
Expand All @@ -108,4 +126,21 @@ public function throw(\Throwable $throwable): void
($this->interrupt)(static fn () => throw $throwable);
}
}

private function formatStacktrace(array $trace): string
{
return \implode("\n", \array_map(static function ($e, $i) {
$line = "#{$i} ";

if (isset($e["file"])) {
$line .= "{$e['file']}:{$e['line']} ";
}

if (isset($e["class"], $e["type"])) {
$line .= $e["class"] . $e["type"];
}

return $line . $e["function"] . "()";
}, $trace, \array_keys($trace)));
}
}

0 comments on commit 985d239

Please sign in to comment.