Skip to main content
Drupal API
User account menu
  • Log in

Breadcrumb

  1. Drupal Core 11.1.x
  2. DriverSuspension.php

function DriverSuspension::suspend

Overrides Suspension::suspend

File

vendor/revolt/event-loop/src/EventLoop/Internal/DriverSuspension.php, line 73

Class

DriverSuspension
@internal

Namespace

Revolt\EventLoop\Internal

Code

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();
}
RSS feed
Powered by Drupal