From 2793e46c8bde5dbed2d45c62fb909d0186f9e05b Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Sat, 17 Oct 2026 07:03:03 -0400 Subject: [PATCH] [Refactor] (CMakeLists.txt, MG_Pipe): move the device-loss debug knobs out of PipeApply.cpp - PipeDeviceLossKnobs.cpp holds MGPipeDebugDeviceLossDue and MGPipeDebugSessionLossDue as they were; PipeApply.cpp keeps the session-fail seam its comment places there --- CMakeLists.txt | 1 + MobileGL/MG_Pipe/PipeApply.cpp | 83 ------------------ MobileGL/MG_Pipe/PipeDeviceLossKnobs.cpp | 106 +++++++++++++++++++++++ 3 files changed, 107 insertions(+), 83 deletions(-) create mode 100644 MobileGL/MG_Pipe/PipeDeviceLossKnobs.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 5eb19767..0184ba26 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -648,6 +648,7 @@ list(APPEND SOURCE_FILES # pull build gains no symbol from P2 (G1) - a declaration emits nothing. MobileGL/MG_Pipe/MGPipeRenderStateSpans.cpp MobileGL/MG_Pipe/PipeApply.cpp + MobileGL/MG_Pipe/PipeDeviceLossKnobs.cpp MobileGL/MG_Impl/Pipe/SlotAllocator.cpp # P4a's contract: the reflection-archive serializer over ProgramArtifacts.h's # VisitFields tables. Push-only for the same G1 reason as the three above - in diff --git a/MobileGL/MG_Pipe/PipeApply.cpp b/MobileGL/MG_Pipe/PipeApply.cpp index c5b3137d..416219e2 100644 --- a/MobileGL/MG_Pipe/PipeApply.cpp +++ b/MobileGL/MG_Pipe/PipeApply.cpp @@ -62,9 +62,6 @@ #include #include #include -#if defined(__ANDROID__) -#include -#endif // THE VERDICT OF EVERY TRIP WIRE IN THIS FILE, IN ONE PLACE. // @@ -281,86 +278,6 @@ namespace MobileGL::MG_Pipe { return g_sessionLatchArmedHook != nullptr && g_sessionLatchArmedHook(); } -#if MOBILEGL_BUILD_DISAGGREGATED - bool MGPipeDebugDeviceLossDue() { - long at = 0; - if (const char* value = std::getenv("MOBILEGL_DEBUG_INJECT_DEVICE_LOST_AT")) { - at = std::strtol(value, nullptr, 10); - } -#if defined(__ANDROID__) - else { - char property[PROP_VALUE_MAX] = {}; - if (__system_property_get("debug.mobilegl.inject_device_lost_at", property) > 0) { - at = std::strtol(property, nullptr, 10); - } - } -#endif - static std::atomic armedAt{0}; - static std::atomic seen{0}; - static std::atomic fired{false}; - if (at <= 0) { - // Unset (or 0) disarms: the same value set again counts afresh. - if (armedAt.load(std::memory_order_relaxed) != 0) armedAt.store(0, std::memory_order_relaxed); - return false; - } - // A NEW VALUE RE-ARMS. One server process outlives many sessions, so a second loss is - // injected by setting the knob again (another value, or 0 and then a value): the count - // restarts from the checks made after it was seen. - if (long previous = armedAt.load(std::memory_order_acquire); - previous != at && armedAt.compare_exchange_strong(previous, at, std::memory_order_acq_rel)) { - seen.store(0, std::memory_order_release); - fired.store(false, std::memory_order_release); - } - if (fired.load(std::memory_order_acquire)) return false; - if (seen.fetch_add(1, std::memory_order_acq_rel) + 1 < at) return false; - if (fired.exchange(true, std::memory_order_acq_rel)) return false; - MGLOG_E("MGPipe: debug knob inject_device_lost_at=%ld - this device check reports the device LOST", at); - return true; - } - - bool MGPipeDebugSessionLossDue(unsigned clientPid) { - if (clientPid == 0) return false; - // The first call on a thread only starts the clock, so a session is first asked 100 ms - // after it started rendering - never in the middle of its first make-current. - thread_local auto lastAsked = std::chrono::steady_clock::time_point{}; - const auto now = std::chrono::steady_clock::now(); - if (lastAsked == std::chrono::steady_clock::time_point{}) { - lastAsked = now; - return false; - } - if (now - lastAsked < std::chrono::milliseconds(100)) return false; - lastAsked = now; - long target = 0; - if (const char* value = std::getenv("MOBILEGL_DEBUG_INJECT_DEVICE_LOST_PID")) { - target = std::strtol(value, nullptr, 10); - } -#if defined(__ANDROID__) - else { - char property[PROP_VALUE_MAX] = {}; - if (__system_property_get("debug.mobilegl.inject_device_lost_pid", property) > 0) { - target = std::strtol(property, nullptr, 10); - } - } -#endif - // Once per value: the session it hit is over, and a later session of the same process (the - // recovery's) must not be lost again by the same setting. Another pid - or unset/0 and - // then the same one - re-arms it. - static std::atomic firedFor{0}; - if (target <= 0) { - if (firedFor.load(std::memory_order_relaxed) != 0) firedFor.store(0, std::memory_order_relaxed); - return false; - } - if (static_cast(target) != clientPid) return false; - long previous = firedFor.load(std::memory_order_acquire); - if (previous == target || !firedFor.compare_exchange_strong(previous, target, std::memory_order_acq_rel)) { - return false; - } - MGLOG_E("MGPipe: debug knob inject_device_lost_pid=%ld - this session's device is reported LOST", target); - return true; - } - -#endif // MOBILEGL_BUILD_DISAGGREGATED - bool MGPipeSessionLatch(MGPipeFatalFamily family, const char* fmt, ...) { char line[512]; va_list args; diff --git a/MobileGL/MG_Pipe/PipeDeviceLossKnobs.cpp b/MobileGL/MG_Pipe/PipeDeviceLossKnobs.cpp new file mode 100644 index 00000000..b0ae9a0a --- /dev/null +++ b/MobileGL/MG_Pipe/PipeDeviceLossKnobs.cpp @@ -0,0 +1,106 @@ +// MobileGL - MobileGL/MG_Pipe/PipeDeviceLossKnobs.cpp +// Copyright (c) 2025-2026 MobileGL-Dev +// Licensed under the GNU Lesser General Public License v3.0: +// https://www.gnu.org/licenses/gpl-3.0.txt +// https://www.gnu.org/licenses/lgpl-3.0.txt +// SPDX-License-Identifier: LGPL-3.0-only +// End of Source File Header + +// The device-loss debug knobs (MG_Pipe/PipeSessionFail.h): a device check, or one client's +// session, reported lost on demand, so the containment of a real loss can be driven without a GPU +// that faults. + +#include +#include +#include + +#include +#include +#include +#include +#include +#if defined(__ANDROID__) +#include +#endif + +namespace MobileGL::MG_Pipe { +#if MOBILEGL_BUILD_DISAGGREGATED + bool MGPipeDebugDeviceLossDue() { + long at = 0; + if (const char* value = std::getenv("MOBILEGL_DEBUG_INJECT_DEVICE_LOST_AT")) { + at = std::strtol(value, nullptr, 10); + } +#if defined(__ANDROID__) + else { + char property[PROP_VALUE_MAX] = {}; + if (__system_property_get("debug.mobilegl.inject_device_lost_at", property) > 0) { + at = std::strtol(property, nullptr, 10); + } + } +#endif + static std::atomic armedAt{0}; + static std::atomic seen{0}; + static std::atomic fired{false}; + if (at <= 0) { + // Unset (or 0) disarms: the same value set again counts afresh. + if (armedAt.load(std::memory_order_relaxed) != 0) armedAt.store(0, std::memory_order_relaxed); + return false; + } + // A NEW VALUE RE-ARMS. One server process outlives many sessions, so a second loss is + // injected by setting the knob again (another value, or 0 and then a value): the count + // restarts from the checks made after it was seen. + if (long previous = armedAt.load(std::memory_order_acquire); + previous != at && armedAt.compare_exchange_strong(previous, at, std::memory_order_acq_rel)) { + seen.store(0, std::memory_order_release); + fired.store(false, std::memory_order_release); + } + if (fired.load(std::memory_order_acquire)) return false; + if (seen.fetch_add(1, std::memory_order_acq_rel) + 1 < at) return false; + if (fired.exchange(true, std::memory_order_acq_rel)) return false; + MGLOG_E("MGPipe: debug knob inject_device_lost_at=%ld - this device check reports the device LOST", at); + return true; + } + + bool MGPipeDebugSessionLossDue(unsigned clientPid) { + if (clientPid == 0) return false; + // The first call on a thread only starts the clock, so a session is first asked 100 ms + // after it started rendering - never in the middle of its first make-current. + thread_local auto lastAsked = std::chrono::steady_clock::time_point{}; + const auto now = std::chrono::steady_clock::now(); + if (lastAsked == std::chrono::steady_clock::time_point{}) { + lastAsked = now; + return false; + } + if (now - lastAsked < std::chrono::milliseconds(100)) return false; + lastAsked = now; + long target = 0; + if (const char* value = std::getenv("MOBILEGL_DEBUG_INJECT_DEVICE_LOST_PID")) { + target = std::strtol(value, nullptr, 10); + } +#if defined(__ANDROID__) + else { + char property[PROP_VALUE_MAX] = {}; + if (__system_property_get("debug.mobilegl.inject_device_lost_pid", property) > 0) { + target = std::strtol(property, nullptr, 10); + } + } +#endif + // Once per value: the session it hit is over, and a later session of the same process (the + // recovery's) must not be lost again by the same setting. Another pid - or unset/0 and + // then the same one - re-arms it. + static std::atomic firedFor{0}; + if (target <= 0) { + if (firedFor.load(std::memory_order_relaxed) != 0) firedFor.store(0, std::memory_order_relaxed); + return false; + } + if (static_cast(target) != clientPid) return false; + long previous = firedFor.load(std::memory_order_acquire); + if (previous == target || !firedFor.compare_exchange_strong(previous, target, std::memory_order_acq_rel)) { + return false; + } + MGLOG_E("MGPipe: debug knob inject_device_lost_pid=%ld - this session's device is reported LOST", target); + return true; + } + +#endif // MOBILEGL_BUILD_DISAGGREGATED +} // namespace MobileGL::MG_Pipe