11<?php
22
3+ /** @noinspection PhpPropertyOnlyWrittenInspection */
4+
35declare (strict_types=1 );
46
57namespace Revolt \EventLoop \Internal ;
@@ -46,7 +48,12 @@ public function resume(mixed $value = null): void
4648 $ fiber = $ this ->fiberRef ?->get();
4749
4850 if ($ fiber ) {
49- ($ this ->queue )($ fiber ->resume (...), $ value );
51+ ($ this ->queue )(static function () use ($ fiber , $ value ): void {
52+ // The fiber may be destroyed with suspension as part of the GC cycle collector.
53+ if (!$ fiber ->isTerminated ()) {
54+ $ fiber ->resume ($ value );
55+ }
56+ });
5057 } else {
5158 // Suspend event loop fiber to {main}.
5259 ($ this ->interrupt )(static fn () => $ value );
@@ -72,15 +79,20 @@ public function suspend(): mixed
7279 $ this ->suspendedFiber = $ fiber ;
7380
7481 try {
75- return \Fiber::suspend ();
82+ $ value = \Fiber::suspend ();
83+ $ this ->suspendedFiber = null ;
7684 } catch (\FiberError $ exception ) {
7785 $ this ->pending = false ;
86+ $ this ->suspendedFiber = null ;
7887 $ this ->fiberError = $ exception ;
7988
8089 throw $ exception ;
81- } finally {
82- $ this ->suspendedFiber = null ;
8390 }
91+
92+ // Setting $this->suspendedFiber = null in finally will set the fiber to null if a fiber is destroyed
93+ // as part of a cycle collection, causing an error if the suspension is subsequently resumed.
94+
95+ return $ value ;
8496 }
8597
8698 // Awaiting from {main}.
@@ -125,7 +137,12 @@ public function throw(\Throwable $throwable): void
125137 $ fiber = $ this ->fiberRef ?->get();
126138
127139 if ($ fiber ) {
128- ($ this ->queue )($ fiber ->throw (...), $ throwable );
140+ ($ this ->queue )(static function () use ($ fiber , $ throwable ): void {
141+ // The fiber may be destroyed with suspension as part of the GC cycle collector.
142+ if (!$ fiber ->isTerminated ()) {
143+ $ fiber ->throw ($ throwable );
144+ }
145+ });
129146 } else {
130147 // Suspend event loop fiber to {main}.
131148 ($ this ->interrupt )(static fn () => throw $ throwable );
0 commit comments