Browse Source

Add 'IShutdownService'.

newNRvisualizers
Daniel Grunwald 13 years ago
parent
commit
7eea339c6e
  1. 0
      src/AddIns/Analysis/UnitTesting/Model/ITestFramework.cs
  2. 0
      src/AddIns/Analysis/UnitTesting/Service/ITestService.cs
  3. 0
      src/AddIns/Analysis/UnitTesting/Service/SDTestService.cs
  4. 0
      src/AddIns/Analysis/UnitTesting/Service/TestFrameworkDescriptor.cs
  5. 0
      src/AddIns/Analysis/UnitTesting/Service/TestFrameworkDoozer.cs
  6. 12
      src/AddIns/Analysis/UnitTesting/UnitTesting.csproj
  7. 2
      src/Main/Base/Project/ICSharpCode.SharpDevelop.addin
  8. 2
      src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj
  9. 63
      src/Main/Base/Project/Src/Services/IShutdownService.cs
  10. 8
      src/Main/Base/Project/Src/Services/ParserService/ParseProjectContent.cs
  11. 4
      src/Main/Base/Project/Src/Services/SD.cs
  12. 20
      src/Main/Base/Project/Src/Util/IOTaskScheduler.cs
  13. 16
      src/Main/SharpDevelop/Parser/AssemblyParserService.cs
  14. 3
      src/Main/SharpDevelop/Sda/CallHelper.cs
  15. 1
      src/Main/SharpDevelop/SharpDevelop.csproj
  16. 84
      src/Main/SharpDevelop/Workbench/ShutdownService.cs
  17. 8
      src/Main/SharpDevelop/Workbench/WpfWorkbench.cs

0
src/AddIns/Analysis/UnitTesting/Frameworks/ITestFramework.cs → src/AddIns/Analysis/UnitTesting/Model/ITestFramework.cs

0
src/AddIns/Analysis/UnitTesting/Frameworks/ITestService.cs → src/AddIns/Analysis/UnitTesting/Service/ITestService.cs

0
src/AddIns/Analysis/UnitTesting/Frameworks/SDTestService.cs → src/AddIns/Analysis/UnitTesting/Service/SDTestService.cs

0
src/AddIns/Analysis/UnitTesting/Frameworks/TestFrameworkDescriptor.cs → src/AddIns/Analysis/UnitTesting/Service/TestFrameworkDescriptor.cs

0
src/AddIns/Analysis/UnitTesting/Frameworks/TestFrameworkDoozer.cs → src/AddIns/Analysis/UnitTesting/Service/TestFrameworkDoozer.cs

12
src/AddIns/Analysis/UnitTesting/UnitTesting.csproj

