Skip to content

Instantly share code, notes, and snippets.

@bradwilson
Created September 24, 2013 23:25
Show Gist options
  • Select an option

  • Save bradwilson/6692765 to your computer and use it in GitHub Desktop.

Select an option

Save bradwilson/6692765 to your computer and use it in GitHub Desktop.
This is a very hacked together replacement kernel for when your tests are making lots of kernels across many threads, and you hit stack traces like these: https://gist.github.com/bradwilson/6691434 . It's not pretty, but it does the job. It steals the implementation of the cache pruner that's built into Ninject and wraps locks around manipulatio…
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Ninject.Activation.Caching;
using Ninject.Components;
using Ninject.Modules;
namespace Ninject
{
public class StandardTestKernel : StandardKernel
{
public StandardTestKernel(params INinjectModule[] modules)
: base(modules)
{
Components.RemoveAll<ICachePruner>();
Components.Add<ICachePruner, ThreadSafeGarbageCollectionCachePruner>();
}
// Bug in Ninject 2.2.1.4, copied from their GarbageCollectionCachePruner but made (grossly) thread safe
class ThreadSafeGarbageCollectionCachePruner : NinjectComponent, ICachePruner
{
readonly List<IPruneable> caches = new List<IPruneable>();
readonly WeakReference indicator = new WeakReference(new object());
Timer timer;
public override void Dispose(bool disposing)
{
if (disposing)
Stop();
base.Dispose(disposing);
}
private int GetTimeoutInMilliseconds()
{
TimeSpan interval = Settings.CachePruningInterval;
if (interval != TimeSpan.MaxValue)
return (int)interval.TotalMilliseconds;
return -1;
}
private void PruneCacheIfGarbageCollectorHasRun(object state)
{
lock (caches)
try
{
if (!indicator.IsAlive)
{
foreach (var cache in caches)
cache.Prune();
indicator.Target = new object();
}
}
finally
{
if (timer != null)
timer.Change(GetTimeoutInMilliseconds(), -1);
}
}
public void Start(IPruneable cache)
{
lock (caches)
{
caches.Add(cache);
if (timer == null)
timer = new Timer(new TimerCallback(PruneCacheIfGarbageCollectorHasRun), null, GetTimeoutInMilliseconds(), -1);
}
}
public void Stop()
{
lock (caches)
{
timer.Change(-1, -1);
timer.Dispose();
timer = null;
caches.Clear();
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment