Browse Source

Use custom thread pool for saving the type system caches.

newNRvisualizers
Daniel Grunwald 14 years ago
parent
commit
86b6f990b1
  1. 1
      src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs
  2. 2
      src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj
  3. 11
      src/Main/Base/Project/Src/Services/IShutdownService.cs
  4. 2
      src/Main/Base/Project/Src/Services/ParserService/ParseProjectContent.cs
  5. 67
      src/Main/Base/Project/Src/Util/CustomThreadPoolTaskScheduler.cs
  6. 12
      src/Main/Base/Project/Src/Util/IOTaskScheduler.cs
  7. 82
      src/Main/Base/Project/Src/Util/SimpleTaskScheduler.cs
  8. 5
      src/Main/SharpDevelop/Parser/AssemblyParserService.cs
  9. 12
      src/Main/SharpDevelop/Workbench/ShutdownService.cs

1
src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs

@ -227,6 +227,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
} }
AddToTypeSystemTranslationTable(this.currentAssembly, assemblyDefinition); AddToTypeSystemTranslationTable(this.currentAssembly, assemblyDefinition);
currentAssembly.Freeze();
var result = this.currentAssembly; var result = this.currentAssembly;
this.currentAssembly = null; this.currentAssembly = null;

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

@ -745,11 +745,13 @@
<Compile Include="Src\Services\ProjectService\ProjectLoader.cs" /> <Compile Include="Src\Services\ProjectService\ProjectLoader.cs" />
<Compile Include="Src\Services\ViewContentServiceAttribute.cs" /> <Compile Include="Src\Services\ViewContentServiceAttribute.cs" />
<Compile Include="Src\Util\AtomicBoolean.cs" /> <Compile Include="Src\Util\AtomicBoolean.cs" />
<Compile Include="Src\Util\CustomThreadPoolTaskScheduler.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\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\SimpleTaskScheduler.cs" />
<Compile Include="Src\Util\TreeNode.cs" /> <Compile Include="Src\Util\TreeNode.cs" />
<Compile Include="Src\Util\NativeMethods.cs" /> <Compile Include="Src\Util\NativeMethods.cs" />
<Compile Include="Src\Util\ProcessRunnerException.cs" /> <Compile Include="Src\Util\ProcessRunnerException.cs" />

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

@ -49,9 +49,20 @@ namespace ICSharpCode.SharpDevelop
/// <summary> /// <summary>
/// Gets a cancellation token that gets signalled when SharpDevelop is shutting down. /// Gets a cancellation token that gets signalled when SharpDevelop is shutting down.
///
/// This cancellation token may be used to stop background calculations.
/// </summary> /// </summary>
CancellationToken ShutdownToken { get; } CancellationToken ShutdownToken { get; }
/// <summary>
/// Gets a cancellation token that gets signalled a couple of seconds after the ShutdownToken.
///
/// This cancellation token may be used to stop background calculations that should run
/// for a limited time after SharpDevelop is closed (e.g. saving state in caches
/// - work that should better run even though we're shutting down, but shouldn't take too long either)
/// </summary>
CancellationToken DelayedShutdownToken { get; }
/// <summary> /// <summary>
/// Adds a background task on which SharpDevelop should wait on shutdown. /// Adds a background task on which SharpDevelop should wait on shutdown.
/// ///

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

@ -121,7 +121,7 @@ namespace ICSharpCode.SharpDevelop.Parser
} else { } else {
RemoveCache(cacheFileName); RemoveCache(cacheFileName);
} }
}, SD.ShutdownService.ShutdownToken); }, SD.ShutdownService.DelayedShutdownToken);
SD.ShutdownService.AddBackgroundTask(task); SD.ShutdownService.AddBackgroundTask(task);
return task; return task;
} }

67
src/Main/Base/Project/Src/Util/CustomThreadPoolTaskScheduler.cs