@ -70,14 +70,14 @@
<Compile Include="Commands\RunningTestsCondition.cs" /> <Compile Include="Commands\RunningTestsCondition.cs" />
<Compile Include="Commands\TestableCondition.cs" /> <Compile Include="Commands\TestableCondition.cs" />
<Compile Include="Commands\UnitTestCommands.cs" /> <Compile Include="Commands\UnitTestCommands.cs" />
<Compile Include="Frameworks\ITestService.cs" /> <Compile Include="Service\ITestService.cs" />
<Compile Include="Interfaces\IUnitTestProcessRunner.cs" /> <Compile Include="Interfaces\IUnitTestProcessRunner.cs" />
<Compile Include="Interfaces\UnitTestProcessRunner.cs" /> <Compile Include="Interfaces\UnitTestProcessRunner.cs" />
<Compile Include="Model\ITest.cs" /> <Compile Include="Model\ITest.cs" />
<Compile Include="Model\ITestFramework.cs" />
<Compile Include="Model\ITestProject.cs" /> <Compile Include="Model\ITestProject.cs" />
<Compile Include="Model\ITestSolution.cs" /> <Compile Include="Model\ITestSolution.cs" />
<Compile Include="Model\TestBase.cs" /> <Compile Include="Model\TestBase.cs" />
<Compile Include="Frameworks\ITestFramework.cs" />
<Compile Include="Interfaces\IBuildOptions.cs" /> <Compile Include="Interfaces\IBuildOptions.cs" />
<Compile Include="Interfaces\IBuildProjectFactory.cs" /> <Compile Include="Interfaces\IBuildProjectFactory.cs" />
<Compile Include="Interfaces\IFileSystem.cs" /> <Compile Include="Interfaces\IFileSystem.cs" />
@ -105,9 +105,9 @@
<Compile Include="Interfaces\UnitTestSaveAllFilesCommand.cs" /> <Compile Include="Interfaces\UnitTestSaveAllFilesCommand.cs" />
<Compile Include="Interfaces\UnitTestTaskService.cs" /> <Compile Include="Interfaces\UnitTestTaskService.cs" />
<Compile Include="Model\TestSolution.cs" /> <Compile Include="Model\TestSolution.cs" />
<Compile Include="Frameworks\TestFrameworkDescriptor.cs" /> <Compile Include="Service\TestFrameworkDescriptor.cs" />
<Compile Include="Frameworks\TestFrameworkDoozer.cs" /> <Compile Include="Service\TestFrameworkDoozer.cs" />
<Compile Include="Frameworks\SDTestService.cs" /> <Compile Include="Service\SDTestService.cs" />
<Compile Include="TestRunner\ITestResultsMonitor.cs" /> <Compile Include="TestRunner\ITestResultsMonitor.cs" />
<Compile Include="TestRunner\ITestRunner.cs" /> <Compile Include="TestRunner\ITestRunner.cs" />
<Compile Include="TestRunner\MessageReceivedEventArgs.cs" /> <Compile Include="TestRunner\MessageReceivedEventArgs.cs" />
@ -181,7 +181,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="Commands" /> <Folder Include="Commands" />
<Folder Include="Frameworks" /> <Folder Include="Service" />
<Folder Include="Pad" /> <Folder Include="Pad" />
<Folder Include="Interfaces" /> <Folder Include="Interfaces" />
<Folder Include="Model" /> <Folder Include="Model" />

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

@ -62,6 +62,8 @@
class="ICSharpCode.SharpDevelop.Parser.AssemblyParserService"/> class="ICSharpCode.SharpDevelop.Parser.AssemblyParserService"/>
<Service id="ICSharpCode.SharpDevelop.IFileService" <Service id="ICSharpCode.SharpDevelop.IFileService"
class="ICSharpCode.SharpDevelop.Workbench.FileService"/> class="ICSharpCode.SharpDevelop.Workbench.FileService"/>
<Service id="ICSharpCode.SharpDevelop.IShutdownService"
class="ICSharpCode.SharpDevelop.Workbench.ShutdownService"/>
</Path> </Path>
<Path name = "/SharpDevelop/Workbench/Ambiences"> <Path name = "/SharpDevelop/Workbench/Ambiences">

2
src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj

@ -411,6 +411,7 @@
<Compile Include="Src\Services\File\OnDiskTextSourceVersion.cs" /> <Compile Include="Src\Services\File\OnDiskTextSourceVersion.cs" />
<Compile Include="Src\Services\File\OpenedFile.cs" /> <Compile Include="Src\Services\File\OpenedFile.cs" />
<Compile Include="Src\Services\IMessageLoop.cs" /> <Compile Include="Src\Services\IMessageLoop.cs" />
<Compile Include="Src\Services\IShutdownService.cs" />
<Compile Include="Src\Services\LanguageBinding\AggregatedLanguageBinding.cs" /> <Compile Include="Src\Services\LanguageBinding\AggregatedLanguageBinding.cs" />
<Compile Include="Src\Services\LanguageBinding\DefaultLanguageBinding.cs" /> <Compile Include="Src\Services\LanguageBinding\DefaultLanguageBinding.cs" />
<Compile Include="Src\Services\LanguageBinding\ILanguageBinding.cs" /> <Compile Include="Src\Services\LanguageBinding\ILanguageBinding.cs" />
@ -746,6 +747,7 @@
<Compile Include="Src\Util\AtomicBoolean.cs" /> <Compile Include="Src\Util\AtomicBoolean.cs" />
<Compile Include="Src\Util\DotnetDetection.cs" /> <Compile Include="Src\Util\DotnetDetection.cs" />
<Compile Include="Src\Util\FakeXmlViewContent.cs" /> <Compile Include="Src\Util\FakeXmlViewContent.cs" />
<Compile Include="Src\Util\IOTaskScheduler.cs" />
<Compile Include="Src\Util\ReactiveExtensions.cs" /> <Compile Include="Src\Util\ReactiveExtensions.cs" />
<Compile Include="Src\Util\SharpDevelopServiceContainer.cs" /> <Compile Include="Src\Util\SharpDevelopServiceContainer.cs" />
<Compile Include="Src\Util\TreeNode.cs" /> <Compile Include="Src\Util\TreeNode.cs" />

63
src/Main/Base/Project/Src/Services/IShutdownService.cs

@ -0,0 +1,63 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Threading;
using System.Threading.Tasks;
namespace ICSharpCode.SharpDevelop
{
/// <summary>
/// Service that manages the IDE shutdown, and any questions.
/// </summary>
public interface IShutdownService
{
/// <summary>
/// Attemps to close the IDE.
/// </summary>
/// <remarks>
/// This method will
/// - Check if <see cref="PreventShutdown"/> was called and abort the shutdown if it was.
/// - Prompt the user to save the open files. The user has the option to cancel the shutdown at that point.
/// - Closes the solution.
/// - Signals the <see cref="ShutdownToken"/>.
/// - Disposes pads
/// - Wait for background tasks (<see cref="AddBackgroundTask"/>) to finish.
/// - Disposes services
/// - Saves the PropertyService
///
/// This method must be called on the main thread.
/// </remarks>
bool Shutdown();
/// <summary>
/// Prevents shutdown with the following reason.
/// Dispose the returned value to allow shutdown again.
/// </summary>
/// <param name="reason">The reason. This parameter will be passed through the StringParser when the reason is displayed to the user.</param>
/// <exception cref="InvalidOperationException">Shutdown is already in progress</exception>
/// <remarks>This method is thread-safe.</remarks>
IDisposable PreventShutdown(string reason);
/// <summary>
/// Gets the current reason that prevents shutdown.
/// If there isn't any reason, returns null.
/// If there are multiple reasons, this returns one of them.
/// </summary>
/// <remarks>This method is thread-safe.</remarks>
string CurrentReasonPreventingShutdown { get; }
/// <summary>
/// Gets a cancellation token that gets signalled when SharpDevelop is shutting down.
/// </summary>
CancellationToken ShutdownToken { get; }
/// <summary>
/// Adds a background task on which SharpDevelop should wait on shutdown.
///
/// Use this method for tasks that asynchronously write state to disk and should not be
/// interrupted by SharpDevelop closing down.
/// </summary>
void AddBackgroundTask(Task task);
}
}

8
src/Main/Base/Project/Src/Services/ParserService/ParseProjectContent.cs

@ -8,7 +8,6 @@ using System.Linq;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using ICSharpCode.Core; using ICSharpCode.Core;
using ICSharpCode.NRefactory.Editor; using ICSharpCode.NRefactory.Editor;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
@ -16,6 +15,7 @@ using ICSharpCode.NRefactory.TypeSystem.Implementation;
using ICSharpCode.NRefactory.Utils; using ICSharpCode.NRefactory.Utils;
using ICSharpCode.SharpDevelop.Gui; using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Project; using ICSharpCode.SharpDevelop.Project;
using ICSharpCode.SharpDevelop.Util;
namespace ICSharpCode.SharpDevelop.Parser namespace ICSharpCode.SharpDevelop.Parser
{ {
@ -101,7 +101,7 @@ namespace ICSharpCode.SharpDevelop.Parser
{ {
if (cacheFileName == null) if (cacheFileName == null)
return Task.FromResult<object>(null); return Task.FromResult<object>(null);
return Task.Run( Task task = IOTaskScheduler.Factory.StartNew(
delegate { delegate {
pc = pc.RemoveAssemblyReferences(pc.AssemblyReferences); pc = pc.RemoveAssemblyReferences(pc.AssemblyReferences);
int serializableFileCount = 0; int serializableFileCount = 0;
@ -121,7 +121,9 @@ namespace ICSharpCode.SharpDevelop.Parser
} else { } else {
RemoveCache(cacheFileName); RemoveCache(cacheFileName);
} }
}); }, SD.ShutdownService.ShutdownToken);
SD.ShutdownService.AddBackgroundTask(task);
return task;
} }
static bool IsSerializable(IUnresolvedFile unresolvedFile) static bool IsSerializable(IUnresolvedFile unresolvedFile)

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

