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

Commit 143332d

Browse files
committed
When accessing a pad-service from the SD service container, the SD.MainThread.VerifyAccess() call is now performed on every GetService() call, not just on the first call.
1 parent 99d94fd commit 143332d

9 files changed

Lines changed: 67 additions & 16 deletions

File tree

src/Main/Base/Project/ICSharpCode.SharpDevelop.addin

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,6 @@
172172
title = "${res:MainWindow.Windows.OutputWindow}"
173173
icon = "PadIcons.Output"
174174
class = "ICSharpCode.SharpDevelop.Gui.CompilerMessageView"
175-
serviceInterface = "ICSharpCode.SharpDevelop.Workbench.IOutputPad"
176175
defaultPosition = "Bottom" />
177176

178177
<Pad id = "PropertyPad"

src/Main/Base/Project/Services/SD.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ public static IServiceContainer Services {
4444
/// </summary>
4545
public static void InitializeForUnitTests()
4646
{
47-
var container = new SharpDevelopServiceContainer(ServiceSingleton.FallbackServiceProvider);
47+
var container = new SharpDevelopServiceContainer();
48+
container.AddFallbackProvider(ServiceSingleton.FallbackServiceProvider);
4849
container.AddService(typeof(IPropertyService), new PropertyServiceImpl());
4950
container.AddService(typeof(IAddInTree), new AddInTreeImpl(null));
5051
ServiceSingleton.ServiceProvider = container;

src/Main/Base/Project/Util/SharpDevelopServiceContainer.cs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
33

44
using System;
5+
using System.Collections.Concurrent;
56
using System.ComponentModel.Design;
67
using System.Linq;
78
using System.Collections.Generic;
@@ -14,7 +15,7 @@ namespace ICSharpCode.SharpDevelop
1415
/// </summary>
1516
sealed class SharpDevelopServiceContainer : IServiceProvider, IServiceContainer, IDisposable
1617
{
17-
readonly IServiceProvider parentProvider;
18+
readonly ConcurrentStack<IServiceProvider> fallbackProviders = new ConcurrentStack<IServiceProvider>();
1819
readonly Dictionary<Type, object> services = new Dictionary<Type, object>();
1920
readonly List<Type> servicesToDispose = new List<Type>();
2021
readonly Dictionary<Type, object> taskCompletionSources = new Dictionary<Type, object>(); // object = TaskCompletionSource<T> for various T
@@ -25,9 +26,9 @@ public SharpDevelopServiceContainer()
2526
services.Add(typeof(IServiceContainer), this);
2627
}
2728

28-
public SharpDevelopServiceContainer(IServiceProvider parentProvider) : this()
29+
public void AddFallbackProvider(IServiceProvider provider)
2930
{
30-
this.parentProvider = parentProvider;
31+
this.fallbackProviders.Push(provider);
3132
}
3233

3334
public object GetService(Type serviceType)
@@ -50,8 +51,12 @@ public object GetService(Type serviceType)
5051
}
5152
if (instance != null)
5253
return instance;
53-
else
54-
return parentProvider != null ? parentProvider.GetService(serviceType) : null;
54+
foreach (var fallbackProvider in fallbackProviders) {
55+
instance = fallbackProvider.GetService(serviceType);
56+
if (instance != null)
57+
return instance;
58+
}
59+
return null;
5560
}
5661

5762
public void Dispose()

src/Main/Base/Project/Workbench/IOutputPad.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@
33

44
using System;
55
using ICSharpCode.AvalonEdit.Highlighting;
6+
using ICSharpCode.Core;
67

