Fix flaky AsyncContinuation cDAC dump test on osx-arm64 by using Task.Yield#128004
Merged
max-charlamb merged 1 commit intoMay 10, 2026
Merged
Conversation
Contributor
|
Tagging subscribers to this area: @steveisok, @tommcdon, @dotnet/dotnet-diag |
Contributor
There was a problem hiding this comment.
Pull request overview
This PR updates the AsyncContinuation cDAC dump test debuggee to make async suspension deterministic, avoiding intermittent failures where the AsyncDispatcherInfo type hasn’t been forced to load on very fast machines.
Changes:
- Replace
await Task.Delay(1)withawait Task.Yield()to guarantee a suspension point (sinceYieldAwaiter.IsCompletedis alwaysfalse). - Add an explanatory comment documenting why
Task.Delay(1)was timing-dependent and whyTask.Yield()is used instead.
The AsyncContinuation cDAC dump test fails intermittently on osx-arm64 because 'await Task.Delay(1)' in InnerAsync can complete synchronously (the timer fires before await checks IsCompleted), so the async chain runs straight through with no continuation dispatch. AsyncDispatcherInfo MT is never loaded and the test asserts that lookup succeeds. Replace Task.Delay(1) with Task.Yield(). Task.Yield's awaiter always reports IsCompleted=false, so the continuation is guaranteed to be posted back via DispatchContinuations and AsyncDispatcherInfo.t_current is guaranteed to be written before InnerAsync resumes and FailFasts. Verified locally that with Task.Delay(1) the failing osx-arm64 dump shows OuterAsync calling InnerAsync directly (no DispatchContinuations on the stack), confirming the await did not suspend. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
23853f4 to
279786d
Compare
rcj1
approved these changes
May 10, 2026
This was referenced May 11, 2026
jakobbotsch
pushed a commit
to jakobbotsch/runtime
that referenced
this pull request
May 12, 2026
….Yield (dotnet#128004) > [!NOTE] > This pull request was prepared with assistance from GitHub Copilot. ## Problem `AsyncContinuationDumpTests.ThreadLocalContinuation_IsContinuation` fails intermittently on **osx-arm64 R2R** with: > Could not find AsyncDispatcherInfo type in CoreLib Failure tracked in dotnet#127774. Recently observed in builds [1413917](https://dev.azure.com/dnceng-public/public/_build/results?buildId=1413917) and [1411121](https://dev.azure.com/dnceng-public/public/_build/results?buildId=1411121). Fixes dotnet#127774 ## Root cause The test relies on the runtime having executed `AsyncHelpers+RuntimeAsyncTask<T>.DispatchContinuations()`, which writes `AsyncDispatcherInfo.t_current` and forces the JIT to load the `AsyncDispatcherInfo` MethodTable. The current debuggee uses `await Task.Delay(1)` to force a suspension. On fast machines (in particular Apple Silicon CI machines) the 1ms timer can fire before the runtime-async `Await` helper checks `IsCompleted`, so the awaiter is observed as already-completed and the await runs straight through synchronously. With no suspension there is no dispatch, no `t_current` write, and the `AsyncDispatcherInfo` MT is never loaded. I downloaded the failing osx-arm64 dump and walked the crashed thread: ``` [2-4] FailFast [5] InnerAsync [6] OuterAsync (async2 body) [7] OuterAsync (thunk) [8] Main [9] CallEntryPoint ``` There is no `DispatchContinuations` frame on the stack. `OuterAsync` calls `InnerAsync` directly, confirming the await did not suspend. I also walked all 3 modules' `TypeDefToMethodTable` maps and confirmed `AsyncDispatcherInfo` MT is genuinely null everywhere (i.e. cDAC is reporting reality - the type never got loaded). `Object`, `Task`, and `Continuation` MTs are all loaded as expected. ## Fix Replace `await Task.Delay(1)` with `await Task.Yield()` in `InnerAsync`. `Task.Yield()` returns a `YieldAwaitable` whose awaiter's `IsCompleted` always returns `false`, so the continuation is unconditionally posted back via `DispatchContinuations`. This guarantees `AsyncDispatcherInfo.t_current` is written before `InnerAsync` resumes and calls `FailFast`, regardless of machine timing. ## Validation Posting as a draft to run CI across all platforms; the osx-arm64 R2R leg is the one to watch. Co-authored-by: Max Charlamb <maxcharlamb@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.
Note
This pull request was prepared with assistance from GitHub Copilot.
Problem
AsyncContinuationDumpTests.ThreadLocalContinuation_IsContinuationfails intermittently on osx-arm64 R2R with:Failure tracked in #127774. Recently observed in builds 1413917 and 1411121.
Fixes #127774
Root cause
The test relies on the runtime having executed
AsyncHelpers+RuntimeAsyncTask<T>.DispatchContinuations(), which writesAsyncDispatcherInfo.t_currentand forces the JIT to load theAsyncDispatcherInfoMethodTable.The current debuggee uses
await Task.Delay(1)to force a suspension. On fast machines (in particular Apple Silicon CI machines) the 1ms timer can fire before the runtime-asyncAwaithelper checksIsCompleted, so the awaiter is observed as already-completed and the await runs straight through synchronously. With no suspension there is no dispatch, not_currentwrite, and theAsyncDispatcherInfoMT is never loaded.I downloaded the failing osx-arm64 dump and walked the crashed thread:
There is no
DispatchContinuationsframe on the stack.OuterAsynccallsInnerAsyncdirectly, confirming the await did not suspend.I also walked all 3 modules'
TypeDefToMethodTablemaps and confirmedAsyncDispatcherInfoMT is genuinely null everywhere (i.e. cDAC is reporting reality - the type never got loaded).Object,Task, andContinuationMTs are all loaded as expected.Fix
Replace
await Task.Delay(1)withawait Task.Yield()inInnerAsync.Task.Yield()returns aYieldAwaitablewhose awaiter'sIsCompletedalways returnsfalse, so the continuation is unconditionally posted back viaDispatchContinuations. This guaranteesAsyncDispatcherInfo.t_currentis written beforeInnerAsyncresumes and callsFailFast, regardless of machine timing.Validation
Posting as a draft to run CI across all platforms; the osx-arm64 R2R leg is the one to watch.