@ -146,5 +146,9 @@ namespace ICSharpCode.SharpDevelop
public static IAddInTree AddInTree { public static IAddInTree AddInTree {
get { return GetRequiredService<IAddInTree>(); } get { return GetRequiredService<IAddInTree>(); }
} }
public static IShutdownService ShutdownService {
get { return GetRequiredService<IShutdownService>(); }
}
} }
} }

20
src/Main/Base/Project/Src/Util/IOTaskScheduler.cs

@ -0,0 +1,20 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace ICSharpCode.SharpDevelop.Util
{
/// <summary>
/// Scheduler for IO-intensive tasks.
/// </summary>
public class IOTaskScheduler
{
// TODO: use a limited-concurrency scheduler instead
public static TaskFactory Factory {
get { return Task.Factory; }
}
}
}

16
src/Main/SharpDevelop/Parser/AssemblyParserService.cs

@ -11,13 +11,13 @@ using System.Runtime.Serialization;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Xml; using System.Xml;
using ICSharpCode.Core; using ICSharpCode.Core;
using ICSharpCode.NRefactory.Documentation; using ICSharpCode.NRefactory.Documentation;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation; using ICSharpCode.NRefactory.TypeSystem.Implementation;
using ICSharpCode.NRefactory.Utils; using ICSharpCode.NRefactory.Utils;
using ICSharpCode.SharpDevelop.Project; using ICSharpCode.SharpDevelop.Project;
using ICSharpCode.SharpDevelop.Util;
using Mono.Cecil; using Mono.Cecil;
namespace ICSharpCode.SharpDevelop.Parser namespace ICSharpCode.SharpDevelop.Parser
@ -160,7 +160,9 @@ namespace ICSharpCode.SharpDevelop.Parser
} }
} }
l.CancellationToken = cancellationToken; l.CancellationToken = cancellationToken;
l.InterningProvider = null;
pc = l.LoadAssembly(asm); pc = l.LoadAssembly(asm);
//SaveToCacheAsync(cacheFileName, lastWriteTime, pc).FireAndForget();
SaveToCache(cacheFileName, lastWriteTime, pc); SaveToCache(cacheFileName, lastWriteTime, pc);
return pc; return pc;
} }
@ -270,6 +272,18 @@ namespace ICSharpCode.SharpDevelop.Parser
} }
} }
Task SaveToCacheAsync(string cacheFileName, DateTime lastWriteTime, IUnresolvedAssembly pc)
{
if (cacheFileName == null)
return Task.FromResult<object>(null);
// Call SaveToCache on a background task:
var shutdownService = SD.ShutdownService;
var task = IOTaskScheduler.Factory.StartNew(delegate { SaveToCache(cacheFileName, lastWriteTime, pc); }, shutdownService.ShutdownToken);
shutdownService.AddBackgroundTask(task);
return task;
}
void SaveToCache(string cacheFileName, DateTime lastWriteTime, IUnresolvedAssembly pc) void SaveToCache(string cacheFileName, DateTime lastWriteTime, IUnresolvedAssembly pc)
{ {
if (cacheFileName == null) if (cacheFileName == null)

3
src/Main/SharpDevelop/Sda/CallHelper.cs

@ -180,8 +180,11 @@ namespace ICSharpCode.SharpDevelop.Sda
} finally { } finally {
LoggingService.Info("Unloading services..."); LoggingService.Info("Unloading services...");
try { try {
// see IShutdownService.Shutdown for a description of the shut down procedure
WorkbenchSingleton.OnWorkbenchUnloaded(); WorkbenchSingleton.OnWorkbenchUnloaded();
var propertyService = SD.PropertyService; var propertyService = SD.PropertyService;
var shutdownService = (ShutdownService)SD.ShutdownService;
shutdownService.WaitForBackgroundTasks();
((IDisposable)SD.Services).Dispose(); // dispose all services ((IDisposable)SD.Services).Dispose(); // dispose all services
propertyService.Save(); propertyService.Save();
} catch (Exception ex) { } catch (Exception ex) {

1
src/Main/SharpDevelop/SharpDevelop.csproj

@ -98,6 +98,7 @@
<Compile Include="Workbench\LayoutConfiguration.cs" /> <Compile Include="Workbench\LayoutConfiguration.cs" />
<Compile Include="Workbench\RecentOpen.cs" /> <Compile Include="Workbench\RecentOpen.cs" />
<Compile Include="Workbench\SDStatusBar.cs" /> <Compile Include="Workbench\SDStatusBar.cs" />
<Compile Include="Workbench\ShutdownService.cs" />
<Compile Include="Workbench\SingleInstanceHelper.cs" /> <Compile Include="Workbench\SingleInstanceHelper.cs" />
<Compile Include="Workbench\StatusBarService.cs" /> <Compile Include="Workbench\StatusBarService.cs" />
<Compile Include="Workbench\WorkbenchStartup.cs" /> <Compile Include="Workbench\WorkbenchStartup.cs" />

84
src/Main/SharpDevelop/Workbench/ShutdownService.cs

@ -0,0 +1,84 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using ICSharpCode.NRefactory.Utils;
namespace ICSharpCode.SharpDevelop.Workbench
{
sealed class ShutdownService : IShutdownService
{
CancellationTokenSource cts = new CancellationTokenSource();
public CancellationToken ShutdownToken {
get { return cts.Token; }
}
internal void SignalShutdownToken()
{
cts.Cancel();
}
public bool Shutdown()
{
SD.Workbench.MainWindow.Close();
return SD.Workbench.WorkbenchLayout == null;
}
#region PreventShutdown
List<string> reasonsPreventingShutdown = new List<string>();
public IDisposable PreventShutdown(string reason)
{
lock (reasonsPreventingShutdown) {
reasonsPreventingShutdown.Add(reason);
}
return new CallbackOnDispose(
delegate {
lock (reasonsPreventingShutdown) {
reasonsPreventingShutdown.Remove(reason);
}
});
}
public string CurrentReasonPreventingShutdown {
get {
lock (reasonsPreventingShutdown) {
return reasonsPreventingShutdown.FirstOrDefault();
}
}
}
#endregion
#region Background Tasks
int outstandingBackgroundTasks;
ManualResetEventSlim backgroundTaskEvent = new ManualResetEventSlim(true);
public void AddBackgroundTask(Task task)
{
backgroundTaskEvent.Reset();
Interlocked.Increment(ref outstandingBackgroundTasks);
task.ContinueWith(
delegate {
if (Interlocked.Decrement(ref outstandingBackgroundTasks) == 0) {
backgroundTaskEvent.Set();
}
});
}
internal void WaitForBackgroundTasks()
{
if (!backgroundTaskEvent.IsSet) {
SD.LoggingService.Info("Waiting for background tasks to finish...");
backgroundTaskEvent.Wait();
SD.LoggingService.Info("Background tasks have finished.");
}
}
#endregion
}
}

8
src/Main/SharpDevelop/Workbench/WpfWorkbench.cs

@ -561,8 +561,11 @@ namespace ICSharpCode.SharpDevelop.Workbench
{ {
base.OnClosing(e); base.OnClosing(e);
if (!e.Cancel) { if (!e.Cancel) {
if (Project.ProjectService.IsBuilding) { // see IShutdownService.Shutdown() for a description of the shutdown procedure
MessageService.ShowMessage(StringParser.Parse("${res:MainWindow.CannotCloseWithBuildInProgressMessage}"));
var shutdownService = (ShutdownService)SD.ShutdownService;
if (shutdownService.CurrentReasonPreventingShutdown != null) {
MessageService.ShowMessage(StringParser.Parse(shutdownService.CurrentReasonPreventingShutdown));
e.Cancel = true; e.Cancel = true;
return; return;
} }
@ -586,6 +589,7 @@ namespace ICSharpCode.SharpDevelop.Workbench
this.WorkbenchLayout = null; this.WorkbenchLayout = null;
shutdownService.SignalShutdownToken();
foreach (PadDescriptor padDescriptor in this.PadContentCollection) { foreach (PadDescriptor padDescriptor in this.PadContentCollection) {
padDescriptor.Dispose(); padDescriptor.Dispose();
} }

Loading…
Cancel
Save