From 70d1d2f443b040eef6fcc685dbb3e8046fa586de Mon Sep 17 00:00:00 2001 From: kuba Date: Wed, 30 Sep 2026 15:09:01 +0200 Subject: [PATCH] [Cpu] Stop guest threads at their next import once the host shuts down Host shutdown only kept guest threads from starting another slice; a thread already inside guest code kept calling HLE while the services behind it were torn down. Superliminal's job threads then got a null command buffer from the GPU library, wrote through it, and the process died with SIGSEGV on its way out. After shutdown is requested an import now returns to the host entry stub instead of running, ending that thread's slice; the scheduler already refuses to enter guest code again. (cherry picked from commit 9e0e8ec0aa8b0bfaa030e5e97d51dbc0223f93e1) --- .../Native/DirectExecutionBackend.Imports.cs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/SharpEmu.Core/Cpu/Native/DirectExecutionBackend.Imports.cs b/src/SharpEmu.Core/Cpu/Native/DirectExecutionBackend.Imports.cs index 2c149d0..57aaa10 100644 --- a/src/SharpEmu.Core/Cpu/Native/DirectExecutionBackend.Imports.cs +++ b/src/SharpEmu.Core/Cpu/Native/DirectExecutionBackend.Imports.cs @@ -340,6 +340,14 @@ public sealed partial class DirectExecutionBackend Console.Error.WriteLine( $"[LOADER][TRACE] bootstrap_call#{num}: op=0x{value:X16} sym_ptr=0x{value2:X16} sym='{symbolText}' out_ptr=0x{num3:X16} ret=0x{num7:X16}"); } + // Once the host is shutting down, a guest thread still running reaches no more HLE: the + // services behind the imports are being torn down, and a title that sees them fail (a null + // command buffer from the GPU library, say) crashes the process on its way out. + if (_forcedGuestExit && !ActiveForcedGuestExit && TryEndGuestSliceForShutdown(argPackPtr)) + { + cpuContext[CpuRegister.Rax] = 1uL; + return 1uL; + } if (!isGuestWorker && !ActiveForcedGuestExit && ShouldForceGuestExitOnImportLoop(in importStubEntry, num7, num, value, value2)) @@ -1794,6 +1802,20 @@ public sealed partial class DirectExecutionBackend } } + // Returns the import straight to the host entry stub, which ends this guest slice. + private unsafe bool TryEndGuestSliceForShutdown(nint argPackPtr) + { + ulong sentinel = ActiveEntryReturnSentinelRip; + if (sentinel < 65536 || !TryPatchActiveGuestReturnSlot(sentinel)) + { + return false; + } + + *(ulong*)(argPackPtr + 96) = sentinel; + ActiveForcedGuestExit = true; + return true; + } + private unsafe bool TryForceGuestExitToHostStub(nint argPackPtr, long dispatchIndex, ulong returnRip, string nid) { ulong num = ActiveEntryReturnSentinelRip;