78
namespace ICSharpCode.SharpDevelop.Workbench
89
{
910
/// <summary>
1011
/// The 'Output' pad.
1112
/// Allows showing a text log to the user.
1213
/// </summary>
14+
/// <remarks>This service is thread-safe.</remarks>
15+
[SDService("SD.OutputPad")]
1316
public interface IOutputPad
1417
{
1518
/// <summary>
@@ -39,6 +42,10 @@ public interface IOutputPad
3942
IOutputCategory BuildCategory { get; }
4043
}
4144

45+
/// <summary>
46+
/// Represents a category in the <see cref="IOutputPad"/>.
47+
/// </summary>
48+
/// <remarks>This interface is thread-safe.</remarks>
4249
public interface IOutputCategory
4350
{
4451
/// <summary>

src/Main/SharpDevelop/Sda/CallHelper.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ public override object InitializeLifetimeService()
3838
public void InitSharpDevelopCore(SharpDevelopHost.CallbackHelper callback, StartupSettings properties)
3939
{
4040
// Initialize the most important services:
41-
var container = new SharpDevelopServiceContainer(ServiceSingleton.FallbackServiceProvider);
41+
var container = new SharpDevelopServiceContainer();
42+
container.AddFallbackProvider(ServiceSingleton.FallbackServiceProvider);
4243
container.AddService(typeof(IMessageService), new SDMessageService());
4344
container.AddService(typeof(ILoggingService), new log4netLoggingService());
4445
ServiceSingleton.ServiceProvider = container;

src/Main/SharpDevelop/SharpDevelop.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@
212212
<Compile Include="Workbench\FullScreenEnabledWindow.cs" />
213213
<Compile Include="Workbench\IWorkbenchLayout.cs" />
214214
<Compile Include="Workbench\LayoutConfiguration.cs" />
215+
<Compile Include="Workbench\PadServiceProvider.cs" />
215216
<Compile Include="Workbench\RecentOpen.cs" />
216217
<Compile Include="Workbench\SDStatusBar.cs" />
217218
<Compile Include="Workbench\ShutdownService.cs" />
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
2+
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
3+
4+
using System;
5+
using System.Collections.Generic;
6+
7+
namespace ICSharpCode.SharpDevelop.Workbench
8+
{
9+
/// <summary>
10+
/// A service provider that provides the pad services (as declared by the 'serviceInterface' attribute in the &lt;Pad&gt; codon).
11+
/// </summary>
12+
/// <remarks>
13+
/// We register this as a fallback provider for the SD.Services container instead of directly registering the pads (using ServiceCreationCallback)
14+
/// so that the thread-safety check in the .PadContent property accessor runs on every access to the service.
15+
/// </remarks>
16+
class PadServiceProvider : IServiceProvider
17+
{
18+
readonly List<PadDescriptor> pads = new List<PadDescriptor>();
19+
20+
public PadServiceProvider(IEnumerable<PadDescriptor> descriptors)
21+
{
22+
foreach (var descriptor in descriptors) {
23+
if (descriptor.ServiceInterface != null) {
24+
pads.Add(descriptor);
25+
}
26+
}
27+
}
28+
29+
public object GetService(Type serviceType)
30+
{
31+
foreach (var pad in pads) {
32+
if (serviceType == pad.ServiceInterface)
33+
return pad.PadContent;
34+
}
35+
return null;
36+
}
37+
}
38+
}

src/Main/SharpDevelop/Workbench/WorkbenchStartup.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,16 @@ static void InitializeWorkbench(WpfWorkbench workbench, IWorkbenchLayout layout)
4747

4848
UILanguageService.ValidateLanguage();
4949

50-
SD.GetService<IOutputPad>(); // HACK: eagerly load output pad because pad services cannnot be instanciated from background threads
5150
TaskService.Initialize();
5251
Project.CustomToolsService.Initialize();
5352

5453
workbench.Initialize();
5554
workbench.SetMemento(SD.PropertyService.NestedProperties(workbenchMemento));
5655
workbench.WorkbenchLayout = layout;
5756

57+
// HACK: eagerly load output pad because pad services cannnot be instanciated from background threads
58+
SD.Services.AddService(typeof(IOutputPad), CompilerMessageView.Instance);
59+
5860
var dlgMsgService = SD.MessageService as IDialogMessageService;
5961
if (dlgMsgService != null) {
6062
dlgMsgService.DialogSynchronizeInvoke = SD.MainThread.SynchronizingObject;

src/Main/SharpDevelop/Workbench/WpfWorkbench.cs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,10 @@ public void Initialize()
105105
{
106106
UpdateFlowDirection();
107107

108-
foreach (PadDescriptor content in AddInTree.BuildItems<PadDescriptor>(viewContentPath, this, false)) {
109-
if (content != null) {
110-
ShowPad(content);
111-
}
108+
var padDescriptors = AddInTree.BuildItems<PadDescriptor>(viewContentPath, this, false);
109+
((SharpDevelopServiceContainer)SD.Services).AddFallbackProvider(new PadServiceProvider(padDescriptors));
110+
foreach (PadDescriptor content in padDescriptors) {
111+
ShowPad(content);
112112
}
113113

114114
mainMenu.ItemsSource = MenuService.CreateMenuItems(this, this, mainMenuPath, activationMethod: "MainMenu", immediatelyExpandMenuBuildersForShortcuts: true);
@@ -432,9 +432,6 @@ public void ShowPad(PadDescriptor content)
432432
throw new ArgumentException("Pad is already loaded");
433433

434434
padDescriptorCollection.Add(content);
435-
if (content.ServiceInterface != null) {
436-
SD.Services.AddService(content.ServiceInterface, delegate { return content.PadContent; });
437-
}
438435

439436
if (WorkbenchLayout != null) {
440437
WorkbenchLayout.ShowPad(content);

0 commit comments

Comments
 (0)