diff --git a/core/libs/prx/libkernel/System/src/SignalSets.cpp b/core/libs/prx/libkernel/System/src/SignalSets.cpp index 871866cb3..3f2cf5b43 100644 --- a/core/libs/prx/libkernel/System/src/SignalSets.cpp +++ b/core/libs/prx/libkernel/System/src/SignalSets.cpp @@ -109,6 +109,16 @@ asm(".text\n" " popq %rsi\n" " popq %rdi\n" "2:\n" +#ifdef _WIN32 + " pushq %rdi\n" + " pushq %rsi\n" + " movq 16(%rdi), %rdi\n" + " subq $8, %rsp\n" + " call GuestStackSwitch_nid_no_patch\n" + " addq $8, %rsp\n" + " popq %rsi\n" + " popq %rdi\n" +#endif " movq %rdi, %rdx\n" " movl %esi, %eax\n" " movq 0(%rdx), %rcx\n" diff --git a/core/libs/tests/GuestUserContext.cpp b/core/libs/tests/GuestUserContext.cpp index 41a4b5e0b..cd05dca09 100644 --- a/core/libs/tests/GuestUserContext.cpp +++ b/core/libs/tests/GuestUserContext.cpp @@ -21,6 +21,8 @@ int APS5_VABI setcontext_nid_postfix(const UserUcontext* context); void APS5_VABI makecontext_nid_postfix(UserUcontext* context, ContextEntry entry, int count, ...); [[gnu::returns_twice]] int APS5_VABI setjmp_nid_postfix(std::uint64_t* buffer); [[noreturn]] void APS5_VABI longjmp_nid_postfix(std::uint64_t* buffer, int value); +[[gnu::returns_twice]] int APS5_VABI sigsetjmp_nid_postfix(std::uint64_t* buffer, int saveMask); +[[noreturn]] void APS5_VABI siglongjmp_nid_postfix(std::uint64_t* buffer, int value); int APS5_VABI sigprocmask_nid_postfix(int how, const void* set, void* previousSet); int* APS5_VABI __error_nid_postfix(); @@ -150,6 +152,7 @@ int g_entries = 0; Fibre g_dispatcher = {}; Fibre g_job = {}; int g_jobRuns = 0; +bool g_signalJumps = false; void Require(bool value, const char* what) { if (!value) { @@ -348,6 +351,14 @@ namespace { [[gnu::noinline]] void Switch(Fibre* from, Fibre* to) { from->started = 1; + if (g_signalJumps) { + if (sigsetjmp_nid_postfix(from->jump, 1) == 0) { + if (to->started) siglongjmp_nid_postfix(to->jump, 1); + setcontext_nid_postfix(&to->context); + Require(false, "setcontext into the job returned"); + } + return; + } if (setjmp_nid_postfix(from->jump) == 0) { if (to->started) longjmp_nid_postfix(to->jump, 1); setcontext_nid_postfix(&to->context); @@ -360,7 +371,7 @@ namespace { extern "C" void APS5_VABI JobEntry() { for (;;) { ++g_jobRuns; - CheckStackBounds(&g_jobStack, "the stack bounds follow longjmp onto the job stack"); + CheckStackBounds(&g_jobStack, g_signalJumps ? "the stack bounds follow siglongjmp onto the job stack" : "the stack bounds follow longjmp onto the job stack"); ThrowAndCatch(); Switch(&g_job, &g_dispatcher); } @@ -402,7 +413,11 @@ void CheckMakecontext() { #endif } -void CheckJumpBuffers() { +void CheckJumpBuffers(bool signalJumps) { + g_signalJumps = signalJumps; + g_jobRuns = 0; + g_dispatcher = {}; + g_job = {}; #ifdef _WIN32 ULONG_PTR threadLow = 0; ULONG_PTR threadHigh = 0; @@ -420,7 +435,7 @@ void CheckJumpBuffers() { ULONG_PTR low = 0; ULONG_PTR high = 0; GetCurrentThreadStackLimits(&low, &high); - Require(low == threadLow && high == threadHigh, "the stack bounds follow longjmp back to the thread stack"); + Require(low == threadLow && high == threadHigh, signalJumps ? "the stack bounds follow siglongjmp back to the thread stack" : "the stack bounds follow longjmp back to the thread stack"); #endif } } @@ -466,7 +481,8 @@ int main(int argc, char** argv) { CheckSignalMask(); std::thread([] { CheckMakecontext(); - CheckJumpBuffers(); + CheckJumpBuffers(false); + CheckJumpBuffers(true); GrowStack(32); }).join(); return 0;