From cb12f7fa1e628bfde7478ced21f3ce2cf49d8ed3 Mon Sep 17 00:00:00 2001 From: "Herman S." <429230+has207@users.noreply.github.com> Date: Thu, 26 Mar 2026 22:07:28 +0900 Subject: [PATCH] [Build] Generalize POSIX platform guards Most non-Windows code paths use standard POSIX APIs (sockets, signals, dlopen, threading) that work on any POSIX platform. Change Linux-specific guards to !WIN32 or #else where the code is portable. Linux-specific APIs (SIGRTMIN, Vulkan/X11, fontconfig/GTK) remain Linux-guarded. --- src/xenia/base/atomic.h | 6 +---- src/xenia/base/mutex.h | 2 +- src/xenia/cpu/backend/x64/x64_backend.cc | 12 +++------- src/xenia/kernel/xam/xam_net.cc | 3 ++- .../kernel/xboxkrnl/xboxkrnl_threading.cc | 4 +--- src/xenia/kernel/xsocket.cc | 4 ++-- src/xenia/kernel/xthread.cc | 18 +++++++------- src/xenia/kernel/xthread.h | 8 +++---- src/xenia/ui/renderdoc_api.cc | 24 +++++++++---------- src/xenia/ui/renderdoc_api.h | 6 ++--- 10 files changed, 39 insertions(+), 48 deletions(-) diff --git a/src/xenia/base/atomic.h b/src/xenia/base/atomic.h index cd2e3b2f0..b02ab07c9 100644 --- a/src/xenia/base/atomic.h +++ b/src/xenia/base/atomic.h @@ -74,7 +74,7 @@ inline void atomic_store_release(uint32_t new_value, volatile uint32_t* value) { _InterlockedExchange(reinterpret_cast(value), new_value); } -#elif XE_PLATFORM_LINUX || XE_PLATFORM_MAC +#else inline int32_t atomic_inc(volatile int32_t* value) { return __sync_add_and_fetch(value, 1); @@ -133,10 +133,6 @@ inline bool atomic_cas(int64_t old_value, int64_t new_value, reinterpret_cast(value), old_value, new_value); } -#else - -#error No atomic primitives defined for this platform/cpu combination. - #endif // XE_PLATFORM inline uint32_t atomic_inc(volatile uint32_t* value) { diff --git a/src/xenia/base/mutex.h b/src/xenia/base/mutex.h index 94aa36e59..0e1fde23b 100644 --- a/src/xenia/base/mutex.h +++ b/src/xenia/base/mutex.h @@ -15,7 +15,7 @@ #include "platform.h" #if XE_PLATFORM_WIN32 #include "platform_win.h" -#elif XE_PLATFORM_LINUX +#else #include #endif #include "memory.h" diff --git a/src/xenia/cpu/backend/x64/x64_backend.cc b/src/xenia/cpu/backend/x64/x64_backend.cc index 3e43c1209..eabfb41d0 100644 --- a/src/xenia/cpu/backend/x64/x64_backend.cc +++ b/src/xenia/cpu/backend/x64/x64_backend.cc @@ -662,7 +662,7 @@ HostToGuestThunk X64HelperEmitter::EmitHostToGuestThunk() { mov(rdx, qword[rsp + 8 * 2]); mov(r8, qword[rsp + 8 * 3]); ret(); -#elif XE_PLATFORM_LINUX || XE_PLATFORM_MAC +#else // System-V ABI args: // rdi = target // rsi = arg0 (context) @@ -704,8 +704,6 @@ HostToGuestThunk X64HelperEmitter::EmitHostToGuestThunk() { add(rsp, stack_size); ret(); -#else - assert_always("Unknown platform ABI in host to guest thunk!"); #endif code_offsets.tail = getSize(); @@ -761,7 +759,7 @@ GuestToHostThunk X64HelperEmitter::EmitGuestToHostThunk() { add(rsp, stack_size); ret(); -#elif XE_PLATFORM_LINUX || XE_PLATFORM_MAC +#else // This function is being called using the Microsoft ABI from CallNative // rcx = target function // rdx = arg0 @@ -812,8 +810,6 @@ GuestToHostThunk X64HelperEmitter::EmitGuestToHostThunk() { add(rsp, stack_size); ret(); -#else - assert_always("Unknown platform ABI in guest to host thunk!") #endif code_offsets.tail = getSize(); @@ -867,7 +863,7 @@ ResolveFunctionThunk X64HelperEmitter::EmitResolveFunctionThunk() { add(rsp, stack_size); jmp(rax); -#elif XE_PLATFORM_LINUX || XE_PLATFORM_MAC +#else // Function is called with the following params: // ebx = target PPC address // rsi = context @@ -906,8 +902,6 @@ ResolveFunctionThunk X64HelperEmitter::EmitResolveFunctionThunk() { add(rsp, stack_size); jmp(rax); -#else - assert_always("Unknown platform ABI in resolve function!"); #endif code_offsets.tail = getSize(); diff --git a/src/xenia/kernel/xam/xam_net.cc b/src/xenia/kernel/xam/xam_net.cc index d05f39a07..bb5407614 100644 --- a/src/xenia/kernel/xam/xam_net.cc +++ b/src/xenia/kernel/xam/xam_net.cc @@ -23,10 +23,11 @@ // NOTE: must be included last as it expects windows.h to already be included. #define _WINSOCK_DEPRECATED_NO_WARNINGS // inet_addr #include // NOLINT(build/include_order) -#elif XE_PLATFORM_LINUX +#else #include #include #include +#include #include #endif diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc index a9c508ae9..3a4cb2423 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc @@ -244,7 +244,7 @@ dword_result_t NtSuspendThread_entry(dword_t handle, } else { return X_STATUS_THREAD_IS_TERMINATING; } -#elif XE_PLATFORM_LINUX +#else // Handle self-suspension specially to avoid deadlock. if (!thread->guest_object()->terminated) { bool is_self_suspend = @@ -261,8 +261,6 @@ dword_result_t NtSuspendThread_entry(dword_t handle, } else { return X_STATUS_THREAD_IS_TERMINATING; } -#else -#error "Unsupported platform" #endif } else { return X_STATUS_OBJECT_TYPE_MISMATCH; diff --git a/src/xenia/kernel/xsocket.cc b/src/xenia/kernel/xsocket.cc index a9ac1554f..3376f57df 100644 --- a/src/xenia/kernel/xsocket.cc +++ b/src/xenia/kernel/xsocket.cc @@ -86,7 +86,7 @@ X_STATUS XSocket::Initialize(AddressFamily af, Type type, Protocol proto) { X_STATUS XSocket::Close() { #if XE_PLATFORM_WIN32 int ret = closesocket(native_handle_); -#elif XE_PLATFORM_LINUX +#else int ret = close(native_handle_); #endif @@ -166,7 +166,7 @@ X_STATUS XSocket::IOControl(uint32_t cmd, uint8_t* arg_ptr) { return X_STATUS_UNSUCCESSFUL; } return X_STATUS_SUCCESS; -#elif XE_PLATFORM_LINUX +#else int native_cmd = cmd; assert_false(!supported_controls.contains(cmd)); diff --git a/src/xenia/kernel/xthread.cc b/src/xenia/kernel/xthread.cc index f89bd29ad..19be6a6cd 100644 --- a/src/xenia/kernel/xthread.cc +++ b/src/xenia/kernel/xthread.cc @@ -9,7 +9,7 @@ #include "xenia/kernel/xthread.h" -#if XE_PLATFORM_LINUX +#if !XE_PLATFORM_WIN32 #include #endif @@ -556,17 +556,19 @@ void XThread::Execute() { // On Windows, setjmp/longjmp is used because MSVC's longjmp performs SEH // stack unwinding which already calls destructors. uint32_t next_address; -#if XE_PLATFORM_LINUX +#if !XE_PLATFORM_WIN32 try { exit_code = static_cast(kernel_state()->processor()->Execute( thread_state_, address, args.data(), args.size())); next_address = 0; } catch (const FiberReentryException& e) { +#if XE_PLATFORM_LINUX // Ensure SIGRTMIN (used for thread suspend) is not left blocked. sigset_t set; sigemptyset(&set); sigaddset(&set, SIGRTMIN); pthread_sigmask(SIG_UNBLOCK, &set, nullptr); +#endif next_address = e.address; } @@ -578,10 +580,12 @@ void XThread::Execute() { exit_code = static_cast(thread_state_->context()->r[3]); } } catch (const FiberReentryException& e) { +#if XE_PLATFORM_LINUX sigset_t set; sigemptyset(&set); sigaddset(&set, SIGRTMIN); pthread_sigmask(SIG_UNBLOCK, &set, nullptr); +#endif next_address = e.address; } } @@ -616,7 +620,7 @@ void XThread::Reenter(uint32_t address) { // Called when the game switches fiber stacks (e.g., via // KeSetCurrentStackPointers in games like Forza Horizon 2). // Must unwind through all frames between here and Execute(). -#if XE_PLATFORM_LINUX +#if !XE_PLATFORM_WIN32 // Throw a C++ exception that unwinds through JIT frames (using DWARF // .eh_frame info) and host frames (using compiler-generated DWARF), // calling destructors properly along the way. @@ -767,7 +771,7 @@ X_STATUS XThread::Resume(uint32_t* out_suspend_count) { } else { return X_STATUS_UNSUCCESSFUL; } -#elif XE_PLATFORM_LINUX +#else // Use mutex to protect suspend_count access and coordinate with SelfSuspend. bool should_resume_host = false; { @@ -788,8 +792,6 @@ X_STATUS XThread::Resume(uint32_t* out_suspend_count) { thread_->Resume(&unused_host_suspend_count); } return X_STATUS_SUCCESS; -#else -#error "Unsupported platform" #endif } @@ -821,7 +823,7 @@ X_STATUS XThread::Suspend(uint32_t* out_suspend_count) { } } -#if XE_PLATFORM_LINUX +#if !XE_PLATFORM_WIN32 uint32_t XThread::SelfSuspend() { auto guest_thread = guest_object(); std::unique_lock lock(suspend_mutex_); @@ -831,7 +833,7 @@ uint32_t XThread::SelfSuspend() { lock, [guest_thread]() { return guest_thread->suspend_count == 0; }); return previous; } -#endif +#endif // !XE_PLATFORM_WIN32 X_STATUS XThread::Delay(uint32_t processor_mode, uint32_t alertable, uint64_t interval) { diff --git a/src/xenia/kernel/xthread.h b/src/xenia/kernel/xthread.h index 727d9a554..4c60e5c63 100644 --- a/src/xenia/kernel/xthread.h +++ b/src/xenia/kernel/xthread.h @@ -14,7 +14,7 @@ #include #include "xenia/base/mutex.h" -#if XE_PLATFORM_LINUX +#if !XE_PLATFORM_WIN32 #include #include #include @@ -343,7 +343,7 @@ struct X_KTHREAD { }; static_assert_size(X_KTHREAD, 0xAB0); -#if XE_PLATFORM_LINUX +#if !XE_PLATFORM_WIN32 // Exception thrown by XThread::Reenter() to unwind through JIT frames. // C++ exception unwinding uses DWARF .eh_frame info registered for JIT code, // ensuring destructors and RAII guards in host C++ frames are properly called. @@ -442,7 +442,7 @@ class XThread : public XObject, public cpu::Thread { X_STATUS Delay(uint32_t processor_mode, uint32_t alertable, uint64_t interval); -#if XE_PLATFORM_LINUX +#if !XE_PLATFORM_WIN32 // Performs self-suspension: increments suspend_count and blocks until // another thread calls Resume() and suspend_count reaches 0. // Returns the previous suspend_count value. @@ -490,7 +490,7 @@ class XThread : public XObject, public cpu::Thread { int32_t priority_ = 0; -#if XE_PLATFORM_LINUX +#if !XE_PLATFORM_WIN32 // Condition variable for thread self-suspension. std::mutex suspend_mutex_; std::condition_variable suspend_cv_; diff --git a/src/xenia/ui/renderdoc_api.cc b/src/xenia/ui/renderdoc_api.cc index af1a56f46..dd35f849d 100644 --- a/src/xenia/ui/renderdoc_api.cc +++ b/src/xenia/ui/renderdoc_api.cc @@ -12,10 +12,10 @@ #include "xenia/base/logging.h" #include "xenia/base/platform.h" -#if XE_PLATFORM_LINUX -#include -#elif XE_PLATFORM_WIN32 +#if XE_PLATFORM_WIN32 #include "xenia/base/platform_win.h" +#else +#include #endif namespace xe { @@ -29,7 +29,14 @@ std::unique_ptr RenderDocAPI::CreateIfConnected() { // The RenderDoc library should already be loaded into the process if // RenderDoc is attached - this is why RTLD_NOLOAD or GetModuleHandle instead // of LoadLibrary. -#if XE_PLATFORM_LINUX +#if XE_PLATFORM_WIN32 + renderdoc_api->library_ = GetModuleHandleW(L"renderdoc.dll"); + if (!renderdoc_api->library_) { + return nullptr; + } + get_api = pRENDERDOC_GetAPI( + GetProcAddress(renderdoc_api->library_, "RENDERDOC_GetAPI")); +#else #if XE_PLATFORM_ANDROID const char* const library_name = "libVkLayer_GLES_RenderDoc.so"; #else @@ -41,13 +48,6 @@ std::unique_ptr RenderDocAPI::CreateIfConnected() { } get_api = pRENDERDOC_GetAPI(dlsym(renderdoc_api->library_, "RENDERDOC_GetAPI")); -#elif XE_PLATFORM_WIN32 - renderdoc_api->library_ = GetModuleHandleW(L"renderdoc.dll"); - if (!renderdoc_api->library_) { - return nullptr; - } - get_api = pRENDERDOC_GetAPI( - GetProcAddress(renderdoc_api->library_, "RENDERDOC_GetAPI")); #endif // get_api will be null if RenderDoc is not connected, or the API isn't @@ -65,7 +65,7 @@ std::unique_ptr RenderDocAPI::CreateIfConnected() { } RenderDocAPI::~RenderDocAPI() { -#if XE_PLATFORM_LINUX +#if !XE_PLATFORM_WIN32 if (library_) { dlclose(library_); } diff --git a/src/xenia/ui/renderdoc_api.h b/src/xenia/ui/renderdoc_api.h index 0354717ee..aac20ba71 100644 --- a/src/xenia/ui/renderdoc_api.h +++ b/src/xenia/ui/renderdoc_api.h @@ -37,10 +37,10 @@ class RenderDocAPI { private: explicit RenderDocAPI() = default; -#if XE_PLATFORM_LINUX - void* library_ = nullptr; -#elif XE_PLATFORM_WIN32 +#if XE_PLATFORM_WIN32 HMODULE library_ = nullptr; +#else + void* library_ = nullptr; #endif const RENDERDOC_API_1_0_0* api_1_0_0_ = nullptr;