Skip to content
This repository was archived by the owner on Oct 4, 2021. It is now read-only.

Commit 8015857

Browse files
authored
[Ide] Load AddinManager data on the UI thread. (#9391)
* [Ide] Load AddinManager data on the UI thread. We need to run this on the UI thread since AddinManager is not thread safe. Invoking extension changed handlers on non-UI thread can lead to weird results Fixes VSTS #1027414 - [FATAL] SigTerm signal in Mono.Addins.dll!Mono.Addins.RuntimeAddin::LoadModule+82" Synchronously run the OnInitialize of the service to load the addin assemblies on the UI thread, then dispatch the actual composing to a background task. This should prevent deadlock issues, and ensure that the first init is called on the UI thread * Use Runtime.RunInMainThread Some tests (i.e. MD.Core) cannot initialize the composition manager in the UI thread. The Razor extension ends up calling CompositionManager.Instance in the constructor, thus the init will throw and the Core test suite hangs.
1 parent 3fe1b66 commit 8015857

File tree

3 files changed

+33
-43
lines changed

3 files changed

+33
-43
lines changed

main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/CompositionManager.cs

Lines changed: 33 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -56,23 +56,12 @@ public partial class CompositionManager: Service
5656
new AttributedPartDiscoveryV1 (StandardResolver),
5757
new AttributedPartDiscovery (StandardResolver, true));
5858

