From 3a0d80710ddbe308c10682b5fb3dec2dd364f758 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Sat, 28 Feb 2026 07:11:13 +0100 Subject: [PATCH] support suspend calls that don't actually suspend --- src/hxcoro/Coro.hx | 15 ++++++--------- .../continuations/CancellingContinuation.hx | 15 ++++++--------- src/hxcoro/continuations/RacingContinuation.hx | 8 ++++---- 3 files changed, 16 insertions(+), 22 deletions(-) diff --git a/src/hxcoro/Coro.hx b/src/hxcoro/Coro.hx index ca4b2d04..63e54768 100644 --- a/src/hxcoro/Coro.hx +++ b/src/hxcoro/Coro.hx @@ -2,7 +2,6 @@ package hxcoro; import haxe.coro.IContinuation; import haxe.coro.SuspensionResult; -import haxe.coro.context.ExceptionHandler; import haxe.coro.dispatchers.Dispatcher; import haxe.exceptions.ArgumentException; import haxe.exceptions.CancellationException; @@ -16,27 +15,25 @@ import hxcoro.task.NodeLambda; private typedef SuspendCancellableFunc = IContinuation -> Null<(CancellationException -> Void)>; class Coro { - @:coroutine(transformed, outcome = { noThrow: true, noReturn: true }) + @:coroutine(transformed) public static function suspend(completion:IContinuation, func:IContinuation->Void):SuspensionResult { var safe = new RacingContinuation(completion); func(safe); - safe.resolve(); - return cast SuspensionResult.suspended; + return safe.resolve(); } /** * Suspends a coroutine which will be automatically resumed with a `haxe.exceptions.CancellationException` when cancelled. * If `func` returns a callback, it is registered to be invoked on cancellation allowing the easy cleanup of resources. */ - @:coroutine(transformed, outcome = { noThrow: true, noReturn: true }) + @:coroutine(transformed) public static function suspendCancellable(completion:IContinuation, func:SuspendCancellableFunc):SuspensionResult { var safe = new CancellingContinuation(completion); final onCancellationRequested = func(safe); if (onCancellationRequested != null) { safe.onCancellationRequested = onCancellationRequested; } - safe.resolve(); - return cast SuspensionResult.suspended; + return safe.resolve(); } static function delayImpl(ms:Int, cont:IContinuation) { @@ -48,12 +45,12 @@ class Coro { } } - @:coroutine(outcome = { noThrow: true, noReturn: true }, assert = { numStates: 1}) + @:coroutine(assert = { numStates: 1}) public static function delay(ms:Int):Void { suspendCancellable(cont -> delayImpl(ms, cont)); } - @:coroutine(outcome = { noThrow: true, noReturn: true }, assert = { numStates: 1}) + @:coroutine(assert = { numStates: 1}) public static function yield():Void { suspendCancellable(cont -> delayImpl(0, cont)); } diff --git a/src/hxcoro/continuations/CancellingContinuation.hx b/src/hxcoro/continuations/CancellingContinuation.hx index 8a1edafb..0e97465a 100644 --- a/src/hxcoro/continuations/CancellingContinuation.hx +++ b/src/hxcoro/continuations/CancellingContinuation.hx @@ -1,12 +1,11 @@ package hxcoro.continuations; import haxe.Exception; -import haxe.coro.IContinuation; +import haxe.coro.SuspensionResult; import haxe.coro.cancellation.CancellationToken; import haxe.coro.cancellation.ICancellationCallback; import haxe.coro.cancellation.ICancellationHandle; import haxe.coro.cancellation.ICancellationToken; -import haxe.coro.dispatchers.Dispatcher; import haxe.coro.dispatchers.IDispatchObject; import haxe.exceptions.CancellationException; import hxcoro.concurrent.AtomicInt; @@ -103,16 +102,14 @@ class CancellingContinuation extends StackFrameContinuation implements ICa } } - public function resolve():Void { - if (resumeState.compareExchange(Active, Resolved) != Active) { + public function resolve():SuspensionResult { + if (resumeState.compareExchange(Active, Resolved) == Active) { + return cast SuspensionResult.suspended; + } else { while (resumeState.load() == Completing) { BackOff.backOff(); } - // Resume (or cancellation) beat resolve(). Dispatch so that onDispatch() → - // cont.resume() is always called, regardless of whether the caller was a - // BaseContinuation state machine or a plain lambda (where an inline Returned - // result would be silently discarded on multi-threaded targets). - context.dispatchOrCall(this); + return this; } } diff --git a/src/hxcoro/continuations/RacingContinuation.hx b/src/hxcoro/continuations/RacingContinuation.hx index 935283d9..1f4b224d 100644 --- a/src/hxcoro/continuations/RacingContinuation.hx +++ b/src/hxcoro/continuations/RacingContinuation.hx @@ -2,7 +2,7 @@ package hxcoro.continuations; import haxe.Exception; import haxe.coro.IContinuation; -import haxe.coro.dispatchers.Dispatcher; +import haxe.coro.SuspensionResult; import haxe.coro.dispatchers.IDispatchObject; import hxcoro.concurrent.AtomicInt; @@ -29,11 +29,11 @@ class RacingContinuation extends StackFrameContinuation implements IDispat } } - public function resolve():Void { + public function resolve():SuspensionResult { if (resumeState.compareExchange(Active, Resolved) == Active) { - state = Pending; + return cast SuspensionResult.suspended; } else { - context.dispatchOrCall(this); + return this; } }