Patch manager state is static, registration methods are non-static.

Patch manager tracks patch context ownership by assembly internally
This commit is contained in:
Westin Miller
2017-10-09 01:06:01 -07:00
parent 013dc43c2f
commit 2004f71290
5 changed files with 86 additions and 21 deletions

View File

@@ -163,10 +163,14 @@
<Compile Include="ITorchConfig.cs" />
<Compile Include="Managers\DependencyManagerExtensions.cs" />
<Compile Include="Managers\DependencyProviderExtensions.cs" />
<Compile Include="Managers\Event\EventHandlerAttribute.cs" />
<Compile Include="Managers\Event\IEvent.cs" />
<Compile Include="Managers\Event\IEventHandler.cs" />
<Compile Include="Managers\IChatManagerClient.cs" />
<Compile Include="Managers\IChatManagerServer.cs" />
<Compile Include="Managers\IDependencyManager.cs" />
<Compile Include="Managers\IDependencyProvider.cs" />
<Compile Include="Managers\Event\IEventManager.cs" />
<Compile Include="Managers\IManager.cs" />
<Compile Include="Managers\IMultiplayerManagerClient.cs" />
<Compile Include="Managers\IMultiplayerManagerBase.cs" />

View File

@@ -39,7 +39,12 @@ namespace Torch.Managers.Event
}
}
/// <inheritdoc/>
/// <summary>
/// Gets all event handler methods declared by the given type and its base types.
/// </summary>
/// <param name="exploreType">Type to explore</param>
/// <returns>All event handler methods</returns>
private static IEnumerable<MethodInfo> EventHandlers(Type exploreType)
{
IEnumerable<MethodInfo> enumerable = exploreType.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance)
@@ -149,9 +154,9 @@ namespace Torch.Managers.Event
/// Unregisters all handlers owned by the given assembly.
/// </summary>
/// <param name="asm">Assembly to unregister</param>
/// <param name="callback">Optional callback invoked for every registered handler in the assembly. Ignored if null</param>
/// <param name="callback">Optional callback invoked before a handler is unregistered. Ignored if null</param>
/// <returns>the number of handlers that were unregistered</returns>
internal int UnregisterAllHandlers(Assembly asm, Func<IEventHandler> callback = null)
internal int UnregisterAllHandlers(Assembly asm, Action<IEventHandler> callback = null)
{
lock (_registeredHandlers)
{
@@ -159,7 +164,7 @@ namespace Torch.Managers.Event
return 0;
foreach (IEventHandler k in handlers)
{
callback?.Invoke();
callback?.Invoke(k);
UnregisterHandlerInternal(k);
}
int count = handlers.Count;

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Torch.Managers.PatchManager
@@ -31,6 +32,16 @@ namespace Torch.Managers.PatchManager
return res;
}
/// <summary>
/// Gets all methods that this context has patched
/// </summary>
internal IEnumerable<MethodBase> PatchedMethods => _rewritePatterns
.Where(x => x.Value.Prefixes.Count > 0 || x.Value.Suffixes.Count > 0 || x.Value.Transpilers.Count > 0)
.Select(x => x.Key);
/// <summary>
/// Removes all patches in this context
/// </summary>
internal void RemoveAll()
{
foreach (MethodRewritePattern pattern in _rewritePatterns.Values)

View File

@@ -1,6 +1,9 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
using Torch.API;
using Torch.Managers.PatchManager.Transpile;
namespace Torch.Managers.PatchManager
{
@@ -17,8 +20,8 @@ namespace Torch.Managers.PatchManager
{
}
private readonly Dictionary<MethodBase, DecoratedMethod> _rewritePatterns = new Dictionary<MethodBase, DecoratedMethod>();
private readonly HashSet<PatchContext> _contexts = new HashSet<PatchContext>();
private static readonly Dictionary<MethodBase, DecoratedMethod> _rewritePatterns = new Dictionary<MethodBase, DecoratedMethod>();
private readonly Dictionary<Assembly, List<PatchContext>> _contexts = new Dictionary<Assembly, List<PatchContext>>();
/// <summary>
/// Gets the rewrite pattern for the given method, creating one if it doesn't exist.
@@ -27,21 +30,31 @@ namespace Torch.Managers.PatchManager
/// <returns></returns>
public MethodRewritePattern GetPattern(MethodBase method)
{
if (_rewritePatterns.TryGetValue(method, out DecoratedMethod pattern))
return pattern;
var res = new DecoratedMethod(method);
_rewritePatterns.Add(method, res);
return res;
lock (_rewritePatterns)
{
if (_rewritePatterns.TryGetValue(method, out DecoratedMethod pattern))
return pattern;
var res = new DecoratedMethod(method);
_rewritePatterns.Add(method, res);
return res;
}
}
/// <summary>
/// Creates a new <see cref="PatchContext"/> used for tracking changes. A call to <see cref="Commit"/> will apply the patches.
/// </summary>
[MethodImpl(MethodImplOptions.NoInlining)]
public PatchContext AcquireContext()
{
Assembly assembly = Assembly.GetCallingAssembly();
var context = new PatchContext(this);
_contexts.Add(context);
lock (_contexts)
{
if (!_contexts.TryGetValue(assembly, out List<PatchContext> localContexts))
_contexts.Add(assembly, localContexts = new List<PatchContext>());
localContexts.Add(context);
}
return context;
}
@@ -49,10 +62,43 @@ namespace Torch.Managers.PatchManager
/// Frees the given context, and unregister all patches from it. A call to <see cref="Commit"/> will apply the unpatching operation.
/// </summary>
/// <param name="context">Context to remove</param>
[MethodImpl(MethodImplOptions.NoInlining)]
public void FreeContext(PatchContext context)
{
Assembly assembly = Assembly.GetCallingAssembly();
context.RemoveAll();
_contexts.Remove(context);
lock (_contexts)
{
if (_contexts.TryGetValue(assembly, out List<PatchContext> localContexts))
localContexts.Remove(context);
}
}
/// <summary>
/// Frees all contexts owned by the given assembly. A call to <see cref="Commit"/> will apply the unpatching operation.
/// </summary>
/// <param name="assembly">Assembly to retrieve owned contexts for</param>
/// <param name="callback">Callback to run for before each context is freed, ignored if null.</param>
/// <returns>number of contexts freed</returns>
internal int FreeAllContexts(Assembly assembly, Action<PatchContext> callback = null)
{
List<PatchContext> localContexts;
lock (_contexts)
{
if (!_contexts.TryGetValue(assembly, out localContexts))
return 0;
_contexts.Remove(assembly);
}
if (localContexts == null)
return 0;
int count = localContexts.Count;
foreach (PatchContext k in localContexts)
{
callback?.Invoke(k);
k.RemoveAll();
}
localContexts.Clear();
return count;
}
/// <summary>
@@ -80,7 +126,8 @@ namespace Torch.Managers.PatchManager
foreach (DecoratedMethod m in _rewritePatterns.Values)
m.Revert();
_rewritePatterns.Clear();
_contexts.Clear();
lock (_contexts)
_contexts.Clear();
}
}
}

View File

@@ -160,12 +160,10 @@
<Compile Include="Extensions\DispatcherExtensions.cs" />
<Compile Include="Extensions\ICollectionExtensions.cs" />
<Compile Include="Managers\DependencyManager.cs" />
<Compile Include="Managers\EventManager\EventHandlerAttribute.cs" />
<Compile Include="Managers\EventManager\EventList.cs" />
<Compile Include="Managers\EventManager\EventManager.cs" />
<Compile Include="Managers\EventManager\EventShimProgrammableBlock.cs" />
<Compile Include="Managers\EventManager\IEvent.cs" />
<Compile Include="Managers\EventManager\IEventList.cs" />
<Compile Include="Managers\Event\EventList.cs" />
<Compile Include="Managers\Event\EventManager.cs" />
<Compile Include="Managers\Event\EventShimProgrammableBlock.cs" />
<Compile Include="Managers\Event\IEventList.cs" />
<Compile Include="Managers\KeenLogManager.cs" />
<Compile Include="Managers\PatchManager\AssemblyMemory.cs" />
<Compile Include="Managers\PatchManager\DecoratedMethod.cs" />