More waterbox savestate stuff
This commit is contained in:
parent
fa24f5fc9d
commit
b1ff4fbff8
BizHawk.Emulation.Cores/Waterbox
|
@ -16,7 +16,7 @@ using BizHawk.Emulation.Common;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Waterbox
|
||||
{
|
||||
public sealed class ElfRunner : Swappable, IImportResolver, IBinaryStateable, IDisposable
|
||||
public sealed class ElfRunner : Swappable, IImportResolver, IBinaryStateable
|
||||
{
|
||||
// TODO: a lot of things only work with our elves and aren't fully generalized
|
||||
|
||||
|
@ -265,13 +265,6 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
_symlist = symbols.ToList();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// we don't need to activate to dispose
|
||||
Dispose(true);
|
||||
//GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
public void Seal()
|
||||
{
|
||||
Enter();
|
||||
|
@ -285,13 +278,9 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
}
|
||||
}
|
||||
|
||||
//~ElfRunner()
|
||||
//{
|
||||
// Dispose(false);
|
||||
//}
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
if (disposing)
|
||||
{
|
||||
foreach (var d in _disposeList)
|
||||
|
@ -305,7 +294,6 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#region clib monkeypatches
|
||||
|
||||
// our clib expects a few function pointers to be defined for it
|
||||
|
|
|
@ -34,6 +34,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
Memory = new MemoryBlock(start, size);
|
||||
Used = 0;
|
||||
Name = name;
|
||||
Console.WriteLine("Created heap `{1}` at {0:x16}:{2:x16}", start, name, start + size);
|
||||
}
|
||||
|
||||
private void EnsureAlignment(int align)
|
||||
|
@ -118,7 +119,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
var hash = br.ReadBytes(_hash.Length);
|
||||
if (!hash.SequenceEqual(_hash))
|
||||
{
|
||||
throw new InvalidOperationException(string.Format("Hash did not match for heap {0}. Is this the same rom?"));
|
||||
throw new InvalidOperationException(string.Format("Hash did not match for heap {0}. Is this the same rom?", Name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
entryThunk();
|
||||
}
|
||||
|
||||
public PeWrapper(string moduleName, byte[] fileData)
|
||||
public PeWrapper(string moduleName, byte[] fileData, ulong destAddress)
|
||||
{
|
||||
ModuleName = moduleName;
|
||||
_fileData = fileData;
|
||||
|
@ -70,12 +70,13 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
}
|
||||
|
||||
_fileHash = WaterboxUtils.Hash(fileData);
|
||||
Mount(destAddress);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// set memory protections, finishing the Mount process
|
||||
/// set memory protections.
|
||||
/// </summary>
|
||||
public void FinishMount()
|
||||
private void ProtectMemory()
|
||||
{
|
||||
Memory.Protect(Memory.Start, Memory.Size, MemoryBlock.Protection.R);
|
||||
|
||||
|
@ -103,7 +104,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
/// load the PE into memory
|
||||
/// </summary>
|
||||
/// <param name="org">start address</param>
|
||||
public void Mount(ulong org)
|
||||
private void Mount(ulong org)
|
||||
{
|
||||
Start = org;
|
||||
LoadOffset = (long)Start - (long)_pe.ImageNtHeaders.OptionalHeader.ImageBase;
|
||||
|
@ -159,6 +160,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
}
|
||||
}
|
||||
}
|
||||
ProtectMemory();
|
||||
|
||||
// publish exports
|
||||
EntryPoint = Z.US(Start + _pe.ImageNtHeaders.OptionalHeader.AddressOfEntryPoint);
|
||||
|
@ -263,7 +265,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
WaterboxUtils.CopySome(br.BaseStream, ms, (long)length);
|
||||
}
|
||||
|
||||
FinishMount();
|
||||
ProtectMemory();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -507,6 +509,11 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
private Emu _emu;
|
||||
private Syscalls _syscalls;
|
||||
|
||||
/// <summary>
|
||||
/// timestamp of creation acts as a sort of "object id" in the savestate
|
||||
/// </summary>
|
||||
private readonly long _createstamp = WaterboxUtils.Timestamp();
|
||||
|
||||
public PeRunner(string directory, string filename, ulong heapsize, ulong sealedheapsize, ulong invisibleheapsize)
|
||||
{
|
||||
Initialize(_nextStart);
|
||||
|
@ -530,8 +537,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
var moduleName = todoModules.Dequeue();
|
||||
if (!_exports.ContainsKey(moduleName))
|
||||
{
|
||||
var module = new PeWrapper(moduleName, File.ReadAllBytes(Path.Combine(directory, moduleName)));
|
||||
module.Mount(_nextStart);
|
||||
var module = new PeWrapper(moduleName, File.ReadAllBytes(Path.Combine(directory, moduleName)), _nextStart);
|
||||
ComputeNextStart(module.Size);
|
||||
AddMemoryBlock(module.Memory);
|
||||
_savestateComponents.Add(module);
|
||||
|
@ -546,17 +552,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
}
|
||||
}
|
||||
|
||||
foreach (var module in _modules)
|
||||
{
|
||||
foreach (var name in module.ImportsByModule.Keys)
|
||||
{
|
||||
module.ConnectImports(name, _exports[name]);
|
||||
}
|
||||
}
|
||||
foreach (var module in _modules)
|
||||
{
|
||||
module.FinishMount();
|
||||
}
|
||||
ConnectAllImports();
|
||||
|
||||
// load all heaps
|
||||
_heap = new Heap(_nextStart, heapsize, "brk-heap");
|
||||
|
@ -618,11 +614,23 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
}
|
||||
}
|
||||
|
||||
private void ConnectAllImports()
|
||||
{
|
||||
foreach (var module in _modules)
|
||||
{
|
||||
foreach (var name in module.ImportsByModule.Keys)
|
||||
{
|
||||
module.ConnectImports(name, _exports[name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SaveStateBinary(BinaryWriter bw)
|
||||
{
|
||||
bw.Write(_createstamp);
|
||||
bw.Write(_savestateComponents.Count);
|
||||
using (this.EnterExit())
|
||||
{
|
||||
bw.Write(_savestateComponents.Count);
|
||||
foreach (var c in _savestateComponents)
|
||||
{
|
||||
c.SaveStateBinary(bw);
|
||||
|
@ -632,6 +640,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
|
||||
public void LoadStateBinary(BinaryReader br)
|
||||
{
|
||||
var differentCore = br.ReadInt64() != _createstamp; // true if a different core instance created the state
|
||||
if (br.ReadInt32() != _savestateComponents.Count)
|
||||
throw new InvalidOperationException("Internal savestate error");
|
||||
using (this.EnterExit())
|
||||
|
@ -640,14 +649,20 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
{
|
||||
c.LoadStateBinary(br);
|
||||
}
|
||||
if (differentCore)
|
||||
{
|
||||
// if a different runtime instance than this one saved the state,
|
||||
// Exvoker imports need to be reconnected
|
||||
Console.WriteLine("Restoring PeRunner state from a different core...");
|
||||
ConnectAllImports();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _disposed = false;
|
||||
|
||||
public void Dispose()
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (!_disposed)
|
||||
base.Dispose(disposing);
|
||||
if (disposing)
|
||||
{
|
||||
foreach (var d in _disposeList)
|
||||
d.Dispose();
|
||||
|
@ -658,7 +673,6 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
_heap = null;
|
||||
_sealedheap = null;
|
||||
_invisibleheap = null;
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,13 +12,18 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
/// represents an object that can be swapped in and out of memory to compete with other objects in the same memory
|
||||
/// not suited for general purpose stuff
|
||||
/// </summary>
|
||||
public abstract class Swappable : IMonitor
|
||||
public abstract class Swappable : IMonitor, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// start address, or 0 if we don't need to be swapped
|
||||
/// </summary>
|
||||
private ulong _lockkey = 0;
|
||||
|
||||
/// <summary>
|
||||
/// the the relevant lockinfo for this core
|
||||
/// </summary>
|
||||
private LockInfo _currentLockInfo;
|
||||
|
||||
/// <summary>
|
||||
/// everything to swap in for context switches
|
||||
/// </summary>
|
||||
|
@ -37,6 +42,10 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
protected void Initialize(ulong lockkey)
|
||||
{
|
||||
_lockkey = lockkey;
|
||||
if (lockkey != 0)
|
||||
{
|
||||
_currentLockInfo = LockInfos.GetOrAdd(_lockkey, new LockInfo { Sync = new object() });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -50,30 +59,38 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
private class LockInfo
|
||||
{
|
||||
public object Sync;
|
||||
public Swappable Loaded;
|
||||
private WeakReference LoadedRef = new WeakReference(null);
|
||||
public Swappable Loaded
|
||||
{
|
||||
get
|
||||
{
|
||||
// if somehow an object died without being disposed,
|
||||
// the MemoryBlock finalizer will have unloaded the memory
|
||||
// and so we can treat it as if no Swappable was attached
|
||||
return (Swappable)LoadedRef.Target;
|
||||
}
|
||||
set
|
||||
{
|
||||
LoadedRef.Target = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly ConcurrentDictionary<ulong, LockInfo> LockInfos = new ConcurrentDictionary<ulong, LockInfo>();
|
||||
|
||||
static Swappable()
|
||||
{
|
||||
LockInfos.GetOrAdd(0, new LockInfo()); // any errant attempt to lock when ShouldMonitor == false will result in NRE
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// acquire lock and swap this into memory
|
||||
/// </summary>
|
||||
public void Enter()
|
||||
{
|
||||
var li = LockInfos.GetOrAdd(_lockkey, new LockInfo { Sync = new object() });
|
||||
Monitor.Enter(li.Sync);
|
||||
if (li.Loaded != this)
|
||||
Monitor.Enter(_currentLockInfo.Sync);
|
||||
if (_currentLockInfo.Loaded != this)
|
||||
{
|
||||
if (li.Loaded != null)
|
||||
li.Loaded.DeactivateInternal();
|
||||
li.Loaded = null;
|
||||
if (_currentLockInfo.Loaded != null)
|
||||
_currentLockInfo.Loaded.DeactivateInternal();
|
||||
_currentLockInfo.Loaded = null;
|
||||
ActivateInternal();
|
||||
li.Loaded = this;
|
||||
_currentLockInfo.Loaded = this;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,8 +99,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
/// </summary>
|
||||
public void Exit()
|
||||
{
|
||||
var li = LockInfos.GetOrAdd(_lockkey, new LockInfo { Sync = new object() });
|
||||
Monitor.Exit(li.Sync);
|
||||
Monitor.Exit(_currentLockInfo.Sync);
|
||||
}
|
||||
|
||||
private void DeactivateInternal()
|
||||
|
@ -100,5 +116,31 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
m.Activate();
|
||||
}
|
||||
|
||||
private bool _disposed = false;
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
lock (_currentLockInfo.Sync)
|
||||
{
|
||||
if (_currentLockInfo.Loaded == this)
|
||||
{
|
||||
DeactivateInternal();
|
||||
_currentLockInfo.Loaded = null;
|
||||
}
|
||||
_currentLockInfo = null;
|
||||
}
|
||||
}
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,5 +51,10 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
*p++ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static long Timestamp()
|
||||
{
|
||||
return DateTime.UtcNow.Ticks;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue