1313using Microsoft . CodeAnalysis . Host ;
1414using System . Composition ;
1515using Microsoft . CodeAnalysis . Shared . TestHooks ;
16+ using Microsoft . CodeAnalysis . Editor . Shared . Utilities ;
17+ using Microsoft . CodeAnalysis . Options ;
18+ using System . Linq ;
19+ using Microsoft . CodeAnalysis . Experiments ;
1620
1721namespace Microsoft . VisualStudio . LanguageServices . Implementation . LanguageService
1822{
1923 internal abstract class AbstractLanguageServerClient : ILanguageClient
2024 {
25+ private readonly IThreadingContext _threadingContext ;
2126 private readonly Workspace _workspace ;
27+ private readonly IEnumerable < Lazy < IOptionPersister > > _lazyOptions ;
2228 private readonly LanguageServerClientEventListener _eventListener ;
2329 private readonly IAsynchronousOperationListener _asyncListener ;
2430
@@ -55,13 +61,17 @@ internal abstract class AbstractLanguageServerClient : ILanguageClient
5561#pragma warning restore CS0067 // event never used
5662
5763 public AbstractLanguageServerClient (
64+ IThreadingContext threadingContext ,
5865 Workspace workspace ,
66+ IEnumerable < Lazy < IOptionPersister > > lazyOptions ,
5967 LanguageServerClientEventListener eventListener ,
6068 IAsynchronousOperationListenerProvider listenerProvider ,
6169 string languageServerName ,
6270 string serviceHubClientName )
6371 {
72+ _threadingContext = threadingContext ;
6473 _workspace = workspace ;
74+ _lazyOptions = lazyOptions ;
6575 _eventListener = eventListener ;
6676 _asyncListener = listenerProvider . GetListener ( FeatureAttribute . FindReferences ) ;
6777
@@ -103,6 +113,9 @@ public Task OnLoadedAsync()
103113 // set up event stream so that we start LSP server once Roslyn is loaded
104114 _eventListener . WorkspaceStarted . ContinueWith ( async _ =>
105115 {
116+ // initialize things on UI thread
117+ await InitializeOnUIAsync ( ) . ConfigureAwait ( false ) ;
118+
106119 // this might get called before solution is fully loaded and before file is opened.
107120 // we delay our OOP start until then, but user might do vsstart before that. so we make sure we start OOP if
108121 // it is not running yet. multiple start is no-op
@@ -122,6 +135,24 @@ public Task OnLoadedAsync()
122135 } , TaskScheduler . Default ) . CompletesAsyncOperation ( token ) ;
123136
124137 return Task . CompletedTask ;
138+
139+ async Task InitializeOnUIAsync ( )
140+ {
141+ await _threadingContext . JoinableTaskFactory . SwitchToMainThreadAsync ( ) ;
142+
143+ // this doesn't attempt to solve our JTF and some services being not free-thread issue here, but
144+ // try to fix this particular deadlock issue only. we already have long discussion on
145+ // how we need to deal with JTF, Roslyn service requirements and VS services reality conflicting
146+ // each others. architectural fix should come from the result of that discussion.
147+
148+ // Ensure the options persisters are loaded since we have to fetch options from the shell
149+ _lazyOptions . Select ( o => o . Value ) ;
150+
151+ // experimentation service unfortunately uses JTF to jump to UI thread in certain cases
152+ // which can cause deadlock if 2 parties try to enable OOP from BG and then FG before
153+ // experimentation service tries to jump to UI thread.
154+ var experimentationService = _workspace . Services . GetService < IExperimentationService > ( ) ;
155+ }
125156 }
126157
127158 /// <summary>
0 commit comments