Skip to content

Commit dad234d

Browse files
Simplify model computation threading (#76461)
2 parents fc4c9a1 + be3759d commit dad234d

File tree

6 files changed

+38
-51
lines changed

6 files changed

+38
-51
lines changed

src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ internal partial class Controller
1515
internal partial class Session : Session<Controller, Model, ISignatureHelpPresenterSession>
1616
{
1717
public Session(Controller controller, ISignatureHelpPresenterSession presenterSession)
18-
: base(controller, new ModelComputation<Model>(controller.ThreadingContext, controller, TaskScheduler.Default), presenterSession)
18+
: base(controller, new ModelComputation<Model>(controller.ThreadingContext, controller), presenterSession)
1919
{
2020
this.PresenterSession.ItemSelected += OnPresenterSessionItemSelected;
2121
}

src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_ComputeModel.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@
1313
using Microsoft.CodeAnalysis.ErrorReporting;
1414
using Microsoft.CodeAnalysis.Internal.Log;
1515
using Microsoft.CodeAnalysis.LanguageService;
16-
using Microsoft.CodeAnalysis.Options;
1716
using Microsoft.CodeAnalysis.Shared.Extensions;
1817
using Microsoft.CodeAnalysis.SignatureHelp;
1918
using Microsoft.VisualStudio.Text;
19+
using Microsoft.VisualStudio.Threading;
2020
using Roslyn.Utilities;
2121

2222
namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.SignatureHelp
@@ -37,9 +37,8 @@ public void ComputeModel(
3737
// If we've already computed a model, then just use that. Otherwise, actually
3838
// compute a new model and send that along.
3939
Computation.ChainTaskAndNotifyControllerWhenFinished(
40-
(model, cancellationToken) => ComputeModelInBackgroundAsync(
41-
model, providers, caretPosition, disconnectedBufferGraph,
42-
triggerInfo, cancellationToken));
40+
(currentModel, cancellationToken) => ComputeModelInBackgroundAsync(
41+
currentModel, providers, caretPosition, disconnectedBufferGraph, triggerInfo, cancellationToken));
4342
}
4443

4544
private async Task<Model> ComputeModelInBackgroundAsync(

src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_SetModelSelectedItem.cs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5-
#nullable disable
6-
75
using System;
6+
using System.Threading.Tasks;
87
using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
98
using Microsoft.CodeAnalysis.SignatureHelp;
9+
using Microsoft.VisualStudio.Threading;
1010
using Roslyn.Utilities;
1111

1212
namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.SignatureHelp
@@ -20,20 +20,17 @@ private void SetModelExplicitlySelectedItem(Func<Model, SignatureHelpItem> selec
2020
this.Computation.ThreadingContext.ThrowIfNotOnUIThread();
2121

2222
Computation.ChainTaskAndNotifyControllerWhenFinished(
23-
model => SetModelExplicitlySelectedItemInBackground(model, selector),
23+
(model, cancellationToken) => Task.FromResult(SetModelExplicitlySelectedItemInBackground(model, selector)),
2424
updateController: false);
2525
}
2626

27-
private Model SetModelExplicitlySelectedItemInBackground(
28-
Model model,
27+
private Model? SetModelExplicitlySelectedItemInBackground(
28+
Model? model,
2929
Func<Model, SignatureHelpItem> selector)
3030
{
3131
this.Computation.ThreadingContext.ThrowIfNotOnBackgroundThread();
32-
3332
if (model == null)
34-
{
3533
return null;
36-
}
3734

3835
var selectedItem = selector(model);
3936
Contract.ThrowIfFalse(model.Items.Contains(selectedItem));

src/EditorFeatures/Core/IntelliSense/ModelComputation.cs

Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
1212
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
1313
using Microsoft.CodeAnalysis.Shared.TestHooks;
14+
using Microsoft.VisualStudio.Threading;
1415
using Roslyn.Utilities;
1516

1617
namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense;
@@ -32,16 +33,6 @@ internal class ModelComputation<TModel> where TModel : class
3233
#region Fields that can only be accessed from the foreground thread
3334

3435
private readonly IController<TModel> _controller;
35-
private readonly TaskScheduler __taskScheduler;
36-
37-
private TaskScheduler _taskScheduler
38-
{
39-
get
40-
{
41-
ThreadingContext.ThrowIfNotOnUIThread();
42-
return __taskScheduler;
43-
}
44-
}
4536

4637
private readonly CancellationTokenSource _stopTokenSource;
4738

@@ -57,12 +48,10 @@ private TaskScheduler _taskScheduler
5748

5849
public ModelComputation(
5950
IThreadingContext threadingContext,
60-
IController<TModel> controller,
61-
TaskScheduler computationTaskScheduler)
51+
IController<TModel> controller)
6252
{
6353
ThreadingContext = threadingContext;
6454
_controller = controller;
65-
__taskScheduler = computationTaskScheduler;
6655

6756
_stopTokenSource = new CancellationTokenSource();
6857
_stopCancellationToken = _stopTokenSource.Token;
@@ -119,13 +108,6 @@ public virtual void Stop()
119108
_notifyControllerTask = _lastTask = SpecializedTasks.Null<TModel>();
120109
}
121110

122-
public void ChainTaskAndNotifyControllerWhenFinished(
123-
Func<TModel, TModel> transformModel,
124-
bool updateController = true)
125-
{
126-
ChainTaskAndNotifyControllerWhenFinished((m, c) => Task.FromResult(transformModel(m)), updateController);
127-
}
128-
129111
public void ChainTaskAndNotifyControllerWhenFinished(
130112
Func<TModel, CancellationToken, Task<TModel>> transformModelAsync,
131113
bool updateController = true)
@@ -140,9 +122,8 @@ public void ChainTaskAndNotifyControllerWhenFinished(
140122
var asyncToken = _controller.BeginAsyncOperation();
141123

142124
// Create the task that will actually run the transformation step.
143-
var nextTask = _lastTask.SafeContinueWithFromAsync(
144-
t => transformModelAsync(t.Result, _stopCancellationToken),
145-
_stopCancellationToken, TaskContinuationOptions.OnlyOnRanToCompletion, _taskScheduler);
125+
var nextTask = TransformModelAsync(_lastTask);// transformModelAsync(_lastTask, _stopCancellationToken);
126+
nextTask.ReportNonFatalErrorAsync();
146127

147128
// The next task is now the last task in the chain.
148129
_lastTask = nextTask;
@@ -174,6 +155,14 @@ public void ChainTaskAndNotifyControllerWhenFinished(
174155
// When we've notified the controller of our result, we consider the async operation
175156
// to be completed.
176157
_notifyControllerTask.CompletesAsyncOperation(asyncToken);
158+
159+
async Task<TModel> TransformModelAsync(Task<TModel> lastTask)
160+
{
161+
// Ensure we're on the BG before doing any model transformation work.
162+
await TaskScheduler.Default;
163+
var model = await lastTask.ConfigureAwait(false);
164+
return await transformModelAsync(model, _stopCancellationToken).ConfigureAwait(false);
165+
}
177166
}
178167

179168
private void OnModelUpdated(TModel result, bool updateController)

src/EditorFeatures/Test2/IntelliSense/ModelTests.vb

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,22 @@ Imports System.Threading
66
Imports Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense
77
Imports Microsoft.CodeAnalysis.Editor.Shared.Utilities
88
Imports Microsoft.CodeAnalysis.Shared.TestHooks
9+
Imports Microsoft.VisualStudio.Threading
910
Imports Moq
1011

1112
Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense
1213

1314
<UseExportProvider>
1415
<Trait(Traits.Feature, Traits.Features.DebuggingIntelliSense)>
15-
Public Class ModelTests
16+
Public NotInheritable Class ModelTests
1617
Public Class Model
1718
End Class
1819

1920
Private Class TestModelComputation
2021
Inherits ModelComputation(Of Model)
2122

2223
Public Sub New(threadingContext As IThreadingContext, controller As IController(Of Model))
23-
MyBase.New(threadingContext, controller, TaskScheduler.Default)
24+
MyBase.New(threadingContext, controller)
2425
End Sub
2526

2627
Friend Shared Function Create(threadingContext As IThreadingContext, Optional controller As IController(Of Model) = Nothing) As TestModelComputation
@@ -44,7 +45,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense
4445
controller.Setup(Function(c) c.BeginAsyncOperation("", Nothing, It.IsAny(Of String), It.IsAny(Of Integer))).Returns(EmptyAsyncToken.Instance)
4546
Dim modelComputation = TestModelComputation.Create(threadingContext, controller:=controller.Object)
4647

47-
modelComputation.ChainTaskAndNotifyControllerWhenFinished(Function(m) m)
48+
modelComputation.ChainTaskAndNotifyControllerWhenFinished(Function(m, c) Task.FromResult(m))
4849

4950
controller.Verify(Sub(c) c.BeginAsyncOperation(
5051
It.IsAny(Of String),
@@ -62,7 +63,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense
6263
controller.Setup(Sub(c) c.OnModelUpdated(model, True))
6364
Dim modelComputation = TestModelComputation.Create(threadingContext, controller:=controller.Object)
6465

65-
modelComputation.ChainTaskAndNotifyControllerWhenFinished(Function(m) model)
66+
modelComputation.ChainTaskAndNotifyControllerWhenFinished(Function(m, c) Task.FromResult(model))
6667
modelComputation.Wait()
6768

6869
controller.Verify(Sub(c) c.OnModelUpdated(model, True))
@@ -79,12 +80,12 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense
7980
Dim gate = New Object
8081

8182
Monitor.Enter(gate)
82-
modelComputation.ChainTaskAndNotifyControllerWhenFinished(Function(m)
83+
modelComputation.ChainTaskAndNotifyControllerWhenFinished(Function(m, c)
8384
SyncLock gate
84-
Return Nothing
85+
Return Task.FromResult(Of Model)(Nothing)
8586
End SyncLock
8687
End Function)
87-
modelComputation.ChainTaskAndNotifyControllerWhenFinished(Function(m) model)
88+
modelComputation.ChainTaskAndNotifyControllerWhenFinished(Function(m, c) Task.FromResult(model))
8889
Monitor.Exit(gate)
8990
modelComputation.Wait()
9091

@@ -109,12 +110,13 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense
109110

110111
token.Setup(Sub(t) t.Dispose()).Callback(Sub() checkpoint3.Release())
111112

112-
modelComputation.ChainTaskAndNotifyControllerWhenFinished(Function(m, c)
113-
checkpoint1.Release()
114-
checkpoint2.Task.Wait()
115-
c.ThrowIfCancellationRequested()
116-
Return Task.FromResult(model)
117-
End Function)
113+
modelComputation.ChainTaskAndNotifyControllerWhenFinished(
114+
Function(model1, c)
115+
checkpoint1.Release()
116+
checkpoint2.Task.Wait()
117+
c.ThrowIfCancellationRequested()
118+
Return Task.FromResult(model1)
119+
End Function)
118120
Await checkpoint1.Task
119121
modelComputation.Stop()
120122
checkpoint2.Release()

src/EditorFeatures/Test2/IntelliSense/SessionTests.vb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense
2424
controller.Setup(Sub(c) c.StopModelComputation())
2525
Dim session = New Session(Of IController(Of Model), Model, IIntelliSensePresenterSession)(
2626
controller.Object,
27-
New ModelComputation(Of Model)(threadingContext, controller.Object, TaskScheduler.Default),
27+
New ModelComputation(Of Model)(threadingContext, controller.Object),
2828
presenter.Object)
2929

3030
presenter.Raise(Sub(p) AddHandler p.Dismissed, Nothing, New EventArgs())
@@ -41,7 +41,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense
4141
Dim controller = New Mock(Of IController(Of Model))(MockBehavior.Strict)
4242
Dim session = New Session(Of IController(Of Model), Model, IIntelliSensePresenterSession)(
4343
controller.Object,
44-
New ModelComputation(Of Model)(threadingContext, controller.Object, TaskScheduler.Default),
44+
New ModelComputation(Of Model)(threadingContext, controller.Object),
4545
presenter.Object)
4646

4747
session.Stop()

0 commit comments

Comments
 (0)