function DriverSuspension::suspend
Overrides Suspension::suspend
File
-
vendor/
revolt/ event-loop/ src/ EventLoop/ Internal/ DriverSuspension.php, line 73
Class
- DriverSuspension
- @internal
Namespace
Revolt\EventLoop\InternalCode
public function suspend() : mixed {
// Throw exception when trying to use old dead {main} suspension
if ($this->deadMain) {
throw new \Error('Suspension cannot be suspended after an uncaught exception is thrown from the event loop');
}
if ($this->pending) {
throw new \Error('Must call resume() or throw() before calling suspend() again');
}
$fiber = $this->fiberRef?->get();
if ($fiber !== \Fiber::getCurrent()) {
throw new \Error('Must not call suspend() from another fiber');
}
$this->pending = true;
$this->error = null;
// Awaiting from within a fiber.
if ($fiber) {
$this->suspendedFiber = $fiber;
try {
$value = \Fiber::suspend();
$this->suspendedFiber = null;
} catch (\FiberError $error) {
$this->pending = false;
$this->suspendedFiber = null;
$this->error = $error;
throw $error;
}
// Setting $this->suspendedFiber = null in finally will set the fiber to null if a fiber is destroyed
// as part of a cycle collection, causing an error if the suspension is subsequently resumed.
return $value;
}
// Awaiting from {main}.
$result = ($this->run)();
/** @psalm-suppress RedundantCondition $this->pending should be changed when resumed. */
if ($this->pending) {
// This is now a dead {main} suspension.
$this->deadMain = true;
// Unset suspension for {main} using queue closure.
unset($this->suspensions[$this->queue]);
$result && $result();
// Unwrap any uncaught exceptions from the event loop
\gc_collect_cycles();
// Collect any circular references before dumping pending suspensions.
$info = '';
foreach ($this->suspensions as $suspensionRef) {
if ($suspension = $suspensionRef->get()) {
\assert($suspension instanceof self);
$fiber = $suspension->fiberRef?->get();
if ($fiber === null) {
continue;
}
$reflectionFiber = new \ReflectionFiber($fiber);
$info .= "\n\n" . $this->formatStacktrace($reflectionFiber->getTrace(\DEBUG_BACKTRACE_IGNORE_ARGS));
}
}
throw new \Error('Event loop terminated without resuming the current suspension (the cause is either a fiber deadlock, or an incorrectly unreferenced/canceled watcher):' . $info);
}
return $result();
}