Merge pull request #5370 from pavlos256/lua-dispose-crash

Possible fix for lua crash #5269
This commit is contained in:
Paul Chote
2014-05-20 12:38:40 +12:00
3 changed files with 56 additions and 23 deletions

View File

@@ -81,11 +81,12 @@ namespace OpenRA.Scripting
public ScriptGlobalAttribute(string name) { Name = name; } public ScriptGlobalAttribute(string name) { Name = name; }
} }
public class ScriptContext public class ScriptContext : IDisposable
{ {
public World World { get; private set; } public World World { get; private set; }
public WorldRenderer WorldRenderer { get; private set; } public WorldRenderer WorldRenderer { get; private set; }
bool disposed;
readonly MemoryConstrainedLuaRuntime runtime; readonly MemoryConstrainedLuaRuntime runtime;
readonly LuaFunction tick; readonly LuaFunction tick;
@@ -188,26 +189,34 @@ namespace OpenRA.Scripting
public void Tick(Actor self) public void Tick(Actor self)
{ {
if (error) if (error || disposed)
return; return;
using (new PerfSample("tick_lua")) using (new PerfSample("tick_lua"))
tick.Call().Dispose(); tick.Call().Dispose();
} }
public void Dispose() protected void Dispose(bool disposing)
{ {
if (runtime == null) if (disposed)
return; return;
if (disposing)
runtime.Dispose();
disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
runtime.Dispose();
} }
~ScriptContext() ~ScriptContext()
{ {
if (runtime != null) // Dispose unmanaged resources only
Game.RunAfterTick(Dispose); Dispose(false);
} }
static Type[] ExtractRequiredTypes(Type t) static Type[] ExtractRequiredTypes(Type t)

View File

@@ -15,12 +15,13 @@ using OpenRA.Traits;
namespace OpenRA.Mods.RA.Activities namespace OpenRA.Mods.RA.Activities
{ {
public class CallLuaFunc : Activity public class CallLuaFunc : Activity, IDisposable
{ {
LuaFunction function; LuaFunction function;
public CallLuaFunc(LuaFunction func) public CallLuaFunc(LuaFunction func)
{ {
function = func.CopyReference() as LuaFunction; function = (LuaFunction)func.CopyReference();
} }
public override Activity Tick(Actor self) public override Activity Tick(Actor self)
@@ -38,20 +39,28 @@ namespace OpenRA.Mods.RA.Activities
base.Cancel(self); base.Cancel(self);
} }
public void Dispose() protected void Dispose(bool disposing)
{ {
if (function == null) if (function == null)
return; return;
if (disposing)
{
function.Dispose();
function = null;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
function.Dispose();
function = null;
} }
~CallLuaFunc() ~CallLuaFunc()
{ {
if (function != null) // Dispose unmanaged resources only
Game.RunAfterTick(Dispose); Dispose(false);
} }
} }
} }

View File

@@ -21,7 +21,7 @@ namespace OpenRA.Mods.RA.Scripting
[Desc("Allows map scripts to attach triggers to this actor via the Triggers global.")] [Desc("Allows map scripts to attach triggers to this actor via the Triggers global.")]
public class ScriptTriggersInfo : TraitInfo<ScriptTriggers> { } public class ScriptTriggersInfo : TraitInfo<ScriptTriggers> { }
public class ScriptTriggers : INotifyIdle, INotifyDamage, INotifyKilled, INotifyProduction public class ScriptTriggers : INotifyIdle, INotifyDamage, INotifyKilled, INotifyProduction, IDisposable
{ {
public event Action<Actor> OnKilledInternal = _ => {}; public event Action<Actor> OnKilledInternal = _ => {};
@@ -101,21 +101,36 @@ namespace OpenRA.Mods.RA.Scripting
} }
bool disposed; bool disposed;
protected void Dispose(bool disposing)
{
if (disposed)
return;
if (disposing)
{
var toDispose = new [] { onIdle, onDamaged, onKilled, onProduction };
foreach (var f in toDispose.SelectMany(f => f))
f.First.Dispose();
foreach (var l in toDispose)
l.Clear();
}
disposed = true;
}
public void Dispose() public void Dispose()
{ {
disposed = true; Dispose(true);
var toDispose = new [] { onIdle, onDamaged, onKilled, onProduction };
foreach (var f in toDispose.SelectMany(f => f))
f.First.Dispose();
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
} }
~ScriptTriggers() ~ScriptTriggers()
{ {
if (!disposed) // Dispose unmanaged resources only
Game.RunAfterTick(Dispose); Dispose(false);
} }
} }
} }