-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Migrate to Microsoft.VisualStudio.Threading #28781
Conversation
…ispatcherPriority)
@@ -149,7 +149,7 @@ private void StartSearch(INavigateToCallback callback, string searchValue, IImmu | |||
kinds, | |||
_cancellationTokenSource.Token); | |||
|
|||
searcher.Search(); | |||
_ = searcher.SearchAsync(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't this have an effect of silencing all exceptions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
➡️ It's an intermediate step. VSTHRD110 deals with observing the result of asynchronous operations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sharwell intermediate step still needs fixing further?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jasonmalinowski Covered under the VSTHRD110 follow-up issue.
4e99053
to
fb1e11b
Compare
fb1e11b
to
dc48c9b
Compare
2a93c17
to
059cd2f
Compare
b0cdbbc
to
71c6f80
Compare
{ | ||
await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(); |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
{ | ||
await threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(); |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
allRenameLocationsTask.SafeContinueWithFromAsync( | ||
async t => | ||
{ | ||
await ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(_cancellationTokenSource.Token); |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
Dispatcher.CurrentDispatcher.BeginInvoke(propagateEditAction, DispatcherPriority.Send, null); | ||
ThreadingContext.JoinableTaskFactory.WithPriority(Dispatcher.CurrentDispatcher, DispatcherPriority.Send).RunAsync(async () => | ||
{ | ||
await ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(); |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
.SafeContinueWithFromAsync( | ||
async t => | ||
{ | ||
await ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(_conflictResolutionTaskCancellationSource.Token); |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
{ | ||
AssertIsForeground(); | ||
await ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(_cancellationToken); |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
{ | ||
AssertIsForeground(); | ||
await ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(_cancellationTokenSource.Token); |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
@@ -144,7 +143,13 @@ public void RemoveProject(ProjectId projectId) | |||
|
|||
// CPS projects do not support designer attributes. So we just skip these projects entirely. | |||
var vsWorkspace = project.Solution.Workspace as VisualStudioWorkspaceImpl; | |||
var cps = await Task.Factory.StartNew(() => vsWorkspace?.IsCPSProject(project) == true, cancellationToken, TaskCreationOptions.None, this.ForegroundTaskScheduler).ConfigureAwait(false); | |||
|
|||
await ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
.ContinueWith( | ||
async _ => | ||
{ | ||
await ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
{ | ||
await ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(); |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
6401c77
to
c302b71
Compare
c302b71
to
23c08dd
Compare
// since execution is now technically asynchronous | ||
// only execute action if project is not disconnected and currently being tracked. | ||
if (!_disconnected && this.ProjectTracker.ContainsProject(this)) | ||
{ | ||
action(); | ||
} | ||
}, | ||
ForegroundTaskScheduler); | ||
CancellationToken.None, | ||
TaskContinuationOptions.ExecuteSynchronously, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
different options than usual. intentional?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
➡️ Situation is most similar to #28781 (comment), but has a dedicated follow-up item due to #28781 (comment)
My brain really hurts. |
And this is the easy change. 😄 |
@heejaechang @jaredpar @jasonmalinowski @CyrusNajmabadi @DustinCampbell I replied to the easy items, and will work on making requested changes and finishing my replies tomorrow. Thank you for the detailed reviews. 🏅 |
* Remove unused test constructors in QuickInfoCommandHandlerAndSourceProvider * Document `IThreadingContext`, `ThreadingContext`, and `DenyExecutionSynchronizationContext` * Ensure `DenyExecutionSynchronizationContext.ThrowIfSwitchOccurred` gets called during test cleanup * Clean up project layering by moving `StubVsEditorAdaptersFactoryService`
9d8b071
to
bb01d0e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The change looks good. I'd probably wait for one more IDE sign off though as I'm a bit out of my depth in a few places.
My biggest complaint is the lack of ConfigureAwait in places. I get that we cant add it because it's custom awaitable structs. But I feel like the readibility goes down a bit. Perhaps once we get a bit more used to the MS.VS.Threading this will go away.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks pretty good. I'll be interested in the follow ups that come later.
Note that this will almost certainly break insertions due to components that have IVT.
@@ -35,7 +36,7 @@ public async Task TestTagsChangedForEntireFile() | |||
workspace.GetService<IForegroundNotificationService>(), | |||
AsynchronousOperationListenerProvider.NullListener, | |||
null, | |||
new SyntacticClassificationTaggerProvider(null, null, null)); | |||
new SyntacticClassificationTaggerProvider(workspace.ExportProvider.GetExportedValue<IThreadingContext>(), null, null, null)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: would be nice to name the null
arguments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
➡️ #29182
@@ -34,6 +35,7 @@ private IEnumerable<T> Enumerable<T>(params T[] array) | |||
{ | |||
var view = new Mock<ITextView>(); | |||
var producer = new BraceHighlightingViewTaggerProvider( | |||
workspace.ExportProvider.GetExportedValue<IThreadingContext>(), | |||
workspace.GetService<IBraceMatchingService>(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TestWorkspace.GetService<TServiceInterface>
is just a shortcut to call ExportProvider.GetExportedValue
. Should we call one or the other consistently?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
➡️ 😦 I certainly should have used workspace.GetService<IThreadingContext>()
here for consistency. I'll file a follow-up item related to the confusing pattern(s) we see today with these methods.
_cancellationTokenSource.Token, | ||
TaskContinuationOptions.OnlyOnRanToCompletion, | ||
ForegroundTaskScheduler).CompletesAsyncOperation(asyncToken); | ||
TaskContinuationOptions.OnlyOnRanToCompletion | TaskContinuationOptions.ExecuteSynchronously, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It'd be good if this were documented somewhere other than a comment buried in this PR (which has already "unicorned" on me twice! 😄). Since two very smart people have already asked about this pattern here, it'll almost certainly be stumbling block to anyone who happens upon the code. Maybe just add a comment in the code where the pattern is used? E.g. "ExecuteSynchronously
is passed to avoid a situation where the continuation to be scheduled on a background thread before immediately switching to the main thread."
_cancellationTokenSource.Token, | ||
TaskContinuationOptions.OnlyOnRanToCompletion, | ||
ForegroundTaskScheduler).CompletesAsyncOperation(asyncToken); | ||
TaskContinuationOptions.OnlyOnRanToCompletion | TaskContinuationOptions.ExecuteSynchronously, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or, maybe add a helper method with a good name to handle this situation rather than passing the same flags everytime? The exact same pattern is used below.
@@ -24,7 +24,8 @@ internal partial class QuickInfoPresenter : ForegroundThreadAffinitizedObject, I | |||
private readonly DeferredContentFrameworkElementFactory _elementFactory; | |||
|
|||
[ImportingConstructor] | |||
public QuickInfoPresenter(IQuickInfoBroker quickInfoBroker, DeferredContentFrameworkElementFactory elementFactory) | |||
public QuickInfoPresenter(IThreadingContext threadingContext, IQuickInfoBroker quickInfoBroker, DeferredContentFrameworkElementFactory elementFactory) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good. Is there an issue tracking future work to update old code?
@@ -36,7 +34,8 @@ internal abstract class AbstractSnippetCommandHandler : | |||
|
|||
public string DisplayName => FeaturesResources.Snippets; | |||
|
|||
public AbstractSnippetCommandHandler(IVsEditorAdaptersFactoryService editorAdaptersFactoryService, SVsServiceProvider serviceProvider) | |||
public AbstractSnippetCommandHandler(IThreadingContext threadingContext, IVsEditorAdaptersFactoryService editorAdaptersFactoryService, SVsServiceProvider serviceProvider) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor: Shouldn't this constructor be protected?
@@ -46,7 +44,8 @@ internal abstract class AbstractSnippetExpansionClient : ForegroundThreadAffinit | |||
|
|||
internal IVsExpansionSession ExpansionSession; | |||
|
|||
public AbstractSnippetExpansionClient(Guid languageServiceGuid, ITextView textView, ITextBuffer subjectBuffer, IVsEditorAdaptersFactoryService editorAdaptersFactoryService) | |||
public AbstractSnippetExpansionClient(IThreadingContext threadingContext, Guid languageServiceGuid, ITextView textView, ITextBuffer subjectBuffer, IVsEditorAdaptersFactoryService editorAdaptersFactoryService) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor: protected constructor?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -43,9 +43,11 @@ internal abstract class AbstractSnippetInfoService : ForegroundThreadAffinitized | |||
private readonly IAsynchronousOperationListener _waiter; | |||
|
|||
public AbstractSnippetInfoService( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor: should this constructor on an abstract class be protected?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
➡️ Also covered by analyzer limitation
Public Sub New(startActiveSession As Boolean) | ||
MyBase.New(Nothing, Nothing, Nothing, Nothing) | ||
Public Sub New(threadingContext As IThreadingContext, startActiveSession As Boolean) | ||
MyBase.New(threadingContext, Nothing, Nothing, Nothing, Nothing) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor: Named arguments for the trailing Nothing
literals would be nice here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
➡️ I would fix this if I was making other changes, but for now I'll consider it covered by #19186
@@ -3252,7 +3252,7 @@ public async Task TestAddRemoveMetadataReference_GAC() | |||
|
|||
[ConditionalFact(typeof(VisualStudioMSBuildInstalled))] | |||
[Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] | |||
public async void TestAddRemoveMetadataReference_ReferenceAssembly() | |||
public async Task TestAddRemoveMetadataReference_ReferenceAssembly() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good catch! I missed that one.
@dotnet/roslyn-infrastructure windows_debug_vs-integration_prtest is failing, but not due to this pull request. Merging and will file follow-up issues first thing tomorrow and start a deeper investigation into the failures. |
This change implements the first step towards Roslyn working in applications using vs-threading with reduced risk of concurrency bugs. Recommend reviewing by commit after looking at the full list to get an idea for the overall direction.
Most of the work in this change involves internal propagation of the
IThreadingContext
instance, which provides access to theJoinableTaskFactory
used in Roslyn code.Following this pull request, several diagnostics remain disabled.
FileAndForget
" before enabling this diagnostic.Known follow-up issues (GitHub issues will be linked here once they are available):
WaitAndGetResult
andWaitAndGetResult_CanCallOnBackground
as problematic synchronous waits (blocked on Allow extensions for VSTHRD002 (Avoid problematic synchronous waits) microsoft/vs-threading#344)ForegroundThreadDataKind
, and gut or eliminateForegroundThreadAffinitizedObject
Migrate to Microsoft.VisualStudio.Threading #28781 (comment)JoinableTaskContext
a required import forThreadingContext
Migrate to Microsoft.VisualStudio.Threading #28781 (comment)JoinableTaskFactoryTaskScheduler
, or at least add it to the set of legacy thread switching types Migrate to Microsoft.VisualStudio.Threading #28781 (comment)AbstractPackage.ForegroundObject
, and its costly initialization Migrate to Microsoft.VisualStudio.Threading #28781 (comment)ContinueWith
,SafeContinueWith
,StartNew
,SafeStartNew
, andTask.Run
to identify cases where simpler approaches are viable Migrate to Microsoft.VisualStudio.Threading #28781 (comment)TestWorkspace.GetService<T>
andTestWorkspace.ExportProvider.GetExportedValue<T>
Migrate to Microsoft.VisualStudio.Threading #28781 (comment)Customer scenario
This is an internal code change that allows dotnet/roslyn to be more easily incorporated into applications that involve user interfaces and leverage the Microsoft.VisualStudio.Threading library for deadlock and reentrancy mitigation and overall best practices.
Bugs this fixes
N/A
Workarounds, if any
Fixing bugs as they occur.
Risk
This change has moderate risk, but I believe it's relatively low risk considering its scope since existing behaviors were preserved where possible. The primary points where I see risk are the following:
WaitAndGetResult
was weakened, the debug assertion it contained was strengthened substantially. This code does not affect release builds, but despite the work in this pull request it may continue to affect debug pull request builds.Performance impact
Performance should not change substantially as a direct result of this pull request. Over time, performance should improve by allowing more code to use asynchronous operations and more efficient task continuations.
Is this a regression from a previous update?
N/A
Root cause analysis
N/A
How was the bug found?
N/A
Test documentation updated?
N/A