Free-threaded validation sample not working
Bug description
The cookbook has this sample for how to test if a method is free-threaded: https://github.com/microsoft/vs-threading/blame/bbc8fc3e26490bf58a46690fbc749389afce9e06/doc/cookbook_vs.md#L353-L364
Using it in an extension with VS 16.9, it always hangs. Even if I change the "component" being tested to nothing more than return 0;, the jtf.Run never returns. Using Visual Studio's Parallel Stacks debugging feature, I can no longer find any tasks from the delegate that it ran, so that task appears to have completed, yet jtf.Run doesn't return.
Repro steps
Here's the code that I'm using. It's a little test extension to test NuGet APIs in Visual Studio, and we'd like to be able to check if an API is free-threaded or not: https://github.com/NuGet/Entropy/blob/6bc031c2f8c668079069afcce1b0b6b16bcc41b3/IVsTestingExtension/src/Xaml/ApiInvoker/ApiInvokeView.xaml.cs#L78-L93
I also tried simplifying and introducing new methods, to make call stacks easier to understand, rather than having an anonymous function inside another anonymous function:
public void RunButton_Click(object sender, RoutedEventArgs e)
{
var message = jtf.Run(CheckFreeThreaded);
_results.Text = message;
}
private async Task<string> CheckFreeThreaded()
{
string message;
var o = jtf.Context.SuppressRelevance();
try
{
await Task.Run(MethodToCheck);
}
catch (Exception e)
{
message = e.ToString();
}
finally
{
o.Dispose();
}
return message;
}
private string MethodToCheck()
{
return "worked";
}
Expected behavior
Given the "simplified" example above, I'd expect when I click the WPF button, that the _results text block's message becomes the string "worked".
Actual behavior
VS hangs.
Putting a breakpoint in MethodToCheck and looking at Visual Studio's threads window, I can see that the main thread's call stack is on CheckFreeThreaded's await Task.Run line, and MethodToCheck is being run on a background thread. I don't know if it's normal, but the Parallel Stacks window shows the task running MethodToCheck, but there are no tasks that are linked/waiting to it. Also, none of the tasks in the Parallel Stacks tasks view shows CheckFreeThreaded. I know that calling an async method is synchronous until the first await on an incomplete task, but I would have thought that calling await Task.Run from the main thread always awaits an incomplete task, so a Task should be created. I'm confused why MethodToCheck is currently executing, but the main thread is still in CheckFreeThreaded's await line. But it doesn't bother me, maybe it's just how async state machines for async methods work when calling Task.Run.
Letting the debugger continue, VS just hangs. Breakpoints in CheckFreeThreaded's catch and finally block, or the return statement, never get hit. Maybe it's a bug or limitation in the debugger and/or compiler and the state machine it generated, I don't know.
But pressing the pause button shows that the main thread's call stack is now RunButton_Click->[waiting on async operation]->NoMessagePumpSyncContext.Wait, so CheckFreeThreaded is no longer on the main call stack. The Parallel Stacks window doesn't show any task with CheckFreeThreaded in the call stack, so I'm confused how it could have completed without hitting any of my breakpoints. But at the same time, if there is no incomplete task for CheckFreeThreaded, then the task that RunButton_Click was waiting on should be finished, and execution continues. As mentioned, the threads window says that the main thread is waiting on async operation before saying NoMessagePumpSyncContext.Wait, so I would expect to see a task in the Parallel Stacks task view with NoMessagePumpSyncContext in the call stack, but there isn't.
I'm way outside of my area of expertise, so I have no idea what else might help.
- Version used: 16.8.55
- Application (if applicable): Visual Studio 2019 16.9 preview
Additional context
I didn't try older versions of VS, but a team mate used this in an extension to test APIs in VS, so I assume this worked at some point.