diff --git a/src/Ryujinx.Common/Logging/Logger.cs b/src/Ryujinx.Common/Logging/Logger.cs index e6f68599a..0d8bd3ac3 100644 --- a/src/Ryujinx.Common/Logging/Logger.cs +++ b/src/Ryujinx.Common/Logging/Logger.cs @@ -187,6 +187,17 @@ namespace Ryujinx.Common.Logging } } + public static void Flush() + { + foreach (ILogTarget target in _logTargets) + { + if (target is AsyncLogTargetWrapper asyncTarget) + { + asyncTarget.Flush(); + } + } + } + public static void Shutdown() { Updated = null; diff --git a/src/Ryujinx.Common/Logging/Targets/AsyncLogTargetWrapper.cs b/src/Ryujinx.Common/Logging/Targets/AsyncLogTargetWrapper.cs index 1fcfea4da..34f52d6ab 100644 --- a/src/Ryujinx.Common/Logging/Targets/AsyncLogTargetWrapper.cs +++ b/src/Ryujinx.Common/Logging/Targets/AsyncLogTargetWrapper.cs @@ -27,6 +27,17 @@ namespace Ryujinx.Common.Logging.Targets private readonly int _overflowTimeout; + private sealed class FlushEventArgs : LogEventArgs + { + public readonly ManualResetEventSlim SignalEvent; + + public FlushEventArgs(ManualResetEventSlim signalEvent) + : base(LogLevel.Notice, TimeSpan.Zero, string.Empty, string.Empty) + { + SignalEvent = signalEvent; + } + } + string ILogTarget.Name => _target.Name; public AsyncLogTargetWrapper(ILogTarget target, int queueLimit = -1, AsyncLogTargetOverflowAction overflowAction = AsyncLogTargetOverflowAction.Block) @@ -41,7 +52,15 @@ namespace Ryujinx.Common.Logging.Targets { try { - _target.Log(this, _messageQueue.Take()); + LogEventArgs item = _messageQueue.Take(); + + if (item is FlushEventArgs flush) + { + flush.SignalEvent.Set(); + continue; + } + + _target.Log(this, item); } catch (InvalidOperationException) { @@ -68,6 +87,26 @@ namespace Ryujinx.Common.Logging.Targets } } + public void Flush() + { + if (_messageQueue.Count == 0 || _messageQueue.IsAddingCompleted) + { + return; + } + + using var signal = new ManualResetEventSlim(false); + try + { + _messageQueue.Add(new FlushEventArgs(signal)); + } + catch (InvalidOperationException) + { + return; + } + + signal.Wait(); + } + public void Dispose() { GC.SuppressFinalize(this); diff --git a/src/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs b/src/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs index 54311f229..bea1f0ef3 100644 --- a/src/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs +++ b/src/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs @@ -1095,6 +1095,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process Logger.Error?.Print(LogClass.Cpu, $"Invalid memory access at virtual address 0x{va:X16}."); + Logger.Flush(); + return false; } @@ -1103,6 +1105,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process KernelStatic.GetCurrentThread().PrintGuestStackTrace(); KernelStatic.GetCurrentThread()?.PrintGuestRegisterPrintout(); + Logger.Flush(); + throw new UndefinedInstructionException(address, opCode); } diff --git a/src/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs b/src/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs index c67220617..005ac1452 100644 --- a/src/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs +++ b/src/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs @@ -1893,6 +1893,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return; } + Logger.Error?.Print(LogClass.KernelSvc, "The guest program broke execution!"); + Logger.Flush(); + // TODO: Debug events. currentThread.Owner.TerminateCurrentProcess(); diff --git a/src/Ryujinx/Program.cs b/src/Ryujinx/Program.cs index db9ae21eb..ecf6779dc 100644 --- a/src/Ryujinx/Program.cs +++ b/src/Ryujinx/Program.cs @@ -351,7 +351,10 @@ namespace Ryujinx.Ava if (isTerminating) + { + Logger.Flush(); Exit(); + } } internal static void Exit()