Skip to content

Commit 25de49a

Browse files
committed
Fix unsetting {main} suspension
1 parent fce6063 commit 25de49a

File tree

2 files changed

+12
-5
lines changed

2 files changed

+12
-5
lines changed

src/EventLoop/Internal/AbstractDriver.php

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ abstract class AbstractDriver implements Driver
6161
private bool $idle = false;
6262
private bool $stopped = false;
6363

64+
/** @var \WeakMap<object, \WeakReference<DriverSuspension>> */
6465
private \WeakMap $suspensions;
6566

6667
public function __construct()
@@ -291,8 +292,10 @@ public function getSuspension(): Suspension
291292
// User callbacks are always executed outside the event loop fiber, so this should always be false.
292293
\assert($fiber !== $this->fiber);
293294

294-
// Use current object in case of {main}
295-
$suspension = ($this->suspensions[$fiber ?? $this] ?? null)?->get();
295+
// Use queue closure in case of {main}, which can be unset by DriverSuspension after an uncaught exception.
296+
$key = $fiber ?? $this->queueCallback;
297+
298+
$suspension = ($this->suspensions[$key] ?? null)?->get();
296299
if ($suspension) {
297300
return $suspension;
298301
}
@@ -304,7 +307,7 @@ public function getSuspension(): Suspension
304307
$this->suspensions,
305308
);
306309

307-
$this->suspensions[$fiber ?? $this] = \WeakReference::create($suspension);
310+
$this->suspensions[$key] = \WeakReference::create($suspension);
308311

309312
return $suspension;
310313
}
@@ -395,7 +398,6 @@ final protected function error(\Closure $closure, \Throwable $exception): void
395398
$this->interrupt = static fn () => $exception instanceof UncaughtThrowable
396399
? throw $exception
397400
: throw UncaughtThrowable::throwingCallback($closure, $exception);
398-
unset($this->suspensions[$this]); // Remove suspension for {main}
399401
return;
400402
}
401403

@@ -629,7 +631,6 @@ private function createErrorCallback(): void
629631
$this->interrupt = static fn () => $exception instanceof UncaughtThrowable
630632
? throw $exception
631633
: throw UncaughtThrowable::throwingErrorHandler($errorHandler, $exception);
632-
unset($this->suspensions[$this]); // Remove suspension for {main}
633634
}
634635
};
635636
}

src/EventLoop/Internal/DriverSuspension.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ final class DriverSuspension implements Suspension
2727

2828
private bool $deadMain = false;
2929

30+
/**
31+
* @param \WeakMap<object, \WeakReference<DriverSuspension>> $suspensions
32+
*/
3033
public function __construct(
3134
private readonly \Closure $run,
3235
private readonly \Closure $queue,
@@ -118,6 +121,9 @@ public function suspend(): mixed
118121
// This is now a dead {main} suspension.
119122
$this->deadMain = true;
120123

124+
// Unset suspension for {main} using queue closure.
125+
unset($this->suspensions[$this->queue]);
126+
121127
$result && $result(); // Unwrap any uncaught exceptions from the event loop
122128

123129
\gc_collect_cycles(); // Collect any circular references before dumping pending suspensions.

0 commit comments

Comments
 (0)