From d387c46aab4cb4ce8730ac71c2332ba66a375c5c Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Fri, 7 Jul 2023 13:40:37 -0700 Subject: [PATCH 1/2] FEXCore: Fixes WIN32 compiling again Mostly a quick bandage while I'm setting getting ready to setup the runners to test this for us. --- .../Source/Interface/Context/Context.h | 2 + .../FEXCore/Source/Interface/Core/Core.cpp | 6 + .../FEXCore/include/FEXCore/Core/Context.h | 2 + .../FEXCore/Utils/DeferredSignalMutex.h | 124 +++++++++++++++--- External/FEXCore/include/FEXCore/fextl/fmt.h | 2 +- FEXHeaderUtils/FEXHeaderUtils/SymlinkChecks.h | 2 + Source/Common/CMakeLists.txt | 2 +- Source/Common/Config.cpp | 26 +++- 8 files changed, 140 insertions(+), 26 deletions(-) diff --git a/External/FEXCore/Source/Interface/Context/Context.h b/External/FEXCore/Source/Interface/Context/Context.h index 586a2e092..6958dadb8 100644 --- a/External/FEXCore/Source/Interface/Context/Context.h +++ b/External/FEXCore/Source/Interface/Context/Context.h @@ -153,8 +153,10 @@ namespace FEXCore::Context { */ void DestroyThread(FEXCore::Core::InternalThreadState *Thread) override; +#ifndef _WIN32 void LockBeforeFork(FEXCore::Core::InternalThreadState *Thread) override; void UnlockAfterFork(FEXCore::Core::InternalThreadState *Thread, bool Child) override; +#endif void SetSignalDelegator(FEXCore::SignalDelegator *SignalDelegation) override; void SetSyscallHandler(FEXCore::HLE::SyscallHandler *Handler) override; diff --git a/External/FEXCore/Source/Interface/Core/Core.cpp b/External/FEXCore/Source/Interface/Core/Core.cpp index 828d08ad4..8c63543d7 100644 --- a/External/FEXCore/Source/Interface/Core/Core.cpp +++ b/External/FEXCore/Source/Interface/Core/Core.cpp @@ -655,6 +655,7 @@ namespace FEXCore::Context { delete Thread; } +#ifndef _WIN32 void ContextImpl::UnlockAfterFork(FEXCore::Core::InternalThreadState *LiveThread, bool Child) { Allocator::UnlockAfterFork(LiveThread, Child); @@ -708,6 +709,7 @@ namespace FEXCore::Context { CodeInvalidationMutex.lock(); Allocator::LockBeforeFork(Thread); } +#endif void ContextImpl::AddBlockMapping(FEXCore::Core::InternalThreadState *Thread, uint64_t Address, void *Ptr) { Thread->LookupCache->AddBlockMapping(Address, Ptr); @@ -1155,7 +1157,9 @@ namespace FEXCore::Context { Thread->ExitReason = FEXCore::Context::ExitReason::EXIT_WAITING; InitializeThreadTLSData(Thread); +#ifndef _WIN32 Alloc::OSAllocator::RegisterTLSData(Thread); +#endif ++IdleWaitRefCount; @@ -1200,7 +1204,9 @@ namespace FEXCore::Context { --IdleWaitRefCount; IdleWaitCV.notify_all(); +#ifndef _WIN32 Alloc::OSAllocator::UninstallTLSData(Thread); +#endif SignalDelegation->UninstallTLSState(Thread); // If the parent thread is waiting to join, then we can't destroy our thread object diff --git a/External/FEXCore/include/FEXCore/Core/Context.h b/External/FEXCore/include/FEXCore/Core/Context.h index af2b2a15e..47366638b 100644 --- a/External/FEXCore/include/FEXCore/Core/Context.h +++ b/External/FEXCore/include/FEXCore/Core/Context.h @@ -243,8 +243,10 @@ namespace FEXCore::Context { FEX_DEFAULT_VISIBILITY virtual void RunThread(FEXCore::Core::InternalThreadState *Thread) = 0; FEX_DEFAULT_VISIBILITY virtual void StopThread(FEXCore::Core::InternalThreadState *Thread) = 0; FEX_DEFAULT_VISIBILITY virtual void DestroyThread(FEXCore::Core::InternalThreadState *Thread) = 0; +#ifndef _WIN32 FEX_DEFAULT_VISIBILITY virtual void LockBeforeFork(FEXCore::Core::InternalThreadState *Thread) {} FEX_DEFAULT_VISIBILITY virtual void UnlockAfterFork(FEXCore::Core::InternalThreadState *Thread, bool Child) {} +#endif FEX_DEFAULT_VISIBILITY virtual void SetSignalDelegator(FEXCore::SignalDelegator *SignalDelegation) = 0; FEX_DEFAULT_VISIBILITY virtual void SetSyscallHandler(FEXCore::HLE::SyscallHandler *Handler) = 0; diff --git a/External/FEXCore/include/FEXCore/Utils/DeferredSignalMutex.h b/External/FEXCore/include/FEXCore/Utils/DeferredSignalMutex.h index e84fb90b5..4fed0fd49 100644 --- a/External/FEXCore/include/FEXCore/Utils/DeferredSignalMutex.h +++ b/External/FEXCore/include/FEXCore/Utils/DeferredSignalMutex.h @@ -7,7 +7,9 @@ #include #include #include +#ifndef _WIN32 #include +#endif #include namespace FEXCore { @@ -93,8 +95,70 @@ namespace FEXCore { }; #else // Windows doesn't support forking, so these can be standard mutexes. - using ForkableUniqueMutex = std::mutex; - using ForkableSharedMutex = std::shared_mutex; + class ForkableUniqueMutex final { + public: + ForkableUniqueMutex() = default; + + // Non-moveable + ForkableUniqueMutex(const ForkableUniqueMutex&) = delete; + ForkableUniqueMutex& operator=(const ForkableUniqueMutex&) = delete; + ForkableUniqueMutex(ForkableUniqueMutex &&rhs) = delete; + ForkableUniqueMutex& operator=(ForkableUniqueMutex &&) = delete; + + void lock() { + Mutex.lock(); + } + void unlock() { + Mutex.unlock(); + } + // Initialize the internal pthread object to its default initializer state. + // Should only ever be used in the child process when a Linux fork() has occured. + void StealAndDropActiveLocks() { + LogMan::Msg::AFmt("{} is unsupported on WIN32 builds!", __func__); + } + private: + std::mutex Mutex; + }; + + class ForkableSharedMutex final { + public: + ForkableSharedMutex() = default; + + // Non-moveable + ForkableSharedMutex(const ForkableSharedMutex&) = delete; + ForkableSharedMutex& operator=(const ForkableSharedMutex&) = delete; + ForkableSharedMutex(ForkableSharedMutex &&rhs) = delete; + ForkableSharedMutex& operator=(ForkableSharedMutex &&) = delete; + + void lock() { + Mutex.lock(); + } + void unlock() { + Mutex.unlock(); + } + void lock_shared() { + Mutex.lock_shared(); + } + + void unlock_shared() { + Mutex.unlock_shared(); + } + + bool try_lock() { + return Mutex.try_lock(); + } + + bool try_lock_shared() { + return Mutex.try_lock_shared(); + } + // Initialize the internal pthread object to its default initializer state. + // Should only ever be used in the child process when a Linux fork() has occured. + void StealAndDropActiveLocks() { + LogMan::Msg::AFmt("{} is unsupported on WIN32 builds!", __func__); + } + private: + std::shared_mutex Mutex; + }; #endif template @@ -165,10 +229,37 @@ namespace FEXCore { &FEXCore::ForkableSharedMutex::lock, &FEXCore::ForkableSharedMutex::unlock>; + class ScopedSignalMasker final { + public: + ScopedSignalMasker() = default; + + void Mask(uint64_t Mask) { +#ifndef _WIN32 + // Mask all signals, storing the original incoming mask + ::syscall(SYS_rt_sigprocmask, SIG_SETMASK, &Mask, &OriginalMask, sizeof(OriginalMask)); +#endif + } + + // Move-only type + ScopedSignalMasker(const ScopedSignalMasker&) = delete; + ScopedSignalMasker& operator=(ScopedSignalMasker&) = delete; + ScopedSignalMasker(ScopedSignalMasker &&rhs) = default; + ScopedSignalMasker& operator=(ScopedSignalMasker &&) = default; + + void Unmask() { +#ifndef _WIN32 + ::syscall(SYS_rt_sigprocmask, SIG_SETMASK, &OriginalMask, nullptr, sizeof(OriginalMask)); +#endif + } + private: +#ifndef _WIN32 + uint64_t OriginalMask{}; +#endif + }; + template class ScopedPotentialDeferredSignalWithMutexBase final { public: - ScopedPotentialDeferredSignalWithMutexBase(MutexType &_Mutex, FEXCore::Core::InternalThreadState *Thread, uint64_t Mask = ~0ULL) : Mutex {&_Mutex} , Thread {Thread} { @@ -176,8 +267,7 @@ namespace FEXCore { Thread->CurrentFrame->State.DeferredSignalRefCount.Increment(1); } else { - // Mask all signals, storing the original incoming mask - ::syscall(SYS_rt_sigprocmask, SIG_SETMASK, &Mask, &OriginalMask, sizeof(OriginalMask)); + Masker.Mask(Mask); } // Lock the mutex (Mutex->*lock_fn)(); @@ -201,29 +291,29 @@ namespace FEXCore { if (Thread) { #ifdef _M_X86_64 - // Needs to be atomic so that operations can't end up getting reordered around this. - // Without this, the refcount and the signal access could get reordered. - auto Result = Thread->CurrentFrame->State.DeferredSignalRefCount.Decrement(1); + // Needs to be atomic so that operations can't end up getting reordered around this. + // Without this, the refcount and the signal access could get reordered. + auto Result = Thread->CurrentFrame->State.DeferredSignalRefCount.Decrement(1); - // X86-64 must do an additional check around the store. - if ((Result - 1) == 0) { - // Must happen after the refcount store - Thread->CurrentFrame->State.DeferredSignalFaultAddress->Store(0); - } + // X86-64 must do an additional check around the store. + if ((Result - 1) == 0) { + // Must happen after the refcount store + Thread->CurrentFrame->State.DeferredSignalFaultAddress->Store(0); + } #else - Thread->CurrentFrame->State.DeferredSignalRefCount.Decrement(1); - Thread->CurrentFrame->State.DeferredSignalFaultAddress->Store(0); + Thread->CurrentFrame->State.DeferredSignalRefCount.Decrement(1); + Thread->CurrentFrame->State.DeferredSignalFaultAddress->Store(0); #endif } else { // Unmask back to the original signal mask - ::syscall(SYS_rt_sigprocmask, SIG_SETMASK, &OriginalMask, nullptr, sizeof(OriginalMask)); + Masker.Unmask(); } } } private: MutexType *Mutex; - uint64_t OriginalMask{}; + ScopedSignalMasker Masker; FEXCore::Core::InternalThreadState *Thread; }; diff --git a/External/FEXCore/include/FEXCore/fextl/fmt.h b/External/FEXCore/include/FEXCore/fextl/fmt.h index 052b2e724..8e28def22 100644 --- a/External/FEXCore/include/FEXCore/fextl/fmt.h +++ b/External/FEXCore/include/FEXCore/fextl/fmt.h @@ -58,7 +58,7 @@ namespace fextl::fmt { FMT_INLINE auto print(::fmt::format_string fmt, T&&... args) -> void { auto String = fextl::fmt::vformat(fmt, ::fmt::make_format_args(args...)); - auto f = fextl::file::File::GetStdOUT(); + auto f = FEXCore::File::File::GetStdOUT(); f.Write(String.c_str(), String.size()); } diff --git a/FEXHeaderUtils/FEXHeaderUtils/SymlinkChecks.h b/FEXHeaderUtils/FEXHeaderUtils/SymlinkChecks.h index 87e23b7b8..f1dcf2d4e 100644 --- a/FEXHeaderUtils/FEXHeaderUtils/SymlinkChecks.h +++ b/FEXHeaderUtils/FEXHeaderUtils/SymlinkChecks.h @@ -7,6 +7,7 @@ #include namespace FHU::Symlinks { +#ifndef _WIN32 // Checks to see if a filepath is a symlink. inline bool IsSymlink(const fextl::string &Filename) { struct stat Buffer{}; @@ -26,4 +27,5 @@ inline std::string_view ResolveSymlink(const fextl::string &Filename, std::span< return std::string_view(ResultBuffer.data(), Result); } +#endif } diff --git a/Source/Common/CMakeLists.txt b/Source/Common/CMakeLists.txt index e232dabf5..a5dcb9c46 100644 --- a/Source/Common/CMakeLists.txt +++ b/Source/Common/CMakeLists.txt @@ -2,13 +2,13 @@ add_subdirectory(cpp-optparse/) set(NAME Common) set(SRCS + Config.cpp ArgumentLoader.cpp EnvironmentLoader.cpp StringUtil.cpp) if (NOT MINGW_BUILD) list (APPEND SRCS - Config.cpp FEXServerClient.cpp FileFormatCheck.cpp) endif() diff --git a/Source/Common/Config.cpp b/Source/Common/Config.cpp index a55e73e43..0bc6c8d64 100644 --- a/Source/Common/Config.cpp +++ b/Source/Common/Config.cpp @@ -10,9 +10,11 @@ #include #include +#ifndef _WIN32 #include -#include #include +#endif +#include #include #include #include @@ -103,12 +105,13 @@ namespace JSON { Dest = json_objClose(Dest); json_end(Dest); - constexpr int USER_PERMS = S_IRWXU | S_IRWXG | S_IRWXO; - int FD = open(Filename.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC, USER_PERMS); + auto File = FEXCore::File::File(Filename.c_str(), + FEXCore::File::FileModes::WRITE | + FEXCore::File::FileModes::CREATE | + FEXCore::File::FileModes::TRUNCATE); - if (FD != -1) { - write(FD, Buffer, strlen(Buffer)); - close(FD); + if (File.IsValid()) { + File.Write(Buffer, strlen(Buffer)); } } @@ -286,7 +289,7 @@ namespace JSON { // This is because we rewrite `/proc/self/exe` to the absolute program path calculated in here. if (!Program.starts_with('/')) { char ExistsTempPath[PATH_MAX]; - char *RealPath = realpath(Program.c_str(), ExistsTempPath); + char *RealPath = FHU::Filesystem::Absolute(Program.c_str(), ExistsTempPath); if (RealPath) { Program = RealPath; } @@ -315,6 +318,7 @@ namespace JSON { // execveat binfmt_misc args layout: `FEXInterpreter ...` // - Regular execveat with FD. FD points to file on disk that has been deleted. // execveat binfmt_misc args layout: `FEXInterpreter /dev/fd/ ...` +#ifndef _WIN32 if (ExecFDInterp || !ProgramFDFromEnv.empty()) { // Only in the case that FEX is executing an FD will the program argument potentially be a symlink. // This symlink will be in the style of `/dev/fd/`. @@ -331,6 +335,7 @@ namespace JSON { } } } +#endif return Program; } @@ -425,6 +430,7 @@ namespace JSON { return {}; } +#ifndef _WIN32 char const* FindUserHomeThroughUID() { auto passwd = getpwuid(geteuid()); if (passwd) { @@ -525,4 +531,10 @@ namespace JSON { FEXCore::Config::SetConfigFileLocation(GetConfigFileLocation(false), false); FEXCore::Config::SetConfigFileLocation(GetConfigFileLocation(true), true); } +#else + void InitializeConfigs() { + // TODO: Find out how to set this up on WIN32. + LogMan::Msg::EFmt("{} Unsupported on WIN32!", __func__); + } +#endif } From 5fef0c29aab6f4e02610338a573070138e85a00e Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Fri, 7 Jul 2023 14:40:50 -0700 Subject: [PATCH 2/2] FEXCore: Rename Telemetry helper function `GetObject` WIN32 has a define already called `GetObject` and will cause our symbol to have an A appended to it and break linking. Just rename it to `GetTelemetryValue` --- External/FEXCore/Source/Utils/Telemetry.cpp | 2 +- External/FEXCore/include/FEXCore/Utils/Telemetry.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/External/FEXCore/Source/Utils/Telemetry.cpp b/External/FEXCore/Source/Utils/Telemetry.cpp index 03300179d..75890bbb5 100644 --- a/External/FEXCore/Source/Utils/Telemetry.cpp +++ b/External/FEXCore/Source/Utils/Telemetry.cpp @@ -61,7 +61,7 @@ namespace FEXCore::Telemetry { } } - Value &GetObject(TelemetryType Type) { + Value &GetTelemetryValue(TelemetryType Type) { return TelemetryValues.at(Type); } #endif diff --git a/External/FEXCore/include/FEXCore/Utils/Telemetry.h b/External/FEXCore/include/FEXCore/Utils/Telemetry.h index e70b89ebc..1672389a6 100644 --- a/External/FEXCore/include/FEXCore/Utils/Telemetry.h +++ b/External/FEXCore/include/FEXCore/Utils/Telemetry.h @@ -41,7 +41,7 @@ namespace FEXCore::Telemetry { TYPE_LAST, }; - Value &GetObject(TelemetryType Type); + FEX_DEFAULT_VISIBILITY Value &GetTelemetryValue(TelemetryType Type); FEX_DEFAULT_VISIBILITY void Initialize(); FEX_DEFAULT_VISIBILITY void Shutdown(fextl::string const &ApplicationName); @@ -50,8 +50,8 @@ namespace FEXCore::Telemetry { // This returns the internal structure to the telemetry data structures // One must be careful with placing these in the hot path of code execution // It can be fairly costly, especially in the static version where it puts barriers in the code -#define FEXCORE_TELEMETRY_STATIC_INIT(Name, Type) static FEXCore::Telemetry::Value &Name = FEXCore::Telemetry::GetObject(FEXCore::Telemetry::Type) -#define FEXCORE_TELEMETRY_INIT(Name, Type) FEXCore::Telemetry::Value &Name = FEXCore::Telemetry::GetObject(FEXCore::Telemetry::Type) +#define FEXCORE_TELEMETRY_STATIC_INIT(Name, Type) static FEXCore::Telemetry::Value &Name = FEXCore::Telemetry::GetTelemetryValue(FEXCore::Telemetry::Type) +#define FEXCORE_TELEMETRY_INIT(Name, Type) FEXCore::Telemetry::Value &Name = FEXCore::Telemetry::GetTelemetryValue(FEXCore::Telemetry::Type) // Telemetry ALU operations // These are typically 3-4 instructions depending on what you're doing #define FEXCORE_TELEMETRY_SET(Name, Value) Name = Value