diff --git a/FEXCore/Source/Interface/Core/Core.cpp b/FEXCore/Source/Interface/Core/Core.cpp index 0dc9ed9de7..c6e06b5c38 100644 --- a/FEXCore/Source/Interface/Core/Core.cpp +++ b/FEXCore/Source/Interface/Core/Core.cpp @@ -873,11 +873,6 @@ uintptr_t ContextImpl::CompileBlock(FEXCore::Core::CpuStateFrame* Frame, uint64_ void ContextImpl::ExecutionThread(FEXCore::Core::InternalThreadState* Thread) { Thread->ExitReason = FEXCore::Context::ExitReason::EXIT_WAITING; - if (Thread->StartPaused) { - // Parent thread doesn't need to wait to run - Thread->StartRunning.Wait(); - } - Thread->RunningEvents.WaitingToStart = false; Thread->ExitReason = FEXCore::Context::ExitReason::EXIT_NONE; diff --git a/FEXCore/include/FEXCore/Debug/InternalThreadState.h b/FEXCore/include/FEXCore/Debug/InternalThreadState.h index 5ce663de39..a9236cccdb 100644 --- a/FEXCore/include/FEXCore/Debug/InternalThreadState.h +++ b/FEXCore/include/FEXCore/Debug/InternalThreadState.h @@ -89,8 +89,6 @@ struct InternalThreadState : public FEXCore::Allocator::FEXAllocOperators { FEXCore::Context::Context* const CTX; NonMovableUniquePtr ExecutionThread; - bool StartPaused {false}; - InterruptableConditionVariable StartRunning; NonMovableUniquePtr OpDispatcher; diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls.cpp index bcb92096a7..281ca869b0 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls.cpp @@ -659,9 +659,6 @@ uint64_t CloneHandler(FEXCore::Core::CpuStateFrame* Frame, FEX::HLE::clone3_args // Return the new threads TID uint64_t Result = NewThread->ThreadInfo.TID; - // Actually start the thread - FEX::HLE::_SyscallHandler->TM.RunThread(NewThread); - if (flags & CLONE_VFORK) { // If VFORK is set then the calling process is suspended until the thread exits with execve or exit NewThread->Thread->ExecutionThread->join(nullptr); diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Thread.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Thread.cpp index 0a9e8c234e..a4d466730c 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Thread.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Thread.cpp @@ -48,6 +48,10 @@ struct ExecutionThreadHandler { FEXCore::Context::Context* CTX; FEX::HLE::ThreadStateObject* Thread; Event* ThreadWaiting; + + // Pause on thread start handling. + FEXCore::InterruptableConditionVariable* StartRunningCV {}; + FEXCore::InterruptableConditionVariable* StartRunningResponse {}; }; static void* ThreadHandler(void* Data) { @@ -55,6 +59,9 @@ static void* ThreadHandler(void* Data) { auto CTX = Handler->CTX; auto Thread = Handler->Thread; auto ThreadWaiting = Handler->ThreadWaiting; + auto StartRunningCV = Handler->StartRunningCV; + auto StartRunningResponse = Handler->StartRunningResponse; + FEXCore::Allocator::free(Handler); Thread->ThreadInfo.PID = ::getpid(); @@ -65,6 +72,9 @@ static void* ThreadHandler(void* Data) { // Now notify the thread that we are initialized ThreadWaiting->NotifyOne(); + StartRunningCV->Wait(); + StartRunningResponse->NotifyOne(); + CTX->ExecutionThread(Thread->Thread); FEX::HLE::_SyscallHandler->UninstallTLSState(Thread); FEX::HLE::_SyscallHandler->TM.DestroyThread(Thread); @@ -98,15 +108,18 @@ FEX::HLE::ThreadStateObject* CreateNewThread(FEXCore::Context::Context* CTX, FEX x32::AdjustRipForNewThread(NewThread->Thread->CurrentFrame); } - // We need to do some post-thread creation setup. - NewThread->Thread->StartPaused = true; - // Initialize a new thread for execution. Event ThreadWaitingEvent {}; + FEXCore::InterruptableConditionVariable StartRunningCV {}; + FEXCore::InterruptableConditionVariable StartRunningResponse {}; + ExecutionThreadHandler* Arg = reinterpret_cast(FEXCore::Allocator::malloc(sizeof(ExecutionThreadHandler))); Arg->CTX = CTX; Arg->Thread = NewThread; Arg->ThreadWaiting = &ThreadWaitingEvent; + Arg->StartRunningCV = &StartRunningCV; + Arg->StartRunningResponse = &StartRunningResponse; + NewThread->Thread->ExecutionThread = FEXCore::Threads::Thread::Create(ThreadHandler, Arg); // Wait for the thread to have started. @@ -155,6 +168,12 @@ FEX::HLE::ThreadStateObject* CreateNewThread(FEXCore::Context::Context* CTX, FEX FEX::HLE::_SyscallHandler->TM.TrackThread(NewThread); + // Start running the thread + StartRunningCV.NotifyOne(); + + // Wait for the thread to start running. + StartRunningResponse.Wait(); + return NewThread; } @@ -179,7 +198,6 @@ uint64_t HandleNewClone(FEX::HLE::ThreadStateObject* Thread, FEXCore::Context::C // CLONE_PARENT_SETTID, CLONE_CHILD_SETTID, CLONE_CHILD_CLEARTID, CLONE_PIDFD will be handled by kernel // Call execution thread directly since we already are on the new thread - NewThread->Thread->StartRunning.NotifyAll(); // Clear the start running flag CreatedNewThreadObject = true; } else { // If we don't have CLONE_THREAD then we are effectively a fork diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/ThreadManager.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/ThreadManager.cpp index 025e2e28f0..c92d7138d7 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/ThreadManager.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/ThreadManager.cpp @@ -46,11 +46,6 @@ void ThreadManager::StopThread(FEX::HLE::ThreadStateObject* Thread) { } } -void ThreadManager::RunThread(FEX::HLE::ThreadStateObject* Thread) { - // Tell the thread to start executing - Thread->Thread->StartRunning.NotifyAll(); -} - void ThreadManager::HandleThreadDeletion(FEX::HLE::ThreadStateObject* Thread, bool NeedsTLSUninstall) { if (Thread->Thread->ExecutionThread) { if (Thread->Thread->ExecutionThread->joinable()) { @@ -93,10 +88,6 @@ void ThreadManager::Run() { for (auto& Thread : Threads) { Thread->SignalReason.store(SignalEvent::Return); } - - for (auto& Thread : Threads) { - Thread->Thread->StartRunning.NotifyAll(); - } } void ThreadManager::WaitForIdleWithTimeout() { @@ -166,12 +157,6 @@ void ThreadManager::Stop(bool IgnoreCurrentThread) { if (Thread->Thread->RunningEvents.Running.load()) { StopThread(Thread); } - - // If the thread is waiting to start but immediately killed then there can be a hang - // This occurs in the case of gdb attach with immediate kill - if (Thread->Thread->RunningEvents.WaitingToStart.load()) { - Thread->Thread->StartRunning.NotifyAll(); - } } } @@ -182,6 +167,7 @@ void ThreadManager::Stop(bool IgnoreCurrentThread) { } void ThreadManager::SleepThread(FEXCore::Context::Context* CTX, FEXCore::Core::CpuStateFrame* Frame) { + auto ThreadObject = FEX::HLE::ThreadManager::GetStateObjectFromCPUState(Frame); auto Thread = Frame->Thread; --IdleWaitRefCount; @@ -190,7 +176,7 @@ void ThreadManager::SleepThread(FEXCore::Context::Context* CTX, FEXCore::Core::C Thread->RunningEvents.ThreadSleeping = true; // Go to sleep - Thread->StartRunning.Wait(); + ThreadObject->ThreadPaused.Wait(); Thread->RunningEvents.Running = true; ++IdleWaitRefCount; @@ -199,6 +185,10 @@ void ThreadManager::SleepThread(FEXCore::Context::Context* CTX, FEXCore::Core::C IdleWaitCV.notify_all(); } +void ThreadManager::UnpauseThread(FEX::HLE::ThreadStateObject* Thread) { + Thread->ThreadPaused.NotifyOne(); +} + void ThreadManager::UnlockAfterFork(FEXCore::Core::InternalThreadState* LiveThread, bool Child) { if (!Child) { return; diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/ThreadManager.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/ThreadManager.h index a254cc8019..5fcbfa632a 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/ThreadManager.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/ThreadManager.h @@ -78,6 +78,9 @@ struct ThreadStateObject : public FEXCore::Allocator::FEXAllocOperators { // Thread signaling information std::atomic SignalReason {SignalEvent::Nothing}; + // Thread pause handling + FEXCore::InterruptableConditionVariable ThreadPaused; + int StatusCode {}; }; @@ -108,7 +111,7 @@ class ThreadManager final { void DestroyThread(FEX::HLE::ThreadStateObject* Thread, bool NeedsTLSUninstall = false); void StopThread(FEX::HLE::ThreadStateObject* Thread); - void RunThread(FEX::HLE::ThreadStateObject* Thread); + void UnpauseThread(FEX::HLE::ThreadStateObject* Thread); void Pause(); void Run();