Fixed cancelled ReadAsync/WriteAsync throwing the exception of the native operation instead of an OperationCanceledException - #2067
Open
adutton wants to merge 1 commit into
Conversation
…tive operation instead of an OperationCanceledException (dlemstra#2066).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Fixes #2066.
Since 14.15.0 (when the
AsyncStreamWrapperwas introduced), cancellingReadAsync/WriteAsyncstream operations throws the exception of the native operation instead of anOperationCanceledException. For a cancelled JPEG write that is:The cause: when the token is cancelled, the async pump loops set
_exceptionThrownand the blocked native callback reports a failed read/write, which makes the native coder raise an error that propagates out of the action task. The existing conversion at the end ofReadAsync(Action, ...)/WriteAsync(Action, ...):is unreachable in that case because
await Task.WhenAll(...)rethrows the action task's exception first.This change wraps the
Task.WhenAllin atry/catch when (_exceptionThrown)that callsThrowIfCancellationRequested()(and rethrows the original exception when the failure was not caused by a cancellation, preserving the current behavior for stream exceptions).The existing cancellation tests did not catch this because their test actions ignore the failed read/write result; the native coders throw in that situation. The new tests mirror the existing ones but throw from the action when the operation fails, plus end-to-end tests on
MagickImage.ReadAsync(Stream)/WriteAsync(Stream)with a cancelled token.Verified with the Q8 x64 net8.0 test suite on Windows: all tests pass with the fix; the four new tests fail without it (they reproduce the exact exceptions from #2066).