mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 10:17:22 +01:00
Make crashhandler somewhat more stable, support multi boxing maybe?
This commit is contained in:
parent
c55d6966cd
commit
f3ceb9034e
8 changed files with 105 additions and 61 deletions
|
|
@ -88,18 +88,18 @@ internal sealed class AnimationInvocationBuffer : MemoryMappedBuffer, IAnimation
|
|||
}
|
||||
}
|
||||
|
||||
public static IBufferReader CreateReader()
|
||||
=> new AnimationInvocationBuffer(false);
|
||||
public static IBufferReader CreateReader(int pid)
|
||||
=> new AnimationInvocationBuffer(false, pid);
|
||||
|
||||
public static IAnimationInvocationBufferWriter CreateWriter()
|
||||
=> new AnimationInvocationBuffer();
|
||||
public static IAnimationInvocationBufferWriter CreateWriter(int pid)
|
||||
=> new AnimationInvocationBuffer(pid);
|
||||
|
||||
private AnimationInvocationBuffer(bool writer)
|
||||
: base(_name, _version)
|
||||
private AnimationInvocationBuffer(bool writer, int pid)
|
||||
: base($"{_name}_{pid}_{_version}", _version)
|
||||
{ }
|
||||
|
||||
private AnimationInvocationBuffer()
|
||||
: base(_name, _version, _lineCount, _lineCapacity)
|
||||
private AnimationInvocationBuffer(int pid)
|
||||
: base($"{_name}_{pid}_{_version}", _version, _lineCount, _lineCapacity)
|
||||
{ }
|
||||
|
||||
private static string ToName(AnimationInvocationType type)
|
||||
|
|
|
|||
|
|
@ -69,17 +69,17 @@ internal sealed class CharacterBaseBuffer : MemoryMappedBuffer, ICharacterBaseBu
|
|||
public uint TotalCount
|
||||
=> TotalWrittenLines;
|
||||
|
||||
public static IBufferReader CreateReader()
|
||||
=> new CharacterBaseBuffer(false);
|
||||
public static IBufferReader CreateReader(int pid)
|
||||
=> new CharacterBaseBuffer(false, pid);
|
||||
|
||||
public static ICharacterBaseBufferWriter CreateWriter()
|
||||
=> new CharacterBaseBuffer();
|
||||
public static ICharacterBaseBufferWriter CreateWriter(int pid)
|
||||
=> new CharacterBaseBuffer(pid);
|
||||
|
||||
private CharacterBaseBuffer(bool writer)
|
||||
: base(_name, _version)
|
||||
private CharacterBaseBuffer(bool writer, int pid)
|
||||
: base($"{_name}_{pid}_{_version}", _version)
|
||||
{ }
|
||||
|
||||
private CharacterBaseBuffer()
|
||||
: base(_name, _version, _lineCount, _lineCapacity)
|
||||
private CharacterBaseBuffer(int pid)
|
||||
: base($"{_name}_{pid}_{_version}", _version, _lineCount, _lineCapacity)
|
||||
{ }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ public class MemoryMappedBuffer : IDisposable
|
|||
|
||||
private readonly MemoryMappedFile _file;
|
||||
private readonly MemoryMappedViewAccessor _header;
|
||||
private readonly MemoryMappedViewAccessor[] _lines;
|
||||
private readonly MemoryMappedViewAccessor[] _lines = [];
|
||||
|
||||
public readonly int Version;
|
||||
public readonly uint LineCount;
|
||||
|
|
@ -64,6 +64,7 @@ public class MemoryMappedBuffer : IDisposable
|
|||
public MemoryMappedBuffer(string mapName, int? expectedVersion = null, uint? expectedMinLineCount = null,
|
||||
uint? expectedMinLineCapacity = null)
|
||||
{
|
||||
_lines = [];
|
||||
_file = MemoryMappedFile.OpenExisting(mapName, MemoryMappedFileRights.ReadWrite, HandleInheritability.Inheritable);
|
||||
using var headerLine = _file.CreateViewAccessor(0, 4, MemoryMappedFileAccess.Read);
|
||||
var headerLength = headerLine.ReadUInt32(0);
|
||||
|
|
@ -96,6 +97,7 @@ public class MemoryMappedBuffer : IDisposable
|
|||
void Throw(string text)
|
||||
{
|
||||
_file.Dispose();
|
||||
_header?.Dispose();
|
||||
_disposed = true;
|
||||
throw new Exception(text);
|
||||
}
|
||||
|
|
@ -204,10 +206,10 @@ public class MemoryMappedBuffer : IDisposable
|
|||
if (_disposed)
|
||||
return;
|
||||
|
||||
_header.Dispose();
|
||||
_header?.Dispose();
|
||||
foreach (var line in _lines)
|
||||
line.Dispose();
|
||||
_file.Dispose();
|
||||
line?.Dispose();
|
||||
_file?.Dispose();
|
||||
}
|
||||
|
||||
~MemoryMappedBuffer()
|
||||
|
|
|
|||
|
|
@ -83,17 +83,17 @@ internal sealed class ModdedFileBuffer : MemoryMappedBuffer, IModdedFileBufferWr
|
|||
}
|
||||
}
|
||||
|
||||
public static IBufferReader CreateReader()
|
||||
=> new ModdedFileBuffer(false);
|
||||
public static IBufferReader CreateReader(int pid)
|
||||
=> new ModdedFileBuffer(false, pid);
|
||||
|
||||
public static IModdedFileBufferWriter CreateWriter()
|
||||
=> new ModdedFileBuffer();
|
||||
public static IModdedFileBufferWriter CreateWriter(int pid)
|
||||
=> new ModdedFileBuffer(pid);
|
||||
|
||||
private ModdedFileBuffer(bool writer)
|
||||
: base(_name, _version)
|
||||
private ModdedFileBuffer(bool writer, int pid)
|
||||
: base($"{_name}_{pid}_{_version}", _version)
|
||||
{ }
|
||||
|
||||
private ModdedFileBuffer()
|
||||
: base(_name, _version, _lineCount, _lineCapacity)
|
||||
private ModdedFileBuffer(int pid)
|
||||
: base($"{_name}_{pid}_{_version}", _version, _lineCount, _lineCapacity)
|
||||
{ }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,13 +9,13 @@ public interface IBufferReader
|
|||
public IEnumerable<JsonObject> GetLines(DateTimeOffset crashTime);
|
||||
}
|
||||
|
||||
public sealed class GameEventLogReader : IDisposable
|
||||
public sealed class GameEventLogReader(int pid) : IDisposable
|
||||
{
|
||||
public readonly (IBufferReader Reader, string TypeSingular, string TypePlural)[] Readers =
|
||||
[
|
||||
(CharacterBaseBuffer.CreateReader(), "CharacterLoaded", "CharactersLoaded"),
|
||||
(ModdedFileBuffer.CreateReader(), "ModdedFileLoaded", "ModdedFilesLoaded"),
|
||||
(AnimationInvocationBuffer.CreateReader(), "VFXFuncInvoked", "VFXFuncsInvoked"),
|
||||
(CharacterBaseBuffer.CreateReader(pid), "CharacterLoaded", "CharactersLoaded"),
|
||||
(ModdedFileBuffer.CreateReader(pid), "ModdedFileLoaded", "ModdedFilesLoaded"),
|
||||
(AnimationInvocationBuffer.CreateReader(pid), "VFXFuncInvoked", "VFXFuncsInvoked"),
|
||||
];
|
||||
|
||||
public void Dispose()
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
namespace Penumbra.CrashHandler;
|
||||
|
||||
public sealed class GameEventLogWriter : IDisposable
|
||||
public sealed class GameEventLogWriter(int pid) : IDisposable
|
||||
{
|
||||
public readonly ICharacterBaseBufferWriter CharacterBase = CharacterBaseBuffer.CreateWriter();
|
||||
public readonly IModdedFileBufferWriter FileLoaded = ModdedFileBuffer.CreateWriter();
|
||||
public readonly IAnimationInvocationBufferWriter AnimationFuncInvoked = AnimationInvocationBuffer.CreateWriter();
|
||||
public readonly ICharacterBaseBufferWriter CharacterBase = CharacterBaseBuffer.CreateWriter(pid);
|
||||
public readonly IModdedFileBufferWriter FileLoaded = ModdedFileBuffer.CreateWriter(pid);
|
||||
public readonly IAnimationInvocationBufferWriter AnimationFuncInvoked = AnimationInvocationBuffer.CreateWriter(pid);
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ public class CrashHandler
|
|||
|
||||
try
|
||||
{
|
||||
using var reader = new GameEventLogReader();
|
||||
using var reader = new GameEventLogReader(pid);
|
||||
var parent = Process.GetProcessById(pid);
|
||||
using var handle = parent.SafeHandle;
|
||||
parent.WaitForExit();
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ public sealed class CrashHandlerService : IDisposable, IService
|
|||
private readonly Configuration _config;
|
||||
private readonly ValidityChecker _validityChecker;
|
||||
|
||||
private string _tempExecutableDirectory = string.Empty;
|
||||
|
||||
public CrashHandlerService(FilenameService files, CommunicatorService communicator, ActorManager actors, ResourceLoader resourceLoader,
|
||||
Configuration config, ValidityChecker validityChecker)
|
||||
{
|
||||
|
|
@ -54,6 +56,7 @@ public sealed class CrashHandlerService : IDisposable, IService
|
|||
}
|
||||
|
||||
Unsubscribe();
|
||||
CleanExecutables();
|
||||
}
|
||||
|
||||
private Process? _child;
|
||||
|
|
@ -177,11 +180,12 @@ public sealed class CrashHandlerService : IDisposable, IService
|
|||
|
||||
try
|
||||
{
|
||||
using var reader = new GameEventLogReader();
|
||||
using var reader = new GameEventLogReader(Environment.ProcessId);
|
||||
JsonObject jObj;
|
||||
lock (_eventWriter)
|
||||
{
|
||||
jObj = reader.Dump("Manual Dump", Environment.ProcessId, 0, $"{_validityChecker.Version} ({_validityChecker.CommitHash})", _validityChecker.GameVersion);
|
||||
jObj = reader.Dump("Manual Dump", Environment.ProcessId, 0, $"{_validityChecker.Version} ({_validityChecker.CommitHash})",
|
||||
_validityChecker.GameVersion);
|
||||
}
|
||||
|
||||
var logFile = _files.LogFileName;
|
||||
|
|
@ -198,14 +202,31 @@ public sealed class CrashHandlerService : IDisposable, IService
|
|||
}
|
||||
}
|
||||
|
||||
private string CopyExecutables()
|
||||
private void CleanExecutables()
|
||||
{
|
||||
var parent = Path.GetDirectoryName(_files.CrashHandlerExe)!;
|
||||
var folder = Path.Combine(parent, "temp");
|
||||
Directory.CreateDirectory(folder);
|
||||
foreach (var dir in Directory.EnumerateDirectories(parent, "temp_*"))
|
||||
{
|
||||
try
|
||||
{
|
||||
Directory.Delete(dir, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Penumbra.Log.Debug($"Could not delete {dir}:\n{ex}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string CopyExecutables()
|
||||
{
|
||||
CleanExecutables();
|
||||
var parent = Path.GetDirectoryName(_files.CrashHandlerExe)!;
|
||||
_tempExecutableDirectory = Path.Combine(parent, $"temp_{Environment.ProcessId}");
|
||||
Directory.CreateDirectory(_tempExecutableDirectory);
|
||||
foreach (var file in Directory.EnumerateFiles(parent, "Penumbra.CrashHandler.*"))
|
||||
File.Copy(file, Path.Combine(folder, Path.GetFileName(file)), true);
|
||||
return Path.Combine(folder, Path.GetFileName(_files.CrashHandlerExe));
|
||||
File.Copy(file, Path.Combine(_tempExecutableDirectory, Path.GetFileName(file)), true);
|
||||
return Path.Combine(_tempExecutableDirectory, Path.GetFileName(_files.CrashHandlerExe));
|
||||
}
|
||||
|
||||
public void LogAnimation(nint character, ModCollection collection, AnimationInvocationType type)
|
||||
|
|
@ -213,18 +234,27 @@ public sealed class CrashHandlerService : IDisposable, IService
|
|||
if (_eventWriter == null)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
var name = GetActorName(character);
|
||||
lock (_eventWriter)
|
||||
{
|
||||
_eventWriter?.AnimationFuncInvoked.WriteLine(character, name.Span, collection.Name, type);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Penumbra.Log.Warning($"Error logging animation function {type} to crash handler:\n{ex}");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnCreatingCharacterBase(nint address, string collection, nint _1, nint _2, nint _3)
|
||||
{
|
||||
if (_eventWriter == null)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
var name = GetActorName(address);
|
||||
|
||||
lock (_eventWriter)
|
||||
|
|
@ -232,6 +262,11 @@ public sealed class CrashHandlerService : IDisposable, IService
|
|||
_eventWriter?.CharacterBase.WriteLine(address, name.Span, collection);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Penumbra.Log.Warning($"Error logging character creation to crash handler:\n{ex}");
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe ByteString GetActorName(nint address)
|
||||
{
|
||||
|
|
@ -249,6 +284,8 @@ public sealed class CrashHandlerService : IDisposable, IService
|
|||
if (manipulatedPath == null || _eventWriter == null)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
var dashIdx = manipulatedPath.Value.InternalName[0] == (byte)'|' ? manipulatedPath.Value.InternalName.IndexOf((byte)'|', 1) : -1;
|
||||
if (dashIdx >= 0 && !Utf8GamePath.IsRooted(manipulatedPath.Value.InternalName.Substring(dashIdx + 1)))
|
||||
return;
|
||||
|
|
@ -260,6 +297,11 @@ public sealed class CrashHandlerService : IDisposable, IService
|
|||
manipulatedPath.Value.InternalName.Span, originalPath.Path.Span);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Penumbra.Log.Warning($"Error logging resource to crash handler:\n{ex}");
|
||||
}
|
||||
}
|
||||
|
||||
private void CloseEventWriter()
|
||||
{
|
||||
|
|
@ -276,7 +318,7 @@ public sealed class CrashHandlerService : IDisposable, IService
|
|||
try
|
||||
{
|
||||
CloseEventWriter();
|
||||
_eventWriter = new GameEventLogWriter();
|
||||
_eventWriter = new GameEventLogWriter(Environment.ProcessId);
|
||||
Penumbra.Log.Debug("Opened new Event Writer for crash handler.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue