提交 79009aca 编写于 作者: S Sam Harwell 提交者: Sam Harwell

Require JoinableTaskContext be provided in the MEF container for EditorFeatures

This requirement was inherited from other dependencies, and does not introduce new
requirements for downstream components. The dependency requirement is leveraged to
simplify code on production code paths.

Fixes #29278
Closes #29279
上级 79b9c406
......@@ -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.
先完成此消息的编辑!
想要评论请 注册