From beba435a098443008562178e52b9e6fd870282ae Mon Sep 17 00:00:00 2001 From: Vladislav Mikhalin Date: Sat, 18 Apr 2026 16:17:48 +0300 Subject: [PATCH] separate thread init and run stacks (#4274) * separate thread init and run stacks * copyrights * remove TEB setting * revert fibers * fix linux * remove unused variables --- CMakeLists.txt | 3 ++ src/core/libraries/kernel/threads.cpp | 13 +------- src/core/libraries/kernel/threads.h | 4 +-- src/core/libraries/kernel/threads/pthread.cpp | 14 ++++---- src/core/libraries/kernel/threads/stack.cpp | 4 ++- src/core/libraries/kernel/threads/stack.s | 17 ++++++++++ src/core/linker.cpp | 1 - src/core/thread.cpp | 32 ++++++++++++------- src/core/thread.h | 7 ++-- 9 files changed, 56 insertions(+), 39 deletions(-) create mode 100644 src/core/libraries/kernel/threads/stack.s diff --git a/CMakeLists.txt b/CMakeLists.txt index 4d972e303..f4bed51c6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -327,6 +327,7 @@ set(KERNEL_LIB src/core/libraries/kernel/sync/mutex.cpp src/core/libraries/kernel/threads/sleepq.cpp src/core/libraries/kernel/threads/sleepq.h src/core/libraries/kernel/threads/stack.cpp + src/core/libraries/kernel/threads/stack.s src/core/libraries/kernel/threads/tcb.cpp src/core/libraries/kernel/threads/pthread.h src/core/libraries/kernel/threads/thread_state.cpp @@ -353,6 +354,8 @@ set(KERNEL_LIB src/core/libraries/kernel/sync/mutex.cpp src/core/libraries/kernel/aio.h ) +set_source_files_properties(src/core/libraries/kernel/threads/stack.s PROPERTIES COMPILE_OPTIONS -Wno-unused-command-line-argument) + set(NETWORK_LIBS src/core/libraries/network/http.cpp src/core/libraries/network/http.h src/core/libraries/network/http_error.h diff --git a/src/core/libraries/kernel/threads.cpp b/src/core/libraries/kernel/threads.cpp index 083dc8ee1..c006591e3 100644 --- a/src/core/libraries/kernel/threads.cpp +++ b/src/core/libraries/kernel/threads.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-FileCopyrightText: Copyright 2024-2026 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "core/libraries/kernel/kernel.h" @@ -7,17 +7,6 @@ namespace Libraries::Kernel { -void PS4_SYSV_ABI ClearStack() { - void* const stackaddr_attr = Libraries::Kernel::g_curthread->attr.stackaddr_attr; - void* volatile sp; - asm("mov %%rsp, %0" : "=rm"(sp)); - // leave a safety net of 64 bytes for memset - const size_t size = ((uintptr_t)sp - (uintptr_t)stackaddr_attr) - 64; - void* volatile buf = alloca(size); - memset(buf, 0, size); - sp = nullptr; -} - void RegisterThreads(Core::Loader::SymbolsResolver* sym) { RegisterMutex(sym); RegisterCond(sym); diff --git a/src/core/libraries/kernel/threads.h b/src/core/libraries/kernel/threads.h index 81535352c..46b36fa54 100644 --- a/src/core/libraries/kernel/threads.h +++ b/src/core/libraries/kernel/threads.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-FileCopyrightText: Copyright 2024-2026 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -41,8 +41,6 @@ int PS4_SYSV_ABI posix_pthread_mutex_destroy(PthreadMutexT* mutex); void RegisterThreads(Core::Loader::SymbolsResolver* sym); -void PS4_SYSV_ABI ClearStack(); - class Thread { public: explicit Thread() = default; diff --git a/src/core/libraries/kernel/threads/pthread.cpp b/src/core/libraries/kernel/threads/pthread.cpp index 3742db5cf..2858375b1 100644 --- a/src/core/libraries/kernel/threads/pthread.cpp +++ b/src/core/libraries/kernel/threads/pthread.cpp @@ -12,6 +12,9 @@ #include "core/libraries/libs.h" #include "core/memory.h" +extern "C" void* PS4_SYSV_ABI _runOnAnotherStack(void* arg, void* func, + void* stackb) asm("_runOnAnotherStack"); + namespace Libraries::Kernel { extern PthreadAttr PthreadAttrDefault; @@ -203,13 +206,10 @@ static void RunThread(void* arg) { curthread->native_thr.Initialize(); - // Clear the stack before running the guest thread - if (False(g_curthread->attr.flags & PthreadAttrFlags::StackUser)) { - ClearStack(); - } - /* Run the current thread's start routine with argument: */ - void* ret = curthread->start_routine(curthread->arg); + auto* const stack = + (void*)((size_t)curthread->attr.stackaddr_attr + curthread->attr.stacksize_attr); + void* ret = _runOnAnotherStack(curthread->arg, (void*)curthread->start_routine, stack); /* Remove thread from tracking */ DebugState.RemoveCurrentThreadFromGuestList(); @@ -290,7 +290,7 @@ int PS4_SYSV_ABI posix_pthread_create_name_np(PthreadT* thread, const PthreadAtt /* Create thread */ new_thread->native_thr = Core::NativeThread(); - int ret = new_thread->native_thr.Create(RunThread, new_thread, &new_thread->attr); + int ret = new_thread->native_thr.Create(RunThread, new_thread); ASSERT_MSG(ret == 0, "Failed to create thread with error {}", ret); diff --git a/src/core/libraries/kernel/threads/stack.cpp b/src/core/libraries/kernel/threads/stack.cpp index 0f3a4d59d..8c031e941 100644 --- a/src/core/libraries/kernel/threads/stack.cpp +++ b/src/core/libraries/kernel/threads/stack.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-FileCopyrightText: Copyright 2024-2026 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "common/assert.h" @@ -70,6 +70,7 @@ int ThreadState::CreateStack(PthreadAttr* attr) { /* A cached stack was found. Release the lock. */ if (attr->stackaddr_attr != nullptr) { + std::memset(attr->stackaddr_attr, 0, stacksize); thread_list_lock.unlock(); return 0; } @@ -112,6 +113,7 @@ int ThreadState::CreateStack(PthreadAttr* attr) { attr->stackaddr_attr = (void*)stackaddr; if (attr->stackaddr_attr != nullptr) { + std::memset(attr->stackaddr_attr, 0, stacksize); return 0; } return -1; diff --git a/src/core/libraries/kernel/threads/stack.s b/src/core/libraries/kernel/threads/stack.s new file mode 100644 index 000000000..0adc7ef8b --- /dev/null +++ b/src/core/libraries/kernel/threads/stack.s @@ -0,0 +1,17 @@ +# SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project +# SPDX-License-Identifier: GPL-2.0-or-later + +.global _runOnAnotherStack +_runOnAnotherStack: + pushq %r12 + pushq %r13 + movq %rsp, %r12 + movq %rbp, %r13 + movq %rdx, %rsp + movq %rdx, %rbp + callq *%rsi + movq %r13, %rbp + movq %r12, %rsp + popq %r13 + popq %r12 + ret diff --git a/src/core/linker.cpp b/src/core/linker.cpp index 15b939737..2db41375b 100644 --- a/src/core/linker.cpp +++ b/src/core/linker.cpp @@ -147,7 +147,6 @@ void Linker::Execute(const std::vector& args) { } } params.entry_addr = module->GetEntryAddress(); - Libraries::Kernel::ClearStack(); RunMainEntry(¶ms); }); } diff --git a/src/core/thread.cpp b/src/core/thread.cpp index 0015f40b9..717c7e5f9 100644 --- a/src/core/thread.cpp +++ b/src/core/thread.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-FileCopyrightText: Copyright 2024-2026 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "common/alignment.h" @@ -26,17 +26,17 @@ static constexpr u32 ORBIS_FPUCW = 0x037f; #define RPL_MASK (0x03) #define EFLAGS_INTERRUPT_MASK (0x200) -void InitializeTeb(INITIAL_TEB* teb, const ::Libraries::Kernel::PthreadAttr* attr) { - teb->StackBase = (void*)((u64)attr->stackaddr_attr + attr->stacksize_attr); +void InitializeTeb(INITIAL_TEB* teb, void* stackaddr, size_t stacksize) { + teb->StackBase = (void*)((u64)stackaddr + stacksize); teb->StackLimit = nullptr; - teb->StackAllocationBase = attr->stackaddr_attr; + teb->StackAllocationBase = stackaddr; } -void InitializeContext(CONTEXT* ctx, ThreadFunc func, void* arg, - const ::Libraries::Kernel::PthreadAttr* attr) { +void InitializeContext(CONTEXT* ctx, ThreadFunc func, void* arg, void* stackaddr, + size_t stacksize) { /* Note: The stack has to be reversed */ - ctx->Rsp = (u64)attr->stackaddr_attr + attr->stacksize_attr; - ctx->Rbp = (u64)attr->stackaddr_attr + attr->stacksize_attr; + ctx->Rsp = (u64)stackaddr + stacksize; + ctx->Rbp = (u64)stackaddr + stacksize; ctx->Rcx = (u64)arg; ctx->Rip = (u64)func; @@ -58,12 +58,14 @@ NativeThread::NativeThread() : native_handle{0} {} NativeThread::~NativeThread() {} -int NativeThread::Create(ThreadFunc func, void* arg, const ::Libraries::Kernel::PthreadAttr* attr) { +int NativeThread::Create(ThreadFunc func, void* arg) { + constexpr size_t stacksize = 8_KB; + init_stack_ptr = malloc(stacksize); #ifndef _WIN64 pthread_t* pthr = reinterpret_cast(&native_handle); pthread_attr_t pattr; pthread_attr_init(&pattr); - pthread_attr_setstack(&pattr, attr->stackaddr_attr, attr->stacksize_attr); + pthread_attr_setstack(&pattr, init_stack_ptr, stacksize); return pthread_create(pthr, &pattr, (PthreadFunc)func, arg); #else CLIENT_ID clientId{}; @@ -73,8 +75,8 @@ int NativeThread::Create(ThreadFunc func, void* arg, const ::Libraries::Kernel:: clientId.UniqueProcess = GetCurrentProcess(); clientId.UniqueThread = GetCurrentThread(); - InitializeTeb(&teb, attr); - InitializeContext(&ctx, func, arg, attr); + InitializeTeb(&teb, init_stack_ptr, stacksize); + InitializeContext(&ctx, func, arg, init_stack_ptr, stacksize); return NtCreateThread(&native_handle, THREAD_ALL_ACCESS, nullptr, GetCurrentProcess(), &clientId, &ctx, &teb, false); @@ -107,6 +109,9 @@ void NativeThread::Exit() { auto* teb = reinterpret_cast(NtCurrentTeb()); teb->DeallocationStack = nullptr; + if (init_stack_ptr != nullptr) { + free(init_stack_ptr); + } NtTerminateThread(nullptr, 0); #else // Disable and free the signal stack. @@ -120,6 +125,9 @@ void NativeThread::Exit() { sig_stack_ptr = nullptr; } + if (init_stack_ptr != nullptr) { + free(init_stack_ptr); + } pthread_exit(nullptr); #endif } diff --git a/src/core/thread.h b/src/core/thread.h index 6ea7dfad4..ec06b62eb 100644 --- a/src/core/thread.h +++ b/src/core/thread.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-FileCopyrightText: Copyright 2024-2026 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -19,7 +19,7 @@ public: NativeThread(); ~NativeThread(); - int Create(ThreadFunc func, void* arg, const ::Libraries::Kernel::PthreadAttr* attr); + int Create(ThreadFunc func, void* arg); void Exit(); void Initialize(); @@ -37,8 +37,9 @@ private: void* native_handle; #else uintptr_t native_handle; - void* sig_stack_ptr; + void* sig_stack_ptr = nullptr; #endif + void* init_stack_ptr = nullptr; u64 tid; };