diff --git a/src/EditorFeatures/Core/Shared/Utilities/ThreadingContext.cs b/src/EditorFeatures/Core/Shared/Utilities/ThreadingContext.cs index 49cb4d22ccf5e0004c214674025b211ca817a05a..7d925080cdce2fb36f4496874539da6b90155974 100644 --- a/src/EditorFeatures/Core/Shared/Utilities/ThreadingContext.cs +++ b/src/EditorFeatures/Core/Shared/Utilities/ThreadingContext.cs @@ -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 /// [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); - } - /// public bool HasMainThread { diff --git a/src/Workspaces/Core/Portable/Utilities/ForegroundThreadDataKind.cs b/src/Workspaces/Core/Portable/Utilities/ForegroundThreadDataKind.cs deleted file mode 100644 index 2016bed2fee53211446f31338f9e802a8c47b412..0000000000000000000000000000000000000000 --- a/src/Workspaces/Core/Portable/Utilities/ForegroundThreadDataKind.cs +++ /dev/null @@ -1,54 +0,0 @@ -// 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; - } - } - } -} diff --git a/src/Workspaces/CoreTestUtilities/MEF/UseExportProviderAttribute.cs b/src/Workspaces/CoreTestUtilities/MEF/UseExportProviderAttribute.cs index 4d7275ed51cc02b72197caa24c6eb99b478258ee..d215099000147a0867b0c81fc4ae7dfc3f4721d0 100644 --- a/src/Workspaces/CoreTestUtilities/MEF/UseExportProviderAttribute.cs +++ b/src/Workspaces/CoreTestUtilities/MEF/UseExportProviderAttribute.cs @@ -126,7 +126,7 @@ public override void After(MethodInfo methodUnderTest) // Verify the synchronization context was not used incorrectly var testExportJoinableTaskContext = exportProvider.GetExportedValues().SingleOrDefault(); - if (testExportJoinableTaskContext?.SynchronizationContext is ThreadingContext.DenyExecutionSynchronizationContext synchronizationContext) + if (testExportJoinableTaskContext?.SynchronizationContext is TestExportJoinableTaskContext.DenyExecutionSynchronizationContext synchronizationContext) { synchronizationContext.ThrowIfSwitchOccurred(); } diff --git a/src/EditorFeatures/Core/Shared/Utilities/ThreadingContext+DenyExecutionSynchronizationContext.cs b/src/Workspaces/CoreTestUtilities/TestExportJoinableTaskContext+DenyExecutionSynchronizationContext.cs similarity index 97% rename from src/EditorFeatures/Core/Shared/Utilities/ThreadingContext+DenyExecutionSynchronizationContext.cs rename to src/Workspaces/CoreTestUtilities/TestExportJoinableTaskContext+DenyExecutionSynchronizationContext.cs index e2307e4f9cfe22262be1a9886db2d5642df6af54..3c2e673c1202f2dcece3df7956bec3027207b72d 100644 --- a/src/EditorFeatures/Core/Shared/Utilities/ThreadingContext+DenyExecutionSynchronizationContext.cs +++ b/src/Workspaces/CoreTestUtilities/TestExportJoinableTaskContext+DenyExecutionSynchronizationContext.cs @@ -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 { /// /// Defines a for use in cases where the synchronization context should not diff --git a/src/Workspaces/CoreTestUtilities/TestExportJoinableTaskContext.cs b/src/Workspaces/CoreTestUtilities/TestExportJoinableTaskContext.cs index d82ee616e4cfb66b1d81dad40fbaefff6426370a..3b9e61d76b2715fa3318acab16d19279bb630c1c 100644 --- a/src/Workspaces/CoreTestUtilities/TestExportJoinableTaskContext.cs +++ b/src/Workspaces/CoreTestUtilities/TestExportJoinableTaskContext.cs @@ -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 {