mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 18:13:23 +09:00
[Feat] (P13 W5 S1): the fatal vocabulary moves to MG_Pipe and the record arm gets its own fail / latch seam.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
// MobileGL - MobileGL/MG_Remote/FatalFamilies.def
|
||||
// MobileGL - MobileGL/MG_Pipe/FatalFamilies.def
|
||||
// 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
|
||||
@@ -119,6 +119,66 @@
|
||||
|
||||
namespace MobileGL::MG_Pipe {
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// P13 W5: THE RECORD ARM'S FAIL / LATCH SEAM (PipeSessionFail.h). Constant-initialized
|
||||
// pointers, so a registration made during another translation unit's static init (FatalFunnel.cpp)
|
||||
// is never overwritten by this one's.
|
||||
namespace {
|
||||
constinit MGPipeRecordFailHook g_recordFailHook = nullptr;
|
||||
constinit MGPipeRecordLatchHook g_recordLatchHook = nullptr;
|
||||
constinit MGPipeRecordLatchedHook g_recordLatchedHook = nullptr;
|
||||
|
||||
void FormatRecordLine(char (&line)[512], const char* fmt, va_list args) {
|
||||
const int written = std::vsnprintf(line, sizeof(line), fmt, args);
|
||||
if (written < 0) {
|
||||
std::snprintf(line, sizeof(line), "MGPipe: unformattable Fatal diagnostic (format=%s)", fmt);
|
||||
}
|
||||
}
|
||||
|
||||
[[noreturn]] void RecordDeath(MGFatalFamily family, const char* line) {
|
||||
if (g_recordFailHook != nullptr) g_recordFailHook(family, line);
|
||||
// NO HOOK (no MG_Remote in this library): the line, its stderr echo - the logger's
|
||||
// console sink is off and a gtest death matcher reads the child's stderr - and the abort.
|
||||
MGLOG_F("%s", line);
|
||||
std::fputs(line, stderr);
|
||||
std::fputc('\n', stderr);
|
||||
std::fflush(stderr);
|
||||
std::abort();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void MGPipeInstallRecordFailHooks(MGPipeRecordFailHook fail, MGPipeRecordLatchHook latch,
|
||||
MGPipeRecordLatchedHook latched) {
|
||||
g_recordFailHook = fail;
|
||||
g_recordLatchHook = latch;
|
||||
g_recordLatchedHook = latched;
|
||||
}
|
||||
|
||||
void MGPipeRecordFail(MGFatalFamily family, const char* fmt, ...) {
|
||||
char line[512];
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
FormatRecordLine(line, fmt, args);
|
||||
va_end(args);
|
||||
RecordDeath(family, line);
|
||||
}
|
||||
|
||||
bool MGPipeRecordLatch(MGFatalFamily family, const char* fmt, ...) {
|
||||
char line[512];
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
FormatRecordLine(line, fmt, args);
|
||||
va_end(args);
|
||||
if (g_recordLatchHook != nullptr) return g_recordLatchHook(family, line);
|
||||
RecordDeath(family, line);
|
||||
}
|
||||
|
||||
bool MGPipeRecordLatched() { return g_recordLatchedHook != nullptr && g_recordLatchedHook(); }
|
||||
|
||||
MGPipeRecordFailHook MGPipeRecordFailHookInstalled() { return g_recordFailHook; }
|
||||
MGPipeRecordLatchHook MGPipeRecordLatchHookInstalled() { return g_recordLatchHook; }
|
||||
MGPipeRecordLatchedHook MGPipeRecordLatchedHookInstalled() { return g_recordLatchedHook; }
|
||||
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
// ----------------------------------------------------------------------------
|
||||
// THE BACKEND-SIDE SESSION-FAIL SEAM (P7 wave 0). PipeSessionFail.h holds the argument;
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
// MobileGL - MobileGL/MG_Pipe/PipeFatalFamily.h
|
||||
// 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
|
||||
|
||||
// P13 W5: THE FATAL VOCABULARY WITHOUT THE WIRE. The record arm runs in a library that has no
|
||||
// MG_Remote (the FCL shape), and its deaths still need their family words: a staged store that
|
||||
// cannot answer, a record whose bounds are wrong. So the enum and its names are generated here
|
||||
// from FatalFamilies.def, and MG_Remote/FatalFamily.h keeps only what needs the protocol - the
|
||||
// projection of a family onto the seven-value wire FatalCode - and re-exports these names.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include "FatalFamilies.def"
|
||||
|
||||
namespace MobileGL::MG_Pipe {
|
||||
|
||||
// One value per row of FatalFamilies.def, in file order. The names ARE the family words that
|
||||
// appear in every `Fatal{...}` log line, which is what lets FatalFamilyName round-trip
|
||||
// against the string a site passes.
|
||||
enum class MGFatalFamily : ::std::uint32_t {
|
||||
#define X(Family, WireCode, Why) Family,
|
||||
MGL_FATAL_FAMILY_LIST(X)
|
||||
#undef X
|
||||
};
|
||||
|
||||
// The family's own word, byte-for-byte what appears inside `Fatal{<name>, ...}`. A death
|
||||
// site passes both the enum and its full message string; a test asserts this name is present
|
||||
// in that string, which is what keeps the two from diverging.
|
||||
inline const char* FatalFamilyName(MGFatalFamily family) {
|
||||
switch (family) {
|
||||
#define X(Family, WireCode, Why) \
|
||||
case MGFatalFamily::Family: return #Family;
|
||||
MGL_FATAL_FAMILY_LIST(X)
|
||||
#undef X
|
||||
}
|
||||
return "<unknown>";
|
||||
}
|
||||
|
||||
// The count, for a test that walks every family.
|
||||
inline constexpr ::std::size_t MGFatalFamilyCount() {
|
||||
::std::size_t n = 0;
|
||||
#define X(Family, WireCode, Why) ++n;
|
||||
MGL_FATAL_FAMILY_LIST(X)
|
||||
#undef X
|
||||
return n;
|
||||
}
|
||||
|
||||
} // namespace MobileGL::MG_Pipe
|
||||
@@ -39,6 +39,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <MG_Pipe/PipeFatalFamily.h>
|
||||
|
||||
namespace MobileGL::MG_Pipe {
|
||||
|
||||
// THE FAMILIES THAT CROSS THIS BOUNDARY, AND ONLY THOSE. Not `MGFatalFamily` cast to an
|
||||
@@ -85,6 +87,44 @@ namespace MobileGL::MG_Pipe {
|
||||
#endif
|
||||
void MGPipeSessionFail(MGPipeFatalFamily family, const char* fmt, ...);
|
||||
|
||||
// ---- P13 W5: THE RECORD ARM'S DEATHS, IN EVERY BUILD -------------------------------------
|
||||
//
|
||||
// The record arm's own code - the staged stores, the verb sink, the verb port - dies by
|
||||
// family word (MG_Pipe::MGFatalFamily, the whole FatalFamilies.def vocabulary) and, where a
|
||||
// session can be ended instead of the process, latches. With MG_Remote linked, FatalFunnel.cpp
|
||||
// registers SessionFail / SessionLatch / SessionLatched here at static init, so every DISAGG
|
||||
// process - unit cases with no role init included - counts, publishes and latches exactly as
|
||||
// a direct call did. Without MG_Remote (the FCL shape) the defaults are the monolith answer:
|
||||
// log the line, echo it to stderr (a death test reads the child's stderr), abort; latching is
|
||||
// dying; nothing is ever latched.
|
||||
//
|
||||
// `line` is the FULLY FORMATTED message, family word and all, as for MGPipeSessionFail.
|
||||
using MGPipeRecordFailHook = void (*)(MGFatalFamily family, const char* line);
|
||||
using MGPipeRecordLatchHook = bool (*)(MGFatalFamily family, const char* line);
|
||||
using MGPipeRecordLatchedHook = bool (*)();
|
||||
// Last writer wins; a null leaves that half on its default.
|
||||
void MGPipeInstallRecordFailHooks(MGPipeRecordFailHook fail, MGPipeRecordLatchHook latch,
|
||||
MGPipeRecordLatchedHook latched);
|
||||
// The installed hooks, or nullptr - so a test proves the registration happened (and restores
|
||||
// what it replaced) without having to die to find out.
|
||||
MGPipeRecordFailHook MGPipeRecordFailHookInstalled();
|
||||
MGPipeRecordLatchHook MGPipeRecordLatchHookInstalled();
|
||||
MGPipeRecordLatchedHook MGPipeRecordLatchedHookInstalled();
|
||||
[[noreturn]]
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
__attribute__((format(printf, 2, 3)))
|
||||
#endif
|
||||
void MGPipeRecordFail(MGFatalFamily family, const char* fmt, ...);
|
||||
// Returns false (a Bool site reads `return MGPipeRecordLatch(...);`) when the hook latched the
|
||||
// calling session; with no latch to raise it dies as MGPipeRecordFail does.
|
||||
bool
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
__attribute__((format(printf, 2, 3)))
|
||||
#endif
|
||||
MGPipeRecordLatch(MGFatalFamily family, const char* fmt, ...);
|
||||
// Whether the calling session already latched (false with no hook).
|
||||
bool MGPipeRecordLatched();
|
||||
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
// ---- THE LATCH TWIN: A LOST GPU DEVICE ENDS ITS SESSION, NOT THE PROCESS ----------------
|
||||
//
|
||||
|
||||
@@ -10,23 +10,21 @@
|
||||
// wire FatalCode, both generated from FatalFamilies.def so a family, its name and its wire code
|
||||
// cannot drift apart: adding a family is one row, and a row that forgets its code does not
|
||||
// compile.
|
||||
//
|
||||
// P13 W5: the vocabulary itself (the enum, its names, its count) lives in MG_Pipe/PipeFatalFamily.h
|
||||
// so the record arm can die by name in a library without MG_Remote; this header adds the wire
|
||||
// projection and re-exports the vocabulary under its old names.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <MG_Pipe/PipeFatalFamily.h>
|
||||
#include <MG_Remote/Protocol/generated/protocol_generated.h>
|
||||
|
||||
#include "FatalFamilies.def"
|
||||
|
||||
namespace MobileGL::MG_Remote {
|
||||
|
||||
// One value per row of FatalFamilies.def, in file order. The names ARE the family words that
|
||||
// appear in every `Fatal{...}` log line, which is what lets FatalFamilyName round-trip
|
||||
// against the string a site passes.
|
||||
enum class MGFatalFamily : ::std::uint32_t {
|
||||
#define X(Family, WireCode, Why) Family,
|
||||
MGL_FATAL_FAMILY_LIST(X)
|
||||
#undef X
|
||||
};
|
||||
using ::MobileGL::MG_Pipe::FatalFamilyName;
|
||||
using ::MobileGL::MG_Pipe::MGFatalFamily;
|
||||
using ::MobileGL::MG_Pipe::MGFatalFamilyCount;
|
||||
|
||||
// THE PROJECTION, AS A TOTAL TABLE. Not a switch with a default arm: this build has no
|
||||
// -Werror, so a default would silently swallow a family added without a code. Every family
|
||||
@@ -43,26 +41,4 @@ namespace MobileGL::MG_Remote {
|
||||
return ::MobileGL::Wire::FatalCode::ProtocolCorruption;
|
||||
}
|
||||
|
||||
// The family's own word, byte-for-byte what appears inside `Fatal{<name>, ...}`. A death
|
||||
// site passes both the enum and its full message string; a test asserts this name is present
|
||||
// in that string, which is what keeps the two from diverging.
|
||||
inline const char* FatalFamilyName(MGFatalFamily family) {
|
||||
switch (family) {
|
||||
#define X(Family, WireCode, Why) \
|
||||
case MGFatalFamily::Family: return #Family;
|
||||
MGL_FATAL_FAMILY_LIST(X)
|
||||
#undef X
|
||||
}
|
||||
return "<unknown>";
|
||||
}
|
||||
|
||||
// The count, for a test that walks every family.
|
||||
inline constexpr ::std::size_t MGFatalFamilyCount() {
|
||||
::std::size_t n = 0;
|
||||
#define X(Family, WireCode, Why) ++n;
|
||||
MGL_FATAL_FAMILY_LIST(X)
|
||||
#undef X
|
||||
return n;
|
||||
}
|
||||
|
||||
} // namespace MobileGL::MG_Remote
|
||||
|
||||
@@ -307,4 +307,23 @@ namespace MobileGL::MG_Remote {
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// P13 W5: THE RECORD ARM'S DEATHS GO THROUGH THIS FUNNEL WHEREVER MG_Remote IS LINKED.
|
||||
// Registered at static init rather than at role init: both roles, and unit cases that never
|
||||
// run one, call into the record arm, and each of its deaths must count, publish and latch
|
||||
// exactly as the direct SessionFail / SessionLatch call it replaced did. The line arrives
|
||||
// formatted, so it is passed through "%s" - the same bytes reach the log and the frame.
|
||||
namespace {
|
||||
[[noreturn]] void RecordFailThroughFunnel(MGFatalFamily family, const char* line) {
|
||||
SessionFail(family, "%s", line);
|
||||
}
|
||||
bool RecordLatchThroughFunnel(MGFatalFamily family, const char* line) {
|
||||
return SessionLatch(family, "%s", line);
|
||||
}
|
||||
[[maybe_unused]] const bool g_recordFailHooksRegistered = [] {
|
||||
MG_Pipe::MGPipeInstallRecordFailHooks(&RecordFailThroughFunnel, &RecordLatchThroughFunnel,
|
||||
&SessionLatched);
|
||||
return true;
|
||||
}();
|
||||
} // namespace
|
||||
|
||||
} // namespace MobileGL::MG_Remote
|
||||
|
||||
@@ -24,6 +24,12 @@ if (MSVC)
|
||||
target_compile_options(PipeCatalogueTest PRIVATE /Zc:preprocessor)
|
||||
endif()
|
||||
|
||||
# P13 W5: the record arm's fail / latch seam, in both library shapes (with and without MG_Remote).
|
||||
add_executable(RecordFailSeamTest RecordFailSeamTest.cpp)
|
||||
target_include_directories(RecordFailSeamTest PRIVATE ${MGL_ROOT}/include ${MGL_ROOT}/MobileGL)
|
||||
target_link_libraries(RecordFailSeamTest PRIVATE GTest::gtest_main ${LINK_LIBRARIES})
|
||||
gtest_discover_tests(RecordFailSeamTest DISCOVERY_TIMEOUT 30 PROPERTIES LABELS unit)
|
||||
|
||||
# P7 B4 aggregate-wait regression control shares the production selector; no device is needed.
|
||||
add_executable(MagmaAggregateWaitTest MagmaAggregateWaitTest.cpp)
|
||||
target_include_directories(MagmaAggregateWaitTest PRIVATE ${MGL_ROOT}/include ${MGL_ROOT}/MobileGL)
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
// MobileGL - MobileGL/MG_Test/Pipe/RecordFailSeamTest.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
|
||||
|
||||
// P13 W5: THE RECORD ARM'S FAIL / LATCH SEAM (MG_Pipe/PipeSessionFail.h), in both library shapes.
|
||||
// Without MG_Remote the defaults are the monolith answer - the line on stderr, then the abort; with
|
||||
// it, FatalFunnel.cpp's static registration is in place before any case runs, so the record arm's
|
||||
// deaths count and publish through SessionFail exactly as a direct call did.
|
||||
|
||||
#include <MG_Pipe/PipeFatalFamily.h>
|
||||
#include <MG_Pipe/PipeSessionFail.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
using namespace MobileGL;
|
||||
using MG_Pipe::MGFatalFamily;
|
||||
|
||||
TEST(RecordFailSeam, TheVocabularyIsTheDefFilesWords) {
|
||||
EXPECT_STREQ(MG_Pipe::FatalFamilyName(MGFatalFamily::ProtocolCorruption), "ProtocolCorruption");
|
||||
EXPECT_STREQ(MG_Pipe::FatalFamilyName(MGFatalFamily::BackendDeviceLost), "BackendDeviceLost");
|
||||
EXPECT_GT(MG_Pipe::MGFatalFamilyCount(), 10u);
|
||||
}
|
||||
|
||||
TEST(RecordFailSeam, TheFunnelIsRegisteredWhereverMgRemoteIsLinked) {
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
EXPECT_NE(MG_Pipe::MGPipeRecordFailHookInstalled(), nullptr)
|
||||
<< "FatalFunnel.cpp's static registration did not run: the record arm's deaths would skip "
|
||||
"SessionFail's count and SessionFault frame";
|
||||
EXPECT_NE(MG_Pipe::MGPipeRecordLatchHookInstalled(), nullptr);
|
||||
EXPECT_NE(MG_Pipe::MGPipeRecordLatchedHookInstalled(), nullptr);
|
||||
#else
|
||||
EXPECT_EQ(MG_Pipe::MGPipeRecordFailHookInstalled(), nullptr) << "a library without MG_Remote has no funnel";
|
||||
EXPECT_EQ(MG_Pipe::MGPipeRecordLatchHookInstalled(), nullptr);
|
||||
EXPECT_EQ(MG_Pipe::MGPipeRecordLatchedHookInstalled(), nullptr);
|
||||
#endif
|
||||
EXPECT_FALSE(MG_Pipe::MGPipeRecordLatched()) << "nothing latched in a process with no session";
|
||||
}
|
||||
|
||||
TEST(RecordFailSeamDeathTest, AFailWritesTheCallersLineAndDies) {
|
||||
EXPECT_DEATH(MG_Pipe::MGPipeRecordFail(MGFatalFamily::ProtocolCorruption,
|
||||
"MGPipe: Fatal{ProtocolCorruption, \"record-seam-unit\"} n=%d", 7),
|
||||
"Fatal\\{ProtocolCorruption, \"record-seam-unit\"\\} n=7");
|
||||
}
|
||||
|
||||
TEST(RecordFailSeamDeathTest, ALatchWithNoSessionToLatchDiesTheSameWay) {
|
||||
EXPECT_DEATH((void)MG_Pipe::MGPipeRecordLatch(MGFatalFamily::BackendDeviceLost,
|
||||
"MGPipe: Fatal{BackendDeviceLost, \"record-seam-unit\"} n=%d", 9),
|
||||
"Fatal\\{BackendDeviceLost, \"record-seam-unit\"\\} n=9");
|
||||
}
|
||||
|
||||
namespace {
|
||||
MGFatalFamily g_seenFamily{};
|
||||
std::string g_seenLine;
|
||||
bool CaptureLatch(MGFatalFamily family, const char* line) {
|
||||
g_seenFamily = family;
|
||||
g_seenLine = line;
|
||||
return false;
|
||||
}
|
||||
bool AlwaysLatched() { return true; }
|
||||
} // namespace
|
||||
|
||||
// An installed latch hook gets the family and the FORMATTED line, and its answer is the call's.
|
||||
TEST(RecordFailSeam, AnInstalledLatchHookGetsTheFormattedLine) {
|
||||
const auto fail = MG_Pipe::MGPipeRecordFailHookInstalled();
|
||||
const auto latch = MG_Pipe::MGPipeRecordLatchHookInstalled();
|
||||
const auto latched = MG_Pipe::MGPipeRecordLatchedHookInstalled();
|
||||
MG_Pipe::MGPipeInstallRecordFailHooks(fail, &CaptureLatch, &AlwaysLatched);
|
||||
const bool answer = MG_Pipe::MGPipeRecordLatch(MGFatalFamily::BackendDeviceLost,
|
||||
"MGPipe: Fatal{BackendDeviceLost, \"captured\"} k=%u", 3u);
|
||||
const bool nowLatched = MG_Pipe::MGPipeRecordLatched();
|
||||
MG_Pipe::MGPipeInstallRecordFailHooks(fail, latch, latched);
|
||||
EXPECT_FALSE(answer);
|
||||
EXPECT_TRUE(nowLatched);
|
||||
EXPECT_EQ(g_seenFamily, MGFatalFamily::BackendDeviceLost);
|
||||
EXPECT_EQ(g_seenLine, "MGPipe: Fatal{BackendDeviceLost, \"captured\"} k=3");
|
||||
EXPECT_EQ(MG_Pipe::MGPipeRecordLatchHookInstalled(), latch) << "the case did not restore the hooks";
|
||||
}
|
||||
@@ -110,7 +110,8 @@ EXCLUDED_PARTS = ("MG_Test", "MG_Benchmark", "MG_IntegrationTest")
|
||||
SOURCE_SUFFIXES = (".cpp", ".h", ".inc")
|
||||
|
||||
BASELINE = Path(__file__).with_name("fatal_census_baseline.json")
|
||||
FAMILIES_DEF = ROOT / "MobileGL" / "MG_Remote" / "FatalFamilies.def"
|
||||
# P13 W5: the vocabulary moved to MG_Pipe so the record arm can name its deaths without MG_Remote.
|
||||
FAMILIES_DEF = ROOT / "MobileGL" / "MG_Pipe" / "FatalFamilies.def"
|
||||
PROTOCOL_FBS = ROOT / "MobileGL" / "MG_Remote" / "Protocol" / "protocol.fbs"
|
||||
|
||||
# The funnel's own files. WireLog.cpp's abort is reached only through WireLogFatal, and rule 2
|
||||
@@ -125,6 +126,9 @@ FUNNEL_FILES = {
|
||||
# call, so it is exempt from both rules for the same reason WireLog is.
|
||||
"MobileGL/MG_Remote/FatalFunnel.cpp",
|
||||
"MobileGL/MG_Remote/FatalFunnel.h",
|
||||
# P13 W5: the seam header declares MGPipeRecordFail / MGPipeRecordLatch; it has no abort and no
|
||||
# call, and its declarations would otherwise read as calls with no family word.
|
||||
"MobileGL/MG_Pipe/PipeSessionFail.h",
|
||||
}
|
||||
|
||||
# THE ALLOW-LIST FOR FUNNELS THAT DO NOT GET A WHOLE FILE TO THEMSELVES (P7 wave 0). An unmarked
|
||||
@@ -141,6 +145,10 @@ FUNNEL_SITES = {
|
||||
"the no-hook default of the backend session-fail seam (MG_Pipe/PipeSessionFail.h): the "
|
||||
"line it logs is the CALLER's, family word and all, and with MG_Remote's hook installed "
|
||||
"this abort is never reached at all"),
|
||||
("[[noreturn]] void RecordDeath(",
|
||||
"P13 W5: the no-hook default of the record arm's fail seam (MGPipeRecordFail / "
|
||||
"MGPipeRecordLatch): the line is the CALLER's, family word and all, and wherever MG_Remote "
|
||||
"is linked FatalFunnel.cpp's static registration sends it through SessionFail instead"),
|
||||
),
|
||||
"MobileGL/MG_Pipe/generated/PipeWire.inc": (
|
||||
("MGPipeWireProtocolFatal",
|
||||
@@ -180,6 +188,10 @@ SESSION_FAIL_CALL = re.compile(r"(?<![A-Za-z0-9_])SessionFail\s*\(")
|
||||
# word to FatalFamilies.def. Without this, converting a site from SessionFail to SessionLatch
|
||||
# would quietly take it out of the census.
|
||||
SESSION_LATCH_CALL = re.compile(r"(?<![A-Za-z0-9_])SessionLatch\s*\(")
|
||||
# P13 W5: the record arm's twins (MG_Pipe/PipeSessionFail.h), which reach SessionFail / SessionLatch
|
||||
# through FatalFunnel.cpp's registration and die alone without it - held to the same rule. A
|
||||
# definition (`void MGPipeRecordFail(` / `bool MGPipeRecordLatch(`) is not a call.
|
||||
RECORD_FAIL_CALL = re.compile(r"(?<![A-Za-z0-9_])(?<!void )(?<!bool )MGPipeRecord(?:Fail|Latch)\s*\(")
|
||||
FAMILY_ROW = re.compile(r"^\s*X\(([A-Za-z][A-Za-z0-9]*)\s*,", re.MULTILINE)
|
||||
REFUSE_ENUM = re.compile(r"enum\s+RefuseCode\s*:[^{]*\{(.*?)\}", re.DOTALL)
|
||||
ENUM_VALUE = re.compile(r"^\s*([A-Za-z][A-Za-z0-9]*)\s*=", re.MULTILINE)
|
||||
@@ -310,7 +322,7 @@ def unnamed_funnel_call_lines(lines):
|
||||
found = []
|
||||
for index, line in enumerate(lines):
|
||||
if not (WIRE_LOG_FATAL_CALL.search(line) or SESSION_FAIL_CALL.search(line) or
|
||||
SESSION_LATCH_CALL.search(line)):
|
||||
SESSION_LATCH_CALL.search(line) or RECORD_FAIL_CALL.search(line)):
|
||||
continue
|
||||
window = "\n".join(lines[index:index + kMarkerWindow])
|
||||
if not MARKER.search(window):
|
||||
@@ -331,6 +343,11 @@ SELF_TEST_CASES = (
|
||||
('WireLogFatal("MGPipe: no family word");', 1),
|
||||
('MGPipeSessionLatch(family, format);', 0),
|
||||
('MGPipeSessionFail(family, format);', 0),
|
||||
('MGPipeRecordFail(MGFatalFamily::ProtocolCorruption, "MGPipe: no family word");', 1),
|
||||
('MGPipeRecordLatch(MGFatalFamily::ProtocolCorruption, "MGPipe: no family word %d", x);', 1),
|
||||
('MGPipeRecordFail(MGFatalFamily::ProtocolCorruption, "MGPipe: Fatal{ProtocolCorruption, \\"w\\"}");', 0),
|
||||
('void MGPipeRecordFail(MGFatalFamily family, const char* fmt, ...) {', 0),
|
||||
('bool MGPipeRecordLatch(MGFatalFamily family, const char* fmt, ...) {', 0),
|
||||
)
|
||||
|
||||
|
||||
@@ -485,7 +502,7 @@ def main():
|
||||
rowless = sorted(set(result["families"]) - declared_families())
|
||||
if rowless:
|
||||
failures.append(
|
||||
"family word(s) with no row in MG_Remote/FatalFamilies.def: " + ", ".join(rowless) +
|
||||
"family word(s) with no row in MG_Pipe/FatalFamilies.def: " + ", ".join(rowless) +
|
||||
". A row is the family's projection onto the seven-value wire FatalCode (5.2's D2 "
|
||||
"ruling); a word with no row tells the peer nothing, and FatalCodeForFamily cannot "
|
||||
"compile a call that names it.")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"abort_sites": 75,
|
||||
"abort_sites": 76,
|
||||
"abort_sites_by_file": {
|
||||
"MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp": 12,
|
||||
"MobileGL/MG_Backend/DirectGLES/Managers.cpp": 12,
|
||||
@@ -13,7 +13,7 @@
|
||||
"MobileGL/MG_Impl/Pipe/PipeFill.cpp": 5,
|
||||
"MobileGL/MG_Impl/Pipe/ResourceTracker.h": 5,
|
||||
"MobileGL/MG_Impl/Pipe/SlotAllocator.cpp": 2,
|
||||
"MobileGL/MG_Pipe/PipeApply.cpp": 4,
|
||||
"MobileGL/MG_Pipe/PipeApply.cpp": 5,
|
||||
"MobileGL/MG_Pipe/PipeRoute.cpp": 7,
|
||||
"MobileGL/MG_Pipe/generated/PipeFilled.inc": 1,
|
||||
"MobileGL/MG_Pipe/generated/PipeWire.inc": 1,
|
||||
|
||||
Reference in New Issue
Block a user