Skip to content

Commit

Permalink
Linux: Move ThreadManager to its own header
Browse files Browse the repository at this point in the history
  • Loading branch information
Sonicadvance1 committed May 5, 2024
1 parent 170204d commit 729e32c
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 84 deletions.
85 changes: 1 addition & 84 deletions Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ desc: Glue logic, STRACE magic

#include "LinuxSyscalls/FileManagement.h"
#include "LinuxSyscalls/LinuxAllocator.h"
#include "LinuxSyscalls/ThreadManager.h"

#include <FEXCore/Config/Config.h>
#include <FEXCore/HLE/SyscallHandler.h>
Expand Down Expand Up @@ -92,90 +93,6 @@ struct ExecveAtArgs {

uint64_t ExecveHandler(const char* pathname, char* const* argv, char* const* envp, ExecveAtArgs Args);

class ThreadManager final {
public:
ThreadManager(FEXCore::Context::Context* CTX, FEX::HLE::SignalDelegator* SignalDelegation)
: CTX {CTX}
, SignalDelegation {SignalDelegation} {}

~ThreadManager();

FEXCore::Core::InternalThreadState*
CreateThread(uint64_t InitialRIP, uint64_t StackPointer, FEXCore::Core::CPUState* NewThreadState = nullptr, uint64_t ParentTID = 0);
void TrackThread(FEXCore::Core::InternalThreadState* Thread) {
std::lock_guard lk(ThreadCreationMutex);
Threads.emplace_back(Thread);
}

void DestroyThread(FEXCore::Core::InternalThreadState* Thread);
void StopThread(FEXCore::Core::InternalThreadState* Thread);
void RunThread(FEXCore::Core::InternalThreadState* 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, 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, Start, Length, callback);
}
}

const fextl::vector<FEXCore::Core::InternalThreadState*>* GetThreads() const {
return &Threads;
}

private:
FEXCore::Context::Context* CTX;
FEX::HLE::SignalDelegator* SignalDelegation;

FEXCore::ForkableUniqueMutex ThreadCreationMutex;
fextl::vector<FEXCore::Core::InternalThreadState*> Threads;

// Thread idling support.
bool Running {};
std::mutex IdleWaitMutex;
std::condition_variable IdleWaitCV;
std::atomic<uint32_t> IdleWaitRefCount {};

void HandleThreadDeletion(FEXCore::Core::InternalThreadState* Thread);
void NotifyPause();
};

class SyscallHandler : public FEXCore::HLE::SyscallHandler, FEXCore::HLE::SourcecodeResolver, public FEXCore::Allocator::FEXAllocOperators {
public:
ThreadManager TM;
Expand Down
106 changes: 106 additions & 0 deletions Source/Tools/LinuxEmulation/LinuxSyscalls/ThreadManager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// 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;


class ThreadManager final {
public:
ThreadManager(FEXCore::Context::Context* CTX, FEX::HLE::SignalDelegator* SignalDelegation)
: CTX {CTX}
, SignalDelegation {SignalDelegation} {}

~ThreadManager();

FEXCore::Core::InternalThreadState*
CreateThread(uint64_t InitialRIP, uint64_t StackPointer, FEXCore::Core::CPUState* NewThreadState = nullptr, uint64_t ParentTID = 0);
void TrackThread(FEXCore::Core::InternalThreadState* Thread) {
std::lock_guard lk(ThreadCreationMutex);
Threads.emplace_back(Thread);
}

void DestroyThread(FEXCore::Core::InternalThreadState* Thread);
void StopThread(FEXCore::Core::InternalThreadState* Thread);
void RunThread(FEXCore::Core::InternalThreadState* 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, 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, Start, Length, callback);
}
}

const fextl::vector<FEXCore::Core::InternalThreadState*>* GetThreads() const {
return &Threads;
}

private:
FEXCore::Context::Context* CTX;
FEX::HLE::SignalDelegator* SignalDelegation;

FEXCore::ForkableUniqueMutex ThreadCreationMutex;
fextl::vector<FEXCore::Core::InternalThreadState*> Threads;

// Thread idling support.
bool Running {};
std::mutex IdleWaitMutex;
std::condition_variable IdleWaitCV;
std::atomic<uint32_t> IdleWaitRefCount {};

void HandleThreadDeletion(FEXCore::Core::InternalThreadState* Thread);
void NotifyPause();
};

} // namespace FEX::HLE

0 comments on commit 729e32c

Please sign in to comment.