@ -0,0 +1,67 @@
// 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.Util
{
/// <summary>
/// A task scheduler that manages its own thread pool.
/// </summary>
public class CustomThreadPoolTaskScheduler : SimpleTaskScheduler
{
int currentThreadCount;
readonly int maxThreadCount;
public CustomThreadPoolTaskScheduler(int maxThreadCount)
{
this.maxThreadCount = maxThreadCount;
}
public override int MaximumConcurrencyLevel {
get { return maxThreadCount; }
}
protected override void QueueTask(Task task)
{
base.QueueTask(task);
if (IncrementThreadCount()) {
// Successfully incremented the thread count, we may start a thread
StartThread(RunThread);
return;
}
}
protected virtual void StartThread(ThreadStart start)
{
var t = new Thread(RunThread);
t.IsBackground = true;
t.Start();
}
bool IncrementThreadCount()
{
int c = Volatile.Read(ref currentThreadCount);
while (c < maxThreadCount) {
if (Interlocked.CompareExchange(ref currentThreadCount, c + 1, c) == c) {
return true;
}
}
return false;
}
void RunThread()
{
do {
// Run tasks while they are available:
while (TryRunNextTask());
// Decrement the thread count:
Interlocked.Decrement(ref currentThreadCount);
// Tasks might have been added while we were decrementing the thread count,
// so if the queue isn't empty anymore, resume this thread
} while(ScheduledTaskCount > 0 && IncrementThreadCount());
}
}
}

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

@ -12,9 +12,17 @@ namespace ICSharpCode.SharpDevelop.Util
/// </summary> /// </summary>
public class IOTaskScheduler public class IOTaskScheduler
{ {
// TODO: use a limited-concurrency scheduler instead static readonly CustomThreadPoolTaskScheduler scheduler = new CustomThreadPoolTaskScheduler(
Math.Min(Environment.ProcessorCount, 2));
static readonly TaskFactory factory = new TaskFactory(scheduler);
public static TaskScheduler Scheduler {
get { return scheduler; }
}
public static TaskFactory Factory { public static TaskFactory Factory {
get { return Task.Factory; } get { return factory; }
} }
} }
} }

82
src/Main/Base/Project/Src/Util/SimpleTaskScheduler.cs

@ -0,0 +1,82 @@
// 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.Concurrent;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace ICSharpCode.SharpDevelop.Util
{
/// <summary>
/// A simple scheduler that adds tasks to a queue.
/// This scheduler does not create any worker threads on its own,
/// but requires external code to call <see cref="RunNextTask"/>.
/// </summary>
public class SimpleTaskScheduler : TaskScheduler, IDisposable
{
[ThreadStatic]
static SimpleTaskScheduler activeScheduler;
BlockingCollection<Task> queue = new BlockingCollection<Task>();
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{
return activeScheduler == this && base.TryExecuteTask(task);
}
protected override void QueueTask(Task task)
{
queue.Add(task);
}
protected override IEnumerable<Task> GetScheduledTasks()
{
return queue;
}
protected int ScheduledTaskCount {
get { return queue.Count; }
}
/// <summary>
/// Runs the next task in the queue.
/// If no task is available, this method will block.
/// </summary>
/// <param name="cancellationToken">Cancellation token that can be used to cancel
/// waiting for a task to become available. It cannot be used to cancel task execution!</param>
public void RunNextTask(CancellationToken cancellationToken = default(CancellationToken))
{
Task task = queue.Take(cancellationToken);
RunTask(task);
}
public bool TryRunNextTask()
{
Task task;
if (queue.TryTake(out task)) {
RunTask(task);
return true;
} else {
return false;
}
}
void RunTask(Task task)
{
var oldActiveScheduler = activeScheduler;
activeScheduler = this;
try {
base.TryExecuteTask(task);
} finally {
activeScheduler = oldActiveScheduler;
}
}
public virtual void Dispose()
{
queue.Dispose();
}
}
}

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

@ -160,10 +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(); SaveToCacheAsync(cacheFileName, lastWriteTime, pc).FireAndForget();
SaveToCache(cacheFileName, lastWriteTime, pc); //SaveToCache(cacheFileName, lastWriteTime, pc);
return pc; return pc;
} }

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

@ -13,15 +13,21 @@ namespace ICSharpCode.SharpDevelop.Workbench
{ {
sealed class ShutdownService : IShutdownService sealed class ShutdownService : IShutdownService
{ {
CancellationTokenSource cts = new CancellationTokenSource(); CancellationTokenSource shutdownCTS = new CancellationTokenSource();
CancellationTokenSource delayedShutdownCTS = new CancellationTokenSource();
public CancellationToken ShutdownToken { public CancellationToken ShutdownToken {
get { return cts.Token; } get { return shutdownCTS.Token; }
}
public CancellationToken DelayedShutdownToken {
get { return delayedShutdownCTS.Token; }
} }
internal void SignalShutdownToken() internal void SignalShutdownToken()
{ {
cts.Cancel(); shutdownCTS.Cancel();
delayedShutdownCTS.CancelAfter(2000);
} }
public bool Shutdown() public bool Shutdown()

Loading…
Cancel
Save