mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-07 20:00:16 +02:00
A bit of refactoring necessary before we can move the remaining Linux specific code to the frontend. Most of this taken from #3535 but attempting to be NFC as much as possible.
110 lines
3.5 KiB
C++
110 lines
3.5 KiB
C++
// SPDX-License-Identifier: MIT
|
|
/*
|
|
$info$
|
|
tags: LinuxSyscalls|ThreadManager
|
|
desc: Frontend thread management
|
|
$end_info$
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <FEXCore/Core/Context.h>
|
|
#include <FEXCore/fextl/vector.h>
|
|
#include <FEXCore/Utils/SignalScopeGuards.h>
|
|
|
|
#include <cstdint>
|
|
|
|
namespace FEX::HLE {
|
|
class SyscallHandler;
|
|
class SignalDelegator;
|
|
|
|
struct ThreadStateObject : public FEXCore::Allocator::FEXAllocOperators {
|
|
FEXCore::Core::InternalThreadState* Thread;
|
|
};
|
|
|
|
class ThreadManager final {
|
|
public:
|
|
ThreadManager(FEXCore::Context::Context* CTX, FEX::HLE::SignalDelegator* SignalDelegation)
|
|
: CTX {CTX}
|
|
, SignalDelegation {SignalDelegation} {}
|
|
|
|
~ThreadManager();
|
|
|
|
FEX::HLE::ThreadStateObject*
|
|
CreateThread(uint64_t InitialRIP, uint64_t StackPointer, FEXCore::Core::CPUState* NewThreadState = nullptr, uint64_t ParentTID = 0);
|
|
void TrackThread(FEX::HLE::ThreadStateObject* Thread) {
|
|
std::lock_guard lk(ThreadCreationMutex);
|
|
Threads.emplace_back(Thread);
|
|
}
|
|
|
|
void DestroyThread(FEX::HLE::ThreadStateObject* Thread, bool NeedsTLSUninstall = false);
|
|
void StopThread(FEX::HLE::ThreadStateObject* Thread);
|
|
void RunThread(FEX::HLE::ThreadStateObject* Thread);
|
|
|
|
void Pause();
|
|
void Run();
|
|
void Step();
|
|
void Stop(bool IgnoreCurrentThread = false);
|
|
|
|
void WaitForIdle();
|
|
void WaitForIdleWithTimeout();
|
|
void WaitForThreadsToRun();
|
|
|
|
void SleepThread(FEXCore::Context::Context* CTX, FEXCore::Core::CpuStateFrame* Frame);
|
|
|
|
void UnlockAfterFork(FEXCore::Core::InternalThreadState* Thread, bool Child);
|
|
|
|
void IncrementIdleRefCount() {
|
|
++IdleWaitRefCount;
|
|
}
|
|
|
|
void InvalidateGuestCodeRange(FEXCore::Core::InternalThreadState* CallingThread, uint64_t Start, uint64_t Length) {
|
|
std::lock_guard lk(ThreadCreationMutex);
|
|
|
|
// Potential deferred since Thread might not be valid.
|
|
// Thread object isn't valid very early in frontend's initialization.
|
|
// To be more optimal the frontend should provide this code with a valid Thread object earlier.
|
|
auto CodeInvalidationlk = GuardSignalDeferringSectionWithFallback(CTX->GetCodeInvalidationMutex(), CallingThread);
|
|
|
|
for (auto& Thread : Threads) {
|
|
CTX->InvalidateGuestCodeRange(Thread->Thread, Start, Length);
|
|
}
|
|
}
|
|
|
|
void InvalidateGuestCodeRange(FEXCore::Core::InternalThreadState* CallingThread, uint64_t Start, uint64_t Length,
|
|
FEXCore::Context::CodeRangeInvalidationFn callback) {
|
|
std::lock_guard lk(ThreadCreationMutex);
|
|
|
|
// Potential deferred since Thread might not be valid.
|
|
// Thread object isn't valid very early in frontend's initialization.
|
|
// To be more optimal the frontend should provide this code with a valid Thread object earlier.
|
|
auto CodeInvalidationlk = GuardSignalDeferringSectionWithFallback(CTX->GetCodeInvalidationMutex(), CallingThread);
|
|
|
|
for (auto& Thread : Threads) {
|
|
CTX->InvalidateGuestCodeRange(Thread->Thread, Start, Length, callback);
|
|
}
|
|
}
|
|
|
|
const fextl::vector<FEX::HLE::ThreadStateObject*>* GetThreads() const {
|
|
return &Threads;
|
|
}
|
|
|
|
private:
|
|
FEXCore::Context::Context* CTX;
|
|
FEX::HLE::SignalDelegator* SignalDelegation;
|
|
|
|
FEXCore::ForkableUniqueMutex ThreadCreationMutex;
|
|
fextl::vector<FEX::HLE::ThreadStateObject*> Threads;
|
|
|
|
// Thread idling support.
|
|
bool Running {};
|
|
std::mutex IdleWaitMutex;
|
|
std::condition_variable IdleWaitCV;
|
|
std::atomic<uint32_t> IdleWaitRefCount {};
|
|
|
|
void HandleThreadDeletion(FEX::HLE::ThreadStateObject* Thread, bool NeedsTLSUninstall = false);
|
|
void NotifyPause();
|
|
};
|
|
|
|
} // namespace FEX::HLE
|