59-
static Action HandleMefQueriedBeforeCompletion = UninitializedLogWarning;
60-
61-
static void UninitializedLogWarning ()
62-
=> LoggingService.LogWarning ("UI thread queried MEF while it was still being built:{0}{1}", Environment.NewLine, Environment.StackTrace);
63-
64-
static void UninitializedThrowException ()
65-
=> throw new InvalidOperationException ("MEF queried while it was still being built");
66-
67-
internal static void ConfigureUninitializedMefHandling (bool throwException)
68-
=> HandleMefQueriedBeforeCompletion = throwException ? new Action (UninitializedThrowException) : new Action (UninitializedLogWarning);
69-
7059
public static CompositionManager Instance {
7160
get {
7261
if (instance == null) {
7362
var task = Runtime.GetService<CompositionManager> ();
7463
if (!task.IsCompleted && Runtime.IsMainThread) {
75-
HandleMefQueriedBeforeCompletion ();
64+
LoggingService.LogWarning ("UI thread queried MEF while it was still being built:{0}{1}", Environment.NewLine, Environment.StackTrace);
7665
}
7766
instance = task.WaitAndGetResult ();
7867
}
@@ -82,8 +71,20 @@ public static CompositionManager Instance {
8271
}
8372

8473
protected override Task OnInitialize (ServiceProvider serviceProvider)
85-
{
86-
return Task.Run (async () => await InitializeInstanceAsync ());
74+
{
75+
return Runtime.RunInMainThread (() => {
76+
var timings = new Dictionary<string, long> ();
77+
var metadata = new CompositionLoadMetadata (timings);
78+
79+
var timer = Counters.CompositionLoad.BeginTiming (metadata);
80+
var stepTimer = System.Diagnostics.Stopwatch.StartNew ();
81+
82+
var mefAssemblies = ReadAssembliesFromAddins (timer);
83+
84+
timings ["ReadFromAddins"] = stepTimer.ElapsedMilliseconds;
85+
86+
return Task.Run (() => InitializeInstanceAsync (timer, mefAssemblies));
87+
});
8788
}
8889

8990
/// <summary>
@@ -115,49 +116,42 @@ internal CompositionManager ()
115116
{
116117
}
117118

118-
async Task InitializeInstanceAsync ()
119+
async Task InitializeInstanceAsync (ITimeTracker<CompositionLoadMetadata> timer, HashSet<Assembly> mefAssemblies)
119120
{
120-
var timings = new Dictionary<string, long> ();
121-
var metadata = new CompositionLoadMetadata (timings);
122-
123-
using (var timer = Counters.CompositionLoad.BeginTiming (metadata)) {
124-
var fullTimer = System.Diagnostics.Stopwatch.StartNew ();
125-
var stepTimer = System.Diagnostics.Stopwatch.StartNew ();
126-
127-
var mefAssemblies = ReadAssembliesFromAddins (timer);
128-
timings ["ReadFromAddins"] = stepTimer.ElapsedMilliseconds;
129-
stepTimer.Restart ();
130-
131-
var caching = new Caching (mefAssemblies, new IdeRuntimeCompositionExceptionHandler ());
121+
var metadata = timer.Metadata;
122+
var fullTimer = System.Diagnostics.Stopwatch.StartNew ();
123+
var stepTimer = System.Diagnostics.Stopwatch.StartNew ();
132124

133-
// Try to use cached MEF data
125+
var caching = new Caching (mefAssemblies, new IdeRuntimeCompositionExceptionHandler ());
134126

127+
// Try to use cached MEF data
128+
using (timer) {
135129
var canUse = metadata.ValidCache = caching.CanUse ();
136-
if (canUse) {
130+
if (canUse) {
137131
LoggingService.LogInfo ("Creating MEF composition from cache");
138132
RuntimeComposition = await TryCreateRuntimeCompositionFromCache (caching);
139-
}
140-
timings ["LoadFromCache"] = stepTimer.ElapsedMilliseconds;
133+
}
134+
metadata.Timings ["LoadFromCache"] = stepTimer.ElapsedMilliseconds;
141135
stepTimer.Restart ();
142136

143137
// Otherwise fallback to runtime discovery.
144-
if (RuntimeComposition == null) {
138+
if (RuntimeComposition == null) {
145139
LoggingService.LogInfo ("Creating MEF composition from runtime");
146-
var (runtimeComposition, catalog) = await CreateRuntimeCompositionFromDiscovery (caching, timer);
140+
var (runtimeComposition, catalog) = await CreateRuntimeCompositionFromDiscovery (caching, timer);
147141
RuntimeComposition = runtimeComposition;
148142

149143
CachedComposition cacheManager = new CachedComposition ();
150144
caching.Write (RuntimeComposition, catalog, cacheManager).Ignore ();
151-
}
152-
timings ["LoadRuntimeComposition"] = stepTimer.ElapsedMilliseconds;
153-
stepTimer.Restart ();
145+
}
146+
metadata.Timings ["LoadRuntimeComposition"] = stepTimer.ElapsedMilliseconds;
147+
stepTimer.Restart ();
154148

155149
ExportProviderFactory = RuntimeComposition.CreateExportProviderFactory ();
156150
ExportProvider = ExportProviderFactory.CreateExportProvider ();
157151
HostServices = Microsoft.VisualStudio.LanguageServices.VisualStudioMefHostServices.Create (ExportProvider);
158-
159-
timings ["CreateServices"] = stepTimer.ElapsedMilliseconds;
160-
metadata.Duration = fullTimer.ElapsedMilliseconds;
152+
153+
metadata.Timings ["CreateServices"] = stepTimer.ElapsedMilliseconds;
154+
metadata.Duration = fullTimer.ElapsedMilliseconds;
161155
}
162156
}
163157

main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/Ide.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -315,8 +315,6 @@ static void OnInitialized ()
315315
Counters.InitializationTracker.Trace ("Running Startup Commands");
316316
AddinManager.AddExtensionNodeHandler ("/MonoDevelop/Ide/StartupHandlers", OnExtensionChanged);
317317

318-
// Let extensions now access CompositionManager.Instance and start asynchronously composing the catalog
319-
CompositionManager.ConfigureUninitializedMefHandling (throwException: false);
320318
Runtime.GetService<CompositionManager> ().Ignore ();
321319
}
322320

main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeStartup.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,6 @@ int Run (MonoDevelopOptions options)
8888
{
8989
UnsetEnvironmentVariables ();
9090

91-
CompositionManager.ConfigureUninitializedMefHandling (throwException: true);
92-
9391
LoggingService.LogInfo ("Starting {0} {1}", BrandingService.ApplicationLongName, IdeVersionInfo.MonoDevelopVersion);
9492
LoggingService.LogInfo ("Build Information{0}{1}", Environment.NewLine, SystemInformation.GetBuildInformation ());
9593
LoggingService.LogInfo ("Running on {0}", RuntimeVersionInfo.GetRuntimeInfo ());

0 commit comments

Comments
 (0)