Преглед изворни кода

Converting steam/runtime

* steam_lifecycle uses DataMutex
Kenny Mecham пре 2 недеља
родитељ
комит
cc235cf67e

+ 4 - 3
Sunrise/src/steam/runtime/steam_context_state.cpp

@@ -5,8 +5,10 @@
 #include <atomic>
 #include <cstddef>
 #include <cstring>
+#include <mutex>
 
 #include "../interfaces/steam_interface_factory.h"
+#include "core/threading/srw_lock.h"
 #include "internal.h"
 #include "runtime.h"
 
@@ -32,7 +34,7 @@ enum class ContextField : std::size_t {
     interface = 2,   // Cached context interface pointer.
 };
 
-SRWLOCK g_contextLock{SRWLOCK_INIT};
+core::threading::SrwLock g_contextLock;
 std::atomic_uintptr_t g_contextGeneration{kFirstContextGeneration};
 std::atomic<DWORD> g_appId{};
 std::atomic<ApiCall> g_nextApiCall{kFirstApiCall};
@@ -77,7 +79,7 @@ void* context_init(void* data) noexcept {
     std::uintptr_t storedGeneration{};
     std::memcpy(&storedGeneration, &fields[generationIndex], sizeof(storedGeneration));
 
-    AcquireSRWLockExclusive(&g_contextLock);
+    const std::lock_guard lock(g_contextLock);
     if (storedGeneration != generation) {
         fields[interfaceIndex] = nullptr;
         const auto initializer = reinterpret_cast<void (*)(void*)>(fields[initializerIndex]);
@@ -88,7 +90,6 @@ void* context_init(void* data) noexcept {
         std::memcpy(&fields[generationIndex], &generation, sizeof(generation));
     }
     void* result = &fields[interfaceIndex];
-    ReleaseSRWLockExclusive(&g_contextLock);
     return result;
 }
 

+ 80 - 76
Sunrise/src/steam/runtime/steam_lifecycle.cpp

@@ -10,6 +10,7 @@
 #include "../../core/runtime/core_runtime.h"
 #include "../../core/runtime/host_environment.h"
 #include "callbacks/callback_registry.h"
+#include "core/threading/data_mutex.h"
 #include "internal.h"
 #include "runtime.h"
 #include "steam_context_state.h"
@@ -20,12 +21,15 @@ namespace {
 /** The only delay-loaded module allowed to start the platform Client group. */
 constexpr wchar_t kNetworkingModuleName[] = L"steamnetworkingsockets.dll";
 
-SRWLOCK g_lifecycleLock{SRWLOCK_INIT};
+struct Lifecycle {
+    bool mainActivationDone{};
+    bool mainActivationResult{};
+    bool graphicsActivationAttempted{};
+    bool platformActivationAttempted{};
+};
+
+core::threading::SharedDataMutex<Lifecycle> g_lifecycle;
 std::atomic_bool g_initialized{false};
-bool g_mainActivationDone{};
-bool g_mainActivationResult{};
-bool g_graphicsActivationAttempted{};
-bool g_platformActivationAttempted{};
 
 /**
  * Finds the loaded image that owns a caught return address. It takes no module reference.
@@ -55,60 +59,58 @@ bool initialize(void* module) noexcept {
     if (!client::hooks::egress::install()) {
         return false;
     }
-    AcquireSRWLockExclusive(&g_lifecycleLock);
-    if (g_initialized.load(std::memory_order_acquire)) {
-        ReleaseSRWLockExclusive(&g_lifecycleLock);
+
+    return g_lifecycle.lock_write([module](Lifecycle& lifecycle) {
+        if (g_initialized.load(std::memory_order_acquire)) {
+            return true;
+        }
+        if (!core::initialize(module)) {
+            return false;
+        }
+        // Base generation (_0) packages register during bootload, before the first callback pump,
+        // so package trust must attach at Steam init rather than in the main-image hook sweep.
+        if (!client::hooks::package_trust::install()) {
+            core::log::write(core::log::Channel::client,
+                             core::log::Level::error,
+                             "ev=steam_init stage=package_trust result=fail");
+            (void)core::shutdown();
+            return false;
+        }
+        advance_context_generation();
+        g_initialized.store(true, std::memory_order_release);
+        core::log::write(
+            core::log::Channel::client, core::log::Level::info, "ev=steam_init result=ok");
+        // The guard attaches above, before Core logging exists, so its outcome is reported here.
+        client::hooks::egress::report_installation();
         return true;
-    }
-    if (!core::initialize(module)) {
-        ReleaseSRWLockExclusive(&g_lifecycleLock);
-        return false;
-    }
-    // Base generation (_0) packages register during bootload, before the first callback pump, so
-    // package trust must attach at Steam init rather than in the main-image hook sweep.
-    if (!client::hooks::package_trust::install()) {
-        core::log::write(core::log::Channel::client,
-                         core::log::Level::error,
-                         "ev=steam_init stage=package_trust result=fail");
-        (void)core::shutdown();
-        ReleaseSRWLockExclusive(&g_lifecycleLock);
-        return false;
-    }
-    advance_context_generation();
-    g_initialized.store(true, std::memory_order_release);
-    core::log::write(core::log::Channel::client, core::log::Level::info, "ev=steam_init result=ok");
-    // The guard attaches above, before Core logging exists, so its outcome is reported here.
-    client::hooks::egress::report_installation();
-    ReleaseSRWLockExclusive(&g_lifecycleLock);
-    return true;
+    });
 }
 
 /** Stops callback delivery and clears Steam state. */
 bool shutdown() noexcept {
-    AcquireSRWLockExclusive(&g_lifecycleLock);
-    const bool hadRuntime = g_initialized.load(std::memory_order_acquire) || core::is_initialized();
-    if (!hadRuntime) {
-        ReleaseSRWLockExclusive(&g_lifecycleLock);
+    return g_lifecycle.lock_write([](Lifecycle& lifecycle) {
+        const bool hadRuntime =
+            g_initialized.load(std::memory_order_acquire) || core::is_initialized();
+        if (!hadRuntime) {
+            return true;
+        }
+        if (!core::shutdown()) {
+            core::log::write(core::log::Channel::client,
+                             core::log::Level::error,
+                             "ev=steam_shutdown stage=core result=fail");
+            return false;
+        }
+
+        // Callback pointers are released only after Client hooks stop producing events.
+        runtime::callbacks::clear();
+        g_initialized.store(false, std::memory_order_release);
+        lifecycle.mainActivationDone = false;
+        lifecycle.mainActivationResult = false;
+        lifecycle.graphicsActivationAttempted = false;
+        lifecycle.platformActivationAttempted = false;
+        advance_context_generation();
         return true;
-    }
-    if (!core::shutdown()) {
-        core::log::write(core::log::Channel::client,
-                         core::log::Level::error,
-                         "ev=steam_shutdown stage=core result=fail");
-        ReleaseSRWLockExclusive(&g_lifecycleLock);
-        return false;
-    }
-
-    // Callback pointers are released only after Client hooks stop producing events.
-    runtime::callbacks::clear();
-    g_initialized.store(false, std::memory_order_release);
-    g_mainActivationDone = false;
-    g_mainActivationResult = false;
-    g_graphicsActivationAttempted = false;
-    g_platformActivationAttempted = false;
-    advance_context_generation();
-    ReleaseSRWLockExclusive(&g_lifecycleLock);
-    return true;
+    });
 }
 
 /** @return True. The in-process Steam provider stays up for the whole DLL lifetime. */
@@ -122,33 +124,33 @@ namespace sunrise::steam::runtime {
 
 /** Runs main-image activation once, from a caller that proves the game is loaded. */
 bool activate_main_once() noexcept {
-    AcquireSRWLockExclusive(&g_lifecycleLock);
-    if (!g_mainActivationDone && core::is_initialized()) {
-        g_mainActivationDone = true;
-        g_mainActivationResult = client::activate_main_once();
-    }
-    const bool result = g_mainActivationResult;
-    ReleaseSRWLockExclusive(&g_lifecycleLock);
-    return result;
+    return g_lifecycle.lock_write([](Lifecycle& lifecycle) {
+        if (!lifecycle.mainActivationDone && core::is_initialized()) {
+            lifecycle.mainActivationDone = true;
+            lifecycle.mainActivationResult = client::activate_main_once();
+        }
+
+        const bool result = lifecycle.mainActivationResult;
+        return result;
+    });
 }
 
 /** @return True while the main-image sweep has not run yet. */
 bool main_activation_pending() noexcept {
-    AcquireSRWLockShared(&g_lifecycleLock);
-    const bool pending = !g_mainActivationDone;
-    ReleaseSRWLockShared(&g_lifecycleLock);
+    const bool pending = g_lifecycle.lock_read(
+        [](const Lifecycle& lifecycle) { return !lifecycle.mainActivationDone; });
     // Matches the activation's Core test. A failed Core must not raise an endless overlay.
     return pending && core::is_initialized();
 }
 
 /** Installs the presentation hooks once, from the callback pump, before the game sweep. */
 void activate_graphics_once() noexcept {
-    AcquireSRWLockExclusive(&g_lifecycleLock);
-    if (!g_graphicsActivationAttempted && core::is_initialized()) {
-        g_graphicsActivationAttempted = true;
-        (void)client::activate_graphics_once();
-    }
-    ReleaseSRWLockExclusive(&g_lifecycleLock);
+    g_lifecycle.lock_write([](Lifecycle& lifecycle) {
+        if (!lifecycle.graphicsActivationAttempted && core::is_initialized()) {
+            lifecycle.graphicsActivationAttempted = true;
+            (void)client::activate_graphics_once();
+        }
+    });
 }
 
 /** Activates the platform Client group at its exact interface request boundary. */
@@ -158,12 +160,14 @@ void activate_platform_once(const void* callerAddress) noexcept {
         return;
     }
 
-    AcquireSRWLockExclusive(&g_lifecycleLock);
-    if (!g_platformActivationAttempted && g_initialized.load(std::memory_order_acquire)) {
-        g_platformActivationAttempted = true;
-        (void)client::activate_platform_once(callerModule);
-    }
-    ReleaseSRWLockExclusive(&g_lifecycleLock);
+    g_lifecycle.lock_write([callerModule](Lifecycle& lifecycle) {
+        if (!lifecycle.platformActivationAttempted
+            && g_initialized.load(std::memory_order_acquire)) {
+
+            lifecycle.platformActivationAttempted = true;
+            (void)client::activate_platform_once(callerModule);
+        }
+    });
 }
 
 } // namespace sunrise::steam::runtime