From e1604fb32ffbc155da60774ea32314e277056611 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Sat, 20 Nov 2021 13:39:20 -0800 Subject: [PATCH] Arm64: Reduce the chance of hanging on reentrant allocations When compiling code and linking blocks, disable all signals then reenable once back in the dispatcher. This adds 15-40 microseconds on to each of these steps and some additional branching overhead. This is a problem where our allocator is not reentrant safe and when receiving a signal we need to jump to a new code region and compile. Depending on the mutexes that are currently live, we will just stall out forever. This is /very/ commonly picked up when attempting to run pressure-vessel --- .../Core/Dispatcher/Arm64Dispatcher.cpp | 82 ++++++++++++++++++- 1 file changed, 79 insertions(+), 3 deletions(-) diff --git a/External/FEXCore/Source/Interface/Core/Dispatcher/Arm64Dispatcher.cpp b/External/FEXCore/Source/Interface/Core/Dispatcher/Arm64Dispatcher.cpp index de01cf7ca..788bbaf3a 100644 --- a/External/FEXCore/Source/Interface/Core/Dispatcher/Arm64Dispatcher.cpp +++ b/External/FEXCore/Source/Interface/Core/Dispatcher/Arm64Dispatcher.cpp @@ -25,6 +25,7 @@ #include "code-buffer-vixl.h" #include "platform-vixl.h" +#include #include namespace FEXCore::CPU { @@ -205,11 +206,31 @@ Arm64Dispatcher::Arm64Dispatcher(FEXCore::Context::Context *ctx, FEXCore::Core:: ret(); } + constexpr bool SignalSafeCompile = true; { ExitFunctionLinkerAddress = GetCursorAddress(); if (SRAEnabled) SpillStaticRegs(); + if (SignalSafeCompile) { + // When compiling code, mask all signals to reduce the chance of reentrant allocations + // Args: + // X0: SETMASK + // X1: Pointer to mask value (uint64_t) + // X2: Pointer to old mask value (uint64_t) + // X3: Size of mask, sizeof(uint64_t) + // X8: Syscall + + LoadConstant(x0, ~0ULL); + stp(x0, x0, MemOperand(sp, -16, PreIndex)); + LoadConstant(x0, SIG_SETMASK); + add(x1, sp, 0); + add(x2, sp, 0); + LoadConstant(x3, 8); + LoadConstant(x8, SYS_rt_sigprocmask); + svc(0); + } + ldr(x0, &l_ExitFunctionLinkThis); mov(x1, STATE); mov(x2, lr); @@ -217,6 +238,24 @@ Arm64Dispatcher::Arm64Dispatcher(FEXCore::Context::Context *ctx, FEXCore::Core:: ldr(x3, &l_ExitFunctionLink); blr(x3); + if (SignalSafeCompile) { + // Now restore the signal mask + // Living in the same location + + mov(x4, x0); + LoadConstant(x0, SIG_SETMASK); + add(x1, sp, 0); + LoadConstant(x2, 0); + LoadConstant(x3, 8); + LoadConstant(x8, SYS_rt_sigprocmask); + svc(0); + + // Bring stack back + add(sp, sp, 16); + + mov(x0, x4); + } + if (SRAEnabled) FillStaticRegs(); br(x0); @@ -226,16 +265,53 @@ Arm64Dispatcher::Arm64Dispatcher(FEXCore::Context::Context *ctx, FEXCore::Core:: { bind(&NoBlock); + if (SRAEnabled) + SpillStaticRegs(); + + if (SignalSafeCompile) { + // When compiling code, mask all signals to reduce the chance of reentrant allocations + // Args: + // X0: SETMASK + // X1: Pointer to mask value (uint64_t) + // X2: Pointer to old mask value (uint64_t) + // X3: Size of mask, sizeof(uint64_t) + // X8: Syscall + + LoadConstant(x0, ~0ULL); + stp(x0, x2, MemOperand(sp, -16, PreIndex)); + LoadConstant(x0, SIG_SETMASK); + add(x1, sp, 0); + add(x2, sp, 0); + LoadConstant(x3, 8); + LoadConstant(x8, SYS_rt_sigprocmask); + svc(0); + + // Reload x2 to bring back RIP + ldr(x2, MemOperand(sp, 8, Offset)); + } + ldr(x0, &l_CTX); mov(x1, STATE); ldr(x3, &l_CompileBlock); - if (SRAEnabled) - SpillStaticRegs(); - // X2 contains our guest RIP blr(x3); // { CTX, Frame, RIP} + + if (SignalSafeCompile) { + // Now restore the signal mask + // Living in the same location + LoadConstant(x0, SIG_SETMASK); + add(x1, sp, 0); + LoadConstant(x2, 0); + LoadConstant(x3, 8); + LoadConstant(x8, SYS_rt_sigprocmask); + svc(0); + + // Bring stack back + add(sp, sp, 16); + } + if (SRAEnabled) FillStaticRegs();