mirror of
https://github.com/FEX-Emu/FEX.git
synced 2025-01-10 15:50:18 +00:00
Cleanup threads when they exit
This commit is contained in:
parent
82c2b49a2e
commit
41a1a9d400
@ -119,20 +119,12 @@ namespace FEXCore::Context {
|
||||
CTX->StopThread(Thread);
|
||||
}
|
||||
|
||||
void DestroyThread(FEXCore::Context::Context *CTX, FEXCore::Core::InternalThreadState *Thread) {
|
||||
CTX->DestroyThread(Thread);
|
||||
}
|
||||
|
||||
void DeleteForkedThreads(FEXCore::Context::Context *CTX, FEXCore::Core::InternalThreadState *Thread) {
|
||||
// This function is called after fork
|
||||
// We need to cleanup some of the thread data that is dead
|
||||
for (auto &DeadThread : CTX->Threads) {
|
||||
if (DeadThread == Thread) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Setting running to false ensures that when they are shutdown we won't send signals to kill them
|
||||
DeadThread->RunningEvents.Running = false;
|
||||
}
|
||||
|
||||
// We now only have one thread
|
||||
CTX->IdleWaitRefCount = 1;
|
||||
CTX->DeleteForkedThreads(Thread);
|
||||
}
|
||||
|
||||
void SetSignalDelegator(FEXCore::Context::Context *CTX, FEXCore::SignalDelegator *SignalDelegation) {
|
||||
|
@ -197,6 +197,9 @@ namespace FEXCore::Context {
|
||||
void CopyMemoryMapping(FEXCore::Core::InternalThreadState *ParentThread, FEXCore::Core::InternalThreadState *ChildThread);
|
||||
void RunThread(FEXCore::Core::InternalThreadState *Thread);
|
||||
|
||||
void DestroyThread(FEXCore::Core::InternalThreadState *Thread);
|
||||
void DeleteForkedThreads(FEXCore::Core::InternalThreadState *ExceptForThread);
|
||||
|
||||
std::vector<FEXCore::Core::InternalThreadState*> *const GetThreads() { return &Threads; }
|
||||
|
||||
void AddNamedRegion(uintptr_t Base, uintptr_t Size, uintptr_t Offset, const std::string &filename);
|
||||
|
47
External/FEXCore/Source/Interface/Core/Core.cpp
vendored
47
External/FEXCore/Source/Interface/Core/Core.cpp
vendored
@ -25,6 +25,7 @@
|
||||
#include <fstream>
|
||||
#include <unistd.h>
|
||||
#include <filesystem>
|
||||
#include <algorithm>
|
||||
|
||||
#include "Interface/Core/GdbServer.h"
|
||||
|
||||
@ -621,6 +622,47 @@ namespace FEXCore::Context {
|
||||
return Thread;
|
||||
}
|
||||
|
||||
void Context::DestroyThread(FEXCore::Core::InternalThreadState *Thread) {
|
||||
// remove new thread object
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(ThreadCreationMutex);
|
||||
|
||||
auto It = std::find(Threads.begin(), Threads.end(), Thread);
|
||||
LogMan::Throw::A(It != Threads.end(), "Thread wasn't in Threads");
|
||||
|
||||
Threads.erase(It);
|
||||
}
|
||||
|
||||
if (std::this_thread::get_id() == Thread->ExecutionThread.get_id()) {
|
||||
// To be able to delete a thread from itself, we need to detached the std::thread object
|
||||
Thread->ExecutionThread.detach();
|
||||
}
|
||||
delete Thread;
|
||||
}
|
||||
|
||||
void Context::DeleteForkedThreads(FEXCore::Core::InternalThreadState *ExceptForThread) {
|
||||
// This function is called after fork
|
||||
// We need to cleanup some of the thread data that is dead
|
||||
for (auto &DeadThread : Threads) {
|
||||
if (DeadThread == ExceptForThread) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Setting running to false ensures that when they are shutdown we won't send signals to kill them
|
||||
DeadThread->RunningEvents.Running = false;
|
||||
|
||||
// Clean up thread state
|
||||
delete DeadThread;
|
||||
}
|
||||
|
||||
// Remove all threads but the current thread from Threads
|
||||
Threads.clear();
|
||||
Threads.push_back(ExceptForThread);
|
||||
|
||||
// We now only have one thread
|
||||
IdleWaitRefCount = 1;
|
||||
}
|
||||
|
||||
void Context::AddBlockMapping(FEXCore::Core::InternalThreadState *Thread, uint64_t Address, void *Ptr, uint64_t Start, uint64_t Length) {
|
||||
Thread->LookupCache->AddBlockMapping(Address, Ptr, Start, Length);
|
||||
}
|
||||
@ -1181,6 +1223,11 @@ namespace FEXCore::Context {
|
||||
IdleWaitCV.notify_all();
|
||||
|
||||
SignalDelegation->UninstallTLSState(Thread);
|
||||
|
||||
// If the parent thread is waiting to join, then we can't destroy our thread object
|
||||
if (!Thread->DestroyedByParent && Thread != Thread->CTX->ParentThread) {
|
||||
Thread->CTX->DestroyThread(Thread);
|
||||
}
|
||||
}
|
||||
|
||||
void FlushCodeRange(FEXCore::Core::InternalThreadState *Thread, uint64_t Start, uint64_t Length) {
|
||||
|
@ -218,6 +218,7 @@ namespace FEXCore::Context {
|
||||
void InitializeThread(FEXCore::Context::Context *CTX, FEXCore::Core::InternalThreadState *Thread);
|
||||
void RunThread(FEXCore::Context::Context *CTX, FEXCore::Core::InternalThreadState *Thread);
|
||||
void StopThread(FEXCore::Context::Context *CTX, FEXCore::Core::InternalThreadState *Thread);
|
||||
void DestroyThread(FEXCore::Context::Context *CTX, FEXCore::Core::InternalThreadState *Thread);
|
||||
void DeleteForkedThreads(FEXCore::Context::Context *CTX, FEXCore::Core::InternalThreadState *Thread);
|
||||
void SetSignalDelegator(FEXCore::Context::Context *CTX, FEXCore::SignalDelegator *SignalDelegation);
|
||||
void SetSyscallHandler(FEXCore::Context::Context *CTX, FEXCore::HLE::SyscallHandler *Handler);
|
||||
|
@ -102,8 +102,9 @@ namespace FEXCore::Core {
|
||||
uint32_t CompileBlockReentrantRefCount{};
|
||||
std::shared_ptr<FEXCore::CompileService> CompileService;
|
||||
bool IsCompileService{false};
|
||||
bool DestroyedByParent{false}; // Should the parent destroy this thread, or it destory itself
|
||||
|
||||
FEXCore::Core::CpuStateFrame BaseFrameState{};
|
||||
alignas(16) FEXCore::Core::CpuStateFrame BaseFrameState{};
|
||||
|
||||
};
|
||||
static_assert(std::is_standard_layout<InternalThreadState>::value, "This needs to be standard layout");
|
||||
|
@ -111,12 +111,19 @@ namespace FEX::HLE::x32 {
|
||||
// Return the new threads TID
|
||||
uint64_t Result = NewThread->ThreadManager.GetTID();
|
||||
|
||||
if (flags & CLONE_VFORK) {
|
||||
NewThread->DestroyedByParent = true;
|
||||
}
|
||||
|
||||
// Actually start the thread
|
||||
FEXCore::Context::RunThread(Thread->CTX, NewThread);
|
||||
|
||||
if (flags & CLONE_VFORK) {
|
||||
// If VFORK is set then the calling process is suspended until the thread exits with execve or exit
|
||||
NewThread->ExecutionThread.join();
|
||||
|
||||
// Normally a thread cleans itself up on exit. But because we need to join, we are now responsible
|
||||
FEXCore::Context::DestroyThread(Thread->CTX, NewThread);
|
||||
}
|
||||
SYSCALL_ERRNO();
|
||||
}
|
||||
|
@ -111,12 +111,19 @@ namespace FEX::HLE::x64 {
|
||||
uint64_t Result = NewThread->ThreadManager.GetTID();
|
||||
LogMan::Msg::D("Child [%d] starting at: 0x%lx. Parent was at 0x%lx", Result, NewThread->CurrentFrame->State.rip, Thread->CurrentFrame->State.rip);
|
||||
|
||||
if (flags & CLONE_VFORK) {
|
||||
NewThread->DestroyedByParent = true;
|
||||
}
|
||||
|
||||
// Actually start the thread
|
||||
FEXCore::Context::RunThread(Thread->CTX, NewThread);
|
||||
|
||||
if (flags & CLONE_VFORK) {
|
||||
// If VFORK is set then the calling process is suspended until the thread exits with execve or exit
|
||||
NewThread->ExecutionThread.join();
|
||||
|
||||
// Normally a thread cleans itself up on exit. But because we need to join, we are now responsible
|
||||
FEXCore::Context::DestroyThread(Thread->CTX, NewThread);
|
||||
}
|
||||
SYSCALL_ERRNO();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user