未验证 提交 948a9e1d 编写于 作者: S Sam Harwell 提交者: GitHub

Merge pull request #29309 from sharwell/require-vs-threading

Require JoinableTaskContext be provided in the MEF container for EditorFeatures
......@@ -2,9 +2,7 @@
using System;
using System.Composition;
using System.Threading;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Utilities;
using Microsoft.VisualStudio.Threading;
namespace Microsoft.CodeAnalysis.Editor.Shared.Utilities
......@@ -21,57 +19,17 @@ namespace Microsoft.CodeAnalysis.Editor.Shared.Utilities
/// </remarks>
[Export(typeof(IThreadingContext))]
[Shared]
internal sealed partial class ThreadingContext : IThreadingContext
internal sealed class ThreadingContext : IThreadingContext
{
[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public ThreadingContext([Import(AllowDefault = true)] JoinableTaskContext joinableTaskContext)
public ThreadingContext(JoinableTaskContext joinableTaskContext)
{
if (joinableTaskContext is null)
{
(joinableTaskContext, _) = CreateJoinableTaskContext();
}
HasMainThread = joinableTaskContext.MainThread.IsAlive;
JoinableTaskContext = joinableTaskContext;
JoinableTaskFactory = joinableTaskContext.Factory;
}
internal static (JoinableTaskContext joinableTaskContext, SynchronizationContext synchronizationContext) CreateJoinableTaskContext()
{
Thread mainThread;
SynchronizationContext synchronizationContext;
switch (ForegroundThreadDataInfo.CreateDefault(ForegroundThreadDataKind.Unknown))
{
case ForegroundThreadDataKind.JoinableTask:
throw new NotSupportedException($"A {nameof(VisualStudio.Threading.JoinableTaskContext)} already exists, but we have no way to obtain it.");
case ForegroundThreadDataKind.Wpf:
case ForegroundThreadDataKind.WinForms:
case ForegroundThreadDataKind.MonoDevelopGtk:
case ForegroundThreadDataKind.MonoDevelopXwt:
case ForegroundThreadDataKind.StaUnitTest:
// The current thread is the main thread, and provides a suitable synchronization context
mainThread = Thread.CurrentThread;
synchronizationContext = SynchronizationContext.Current;
break;
case ForegroundThreadDataKind.ForcedByPackageInitialize:
case ForegroundThreadDataKind.Unknown:
default:
// The current thread is not known to be the main thread; we have no way to know if the
// synchronization context of the current thread will behave in a manner consistent with main thread
// synchronization contexts, so we use DenyExecutionSynchronizationContext to track any attempted
// use of it.
var denyExecutionSynchronizationContext = new DenyExecutionSynchronizationContext(SynchronizationContext.Current);
mainThread = denyExecutionSynchronizationContext.MainThread;
synchronizationContext = denyExecutionSynchronizationContext;
break;
}
return (new JoinableTaskContext(mainThread, synchronizationContext), synchronizationContext);
}
/// <inheritdoc/>
public bool HasMainThread
{
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Threading;
using static Microsoft.CodeAnalysis.Utilities.ForegroundThreadDataKind;
namespace Microsoft.CodeAnalysis.Utilities
{
internal enum ForegroundThreadDataKind
{
Wpf,
WinForms,
StaUnitTest,
JoinableTask,
ForcedByPackageInitialize,
MonoDevelopGtk,
MonoDevelopXwt,
Unknown
}
internal static class ForegroundThreadDataInfo
{
internal static ForegroundThreadDataKind CreateDefault(ForegroundThreadDataKind defaultKind)
{
var syncContextTypeName = SynchronizationContext.Current?.GetType().FullName;
switch (syncContextTypeName)
{
case "System.Windows.Threading.DispatcherSynchronizationContext":
return Wpf;
case "Microsoft.VisualStudio.Threading.JoinableTask+JoinableTaskSynchronizationContext":
return JoinableTask;
case "System.Windows.Forms.WindowsFormsSynchronizationContext":
return WinForms;
case "MonoDevelop.Ide.DispatchService+GtkSynchronizationContext":
return MonoDevelopGtk;
case "Xwt.XwtSynchronizationContext":
return MonoDevelopXwt;
default:
return defaultKind;
}
}
}
}
......@@ -126,7 +126,7 @@ public override void After(MethodInfo methodUnderTest)
// Verify the synchronization context was not used incorrectly
var testExportJoinableTaskContext = exportProvider.GetExportedValues<TestExportJoinableTaskContext>().SingleOrDefault();
if (testExportJoinableTaskContext?.SynchronizationContext is ThreadingContext.DenyExecutionSynchronizationContext synchronizationContext)
if (testExportJoinableTaskContext?.SynchronizationContext is TestExportJoinableTaskContext.DenyExecutionSynchronizationContext synchronizationContext)
{
synchronizationContext.ThrowIfSwitchOccurred();
}
......
......@@ -4,11 +4,12 @@
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
using System.Threading;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Editor.Shared.Utilities
namespace Microsoft.CodeAnalysis.Test.Utilities
{
internal sealed partial class ThreadingContext
internal partial class TestExportJoinableTaskContext
{
/// <summary>
/// Defines a <see cref="SynchronizationContext"/> for use in cases where the synchronization context should not
......
......@@ -6,7 +6,7 @@
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using System.Windows.Threading;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.VisualStudio.Threading;
using Xunit.Sdk;
......@@ -16,7 +16,7 @@ namespace Microsoft.CodeAnalysis.Test.Utilities
// Starting with 15.3 the editor took a dependency on JoinableTaskContext
// in Text.Logic and IntelliSense layers as an editor host provided service.
[Export]
internal class TestExportJoinableTaskContext
internal partial class TestExportJoinableTaskContext
{
[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
......@@ -26,7 +26,7 @@ public TestExportJoinableTaskContext()
try
{
SynchronizationContext.SetSynchronizationContext(GetEffectiveSynchronizationContext());
(JoinableTaskContext, SynchronizationContext) = ThreadingContext.CreateJoinableTaskContext();
(JoinableTaskContext, SynchronizationContext) = CreateJoinableTaskContext();
ResetThreadAffinity(JoinableTaskContext.Factory);
}
finally
......@@ -35,6 +35,30 @@ public TestExportJoinableTaskContext()
}
}
private static (JoinableTaskContext joinableTaskContext, SynchronizationContext synchronizationContext) CreateJoinableTaskContext()
{
Thread mainThread;
SynchronizationContext synchronizationContext;
if (SynchronizationContext.Current is DispatcherSynchronizationContext)
{
// The current thread is the main thread, and provides a suitable synchronization context
mainThread = Thread.CurrentThread;
synchronizationContext = SynchronizationContext.Current;
}
else
{
// The current thread is not known to be the main thread; we have no way to know if the
// synchronization context of the current thread will behave in a manner consistent with main thread
// synchronization contexts, so we use DenyExecutionSynchronizationContext to track any attempted
// use of it.
var denyExecutionSynchronizationContext = new DenyExecutionSynchronizationContext(SynchronizationContext.Current);
mainThread = denyExecutionSynchronizationContext.MainThread;
synchronizationContext = denyExecutionSynchronizationContext;
}
return (new JoinableTaskContext(mainThread, synchronizationContext), synchronizationContext);
}
[Export]
private JoinableTaskContext JoinableTaskContext
{
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册