threads: remove low level threads on windows (#4277)

This commit is contained in:
Vladislav Mikhalin 2026-04-19 12:00:49 +03:00 committed by GitHub
parent 9141c19302
commit 9ec75c32ad
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 42 additions and 83 deletions

View File

@ -197,7 +197,11 @@ int PS4_SYSV_ABI posix_pthread_detach(PthreadT pthread) {
return 0;
}
static void RunThread(void* arg) {
#ifdef WIN32
static DWORD RunThread(void* arg) {
#else
static void* RunThread(void* arg) {
#endif
auto* curthread = static_cast<Pthread*>(arg);
g_curthread = curthread;
Common::SetCurrentThreadName(curthread->name.c_str());
@ -214,6 +218,11 @@ static void RunThread(void* arg) {
/* Remove thread from tracking */
DebugState.RemoveCurrentThreadFromGuestList();
posix_pthread_exit(ret);
#ifdef WIN32
return 0;
#else
return nullptr;
#endif
}
int PS4_SYSV_ABI posix_pthread_create_name_np(PthreadT* thread, const PthreadAttrT* attr,

View File

@ -5,6 +5,19 @@
_runOnAnotherStack:
pushq %r12
pushq %r13
#ifdef WIN32
pushq %r14
pushq %r15
# save stack check registers
movq %gs:0x08, %r14 # teb->stack_bottom
movq %gs:0x10, %r15 # teb->stack_top
# disable stack checks
xorq %rcx, %rcx
movq %rcx, %gs:0x08 # teb->stack_bottom = 0
movq %rcx, %gs:0x10 # teb->stack_top = 0
#endif
movq %rsp, %r12
movq %rbp, %r13
movq %rdx, %rsp
@ -12,6 +25,13 @@ _runOnAnotherStack:
callq *%rsi
movq %r13, %rbp
movq %r12, %rsp
#ifdef WIN32
# restore stack check registers
movq %r14, %gs:0x08 # teb->stack_bottom
movq %r15, %gs:0x10 # teb->stack_top
popq %r15
popq %r14
#endif
popq %r13
popq %r12
ret

View File

@ -19,67 +19,20 @@ namespace Core {
static constexpr u32 ORBIS_MXCSR = 0x9fc0;
static constexpr u32 ORBIS_FPUCW = 0x037f;
#ifdef _WIN64
#define KGDT64_R3_DATA (0x28)
#define KGDT64_R3_CODE (0x30)
#define KGDT64_R3_CMTEB (0x50)
#define RPL_MASK (0x03)
#define EFLAGS_INTERRUPT_MASK (0x200)
void InitializeTeb(INITIAL_TEB* teb, void* stackaddr, size_t stacksize) {
teb->StackBase = (void*)((u64)stackaddr + stacksize);
teb->StackLimit = nullptr;
teb->StackAllocationBase = stackaddr;
}
void InitializeContext(CONTEXT* ctx, ThreadFunc func, void* arg, void* stackaddr,
size_t stacksize) {
/* Note: The stack has to be reversed */
ctx->Rsp = (u64)stackaddr + stacksize;
ctx->Rbp = (u64)stackaddr + stacksize;
ctx->Rcx = (u64)arg;
ctx->Rip = (u64)func;
ctx->SegGs = KGDT64_R3_DATA | RPL_MASK;
ctx->SegEs = KGDT64_R3_DATA | RPL_MASK;
ctx->SegDs = KGDT64_R3_DATA | RPL_MASK;
ctx->SegCs = KGDT64_R3_CODE | RPL_MASK;
ctx->SegSs = KGDT64_R3_DATA | RPL_MASK;
ctx->SegFs = KGDT64_R3_CMTEB | RPL_MASK;
ctx->EFlags = 0x3000 | EFLAGS_INTERRUPT_MASK;
ctx->ContextFlags =
CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT;
}
#endif
NativeThread::NativeThread() : native_handle{0} {}
NativeThread::~NativeThread() {}
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<pthread_t*>(&native_handle);
pthread_attr_t pattr;
pthread_attr_init(&pattr);
pthread_attr_setstack(&pattr, init_stack_ptr, stacksize);
return pthread_create(pthr, &pattr, (PthreadFunc)func, arg);
return pthread_create(pthr, nullptr, func, arg);
#else
CLIENT_ID clientId{};
INITIAL_TEB teb{};
CONTEXT ctx{};
clientId.UniqueProcess = GetCurrentProcess();
clientId.UniqueThread = GetCurrentThread();
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);
native_handle = CreateThread(nullptr, 0, func, arg, 0, nullptr);
if (native_handle == nullptr) {
return GetLastError();
}
return 0;
#endif
}
@ -91,28 +44,8 @@ void NativeThread::Exit() {
tid = 0;
#ifdef _WIN64
NtClose(native_handle);
native_handle = nullptr;
/* The Windows kernel will free the stack
given at thread creation via INITIAL_TEB
(StackAllocationBase) upon thread termination.
In earlier Windows versions (NT4 to Windows Server 2003),
you could get around this via disabling FreeStackOnTermination
on the TEB. This has been removed since then.
To avoid this, we must forcefully set the TEB
deallocation stack pointer to NULL so ZwFreeVirtualMemory fails
in the kernel and our stack is not freed.
*/
auto* teb = reinterpret_cast<TEB*>(NtCurrentTeb());
teb->DeallocationStack = nullptr;
if (init_stack_ptr != nullptr) {
free(init_stack_ptr);
}
NtTerminateThread(nullptr, 0);
ExitThread(0);
#else
// Disable and free the signal stack.
constexpr stack_t sig_stack = {
@ -124,10 +57,6 @@ void NativeThread::Exit() {
free(sig_stack_ptr);
sig_stack_ptr = nullptr;
}
if (init_stack_ptr != nullptr) {
free(init_stack_ptr);
}
pthread_exit(nullptr);
#endif
}

View File

@ -10,9 +10,11 @@ struct PthreadAttr;
} // namespace Libraries::Kernel
namespace Core {
using ThreadFunc = void (*)(void*);
using PthreadFunc = void* (*)(void*);
#ifdef WIN32
using ThreadFunc = DWORD (*)(void*);
#else
using ThreadFunc = void* (*)(void*);
#endif
class NativeThread {
public:
@ -39,7 +41,6 @@ private:
uintptr_t native_handle;
void* sig_stack_ptr = nullptr;
#endif
void* init_stack_ptr = nullptr;
u64 tid;
};