mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 01:53:24 +09:00
[Feat] (MG_Remote, P11 B2): T0 is the default - an unset MOBILEGL_IPC_ADOPT_TIER asks T0 (ask 0x80) and falls back to T2 quietly (MGLOG_D, still counted: client T0Fallbacks, server T0Refusals), while an explicit 0 keeps every named line; revision 5's schema comment and pin fixed up
This commit is contained in:
+10
-7
@@ -500,6 +500,9 @@ namespace MobileGL::MG_Config {
|
||||
Offscreen = 0, // a window surface is the client's own window, as before (the default)
|
||||
Server = 1, // a window surface is the SERVER's window: WindowKind::ServerOwned
|
||||
};
|
||||
// IpcTable::AdoptTier when MOBILEGL_IPC_ADOPT_TIER is unset (or unparseable): T0 by default,
|
||||
// with QUIET fallbacks. Not a tier a user can type - the knob admits 0..2.
|
||||
inline constexpr Uint32 kAdoptTierUnset = 3;
|
||||
struct IpcTable {
|
||||
// MOBILEGL_IPC_SERVER_PATH: where to find libMobileGLServer. P6 consumes it; P5
|
||||
// lands the parse because t1's ctest ENVIRONMENT blocks and add_trace_replay_test's
|
||||
@@ -626,13 +629,13 @@ namespace MobileGL::MG_Config {
|
||||
// arm and the red-once of the no-reply gate (FencePollScenario).
|
||||
Uint32 PollEscalate = 64;
|
||||
// MOBILEGL_IPC_ADOPT_TIER, THE ZERO-COPY SWITCH (ruling ID-P11-14, CONTRACT-P11 B2):
|
||||
// 2 = emulate (T2: the client keeps the shadow and pushes), the default and today's
|
||||
// behaviour byte for byte; 0 = T0 (the client allocates each adopted store as an
|
||||
// AHardwareBuffer and the server imports it); 1 = T1, closed - refused by name, then T2.
|
||||
// A T0 this session cannot use (a stream plane, the server's allow switch, no
|
||||
// AHardwareBuffer, a failed server POST) is T2 plus one named line, never a Fatal
|
||||
// (MG_Remote/Transport/AdoptTier.h).
|
||||
Uint32 AdoptTier = 2;
|
||||
// UNSET (kAdoptTierUnset, the default since 2026-09-29, the user's decision) = T0 where the
|
||||
// session can run it, T2 QUIETLY where it cannot (MGLOG_D only, still counted);
|
||||
// 0 = T0 asked by name - a T0 this session cannot use (a stream plane, the server's allow
|
||||
// switch, no AHardwareBuffer, a failed server POST) is T2 plus one named line;
|
||||
// 1 = T1, closed - refused by name, then T2; 2 = emulate (T2: the client keeps the shadow
|
||||
// and pushes). Never a Fatal (MG_Remote/Transport/AdoptTier.h).
|
||||
Uint32 AdoptTier = kAdoptTierUnset;
|
||||
// MOBILEGL_IPC_ALLOW_ADOPT_T0 (server): 1 (default) = grant a client's T0 ask when this
|
||||
// platform and the backend's POST self-test allow it; 0 = never grant it (the session
|
||||
// runs T2 and says so). Read by the server role only; kept through ServerSpawn.
|
||||
|
||||
@@ -433,9 +433,10 @@ namespace MobileGL::MG_ConfigLoader {
|
||||
// torn read rather than a divergence. The batch is therefore off whenever the
|
||||
// shadow comparer is armed.
|
||||
if (MG_Config::Features.PipeVerify) ipc.BatchWaits = 0;
|
||||
// 2 (T2) is the default; 0 asks for T0 and 1 is refused by name - both settled at the
|
||||
// handshake from the data plane (P11 A1/B2, MG_Remote/Transport/AdoptTier.h).
|
||||
ipc.AdoptTier = QueryEnvUint32("MOBILEGL_IPC_ADOPT_TIER", 2, 0, 2);
|
||||
// UNSET is T0 with quiet fallbacks (the default since 2026-09-29); 0 asks for T0 by name, 1 is
|
||||
// refused by name, 2 is T2 - settled at the handshake from the data plane (P11 A1/B2,
|
||||
// MG_Remote/Transport/AdoptTier.h). An unparseable value is warned about and reads as unset.
|
||||
ipc.AdoptTier = QueryEnvUint32("MOBILEGL_IPC_ADOPT_TIER", MG_Config::kAdoptTierUnset, 0, 2);
|
||||
// P11 B2: the server's own T0 allow switch (Config.h).
|
||||
ipc.AllowAdoptT0 = QueryEnvUint32("MOBILEGL_IPC_ALLOW_ADOPT_T0", 1, 0, 1);
|
||||
ipc.VerbBarrier = QueryEnvUint32("MOBILEGL_IPC_VERB_BARRIER", 1, 0, 1);
|
||||
@@ -532,10 +533,11 @@ namespace MobileGL::MG_ConfigLoader {
|
||||
// log that does not name it makes every run ambiguous about its own configuration.
|
||||
MGLOG_I("Config: IPC ring=%uMiB stage=%uMiB wire-deferred=%uMiB spin=%uus event-wait=%ums "
|
||||
"persistent-block=%uKiB create-window=%u pbo-readback-sync=%u poll-escalate=%u "
|
||||
"adopt-tier=%u allow-t0=%u verb-barrier=%u run-ahead=%u present-credit=%u control-timeout=%ums "
|
||||
"adopt-tier=%s allow-t0=%u verb-barrier=%u run-ahead=%u present-credit=%u control-timeout=%ums "
|
||||
"cold-start=%ums strict=%d audit=%d role-split-state=%d affinity='%s' surface=%s",
|
||||
ipc.RingMb, ipc.StageMb, ipc.WireDeferredMb, ipc.SpinUs, ipc.EventWaitMs,
|
||||
ipc.PersistentBlockKb, ipc.CreateWindow, ipc.PboReadbackSync, ipc.PollEscalate, ipc.AdoptTier,
|
||||
ipc.PersistentBlockKb, ipc.CreateWindow, ipc.PboReadbackSync, ipc.PollEscalate,
|
||||
ipc.AdoptTier == 0 ? "0" : ipc.AdoptTier == 1 ? "1" : ipc.AdoptTier == 2 ? "2" : "unset(T0)",
|
||||
ipc.AllowAdoptT0,
|
||||
ipc.VerbBarrier, ipc.RunAhead, ipc.PresentCredit, ipc.ControlTimeoutMs, ipc.ColdStartMs,
|
||||
static_cast<int>(ipc.StrictErrors), static_cast<int>(ipc.Audit),
|
||||
|
||||
@@ -823,7 +823,10 @@ namespace MobileGL::MG_Remote::Client {
|
||||
return result;
|
||||
}
|
||||
ResetT0(false);
|
||||
m_adoptT0Asked = adoptAsk == 0;
|
||||
m_adoptT0Asked = Transport::AdoptAskIsT0(adoptAsk);
|
||||
m_adoptT0Quiet = Transport::AdoptTierIsDefault();
|
||||
if (terms->dataPlane() == ::MobileGL::Wire::DataPlane::Stream && Transport::AdoptTierWantsT0())
|
||||
m_t0Fallbacks = 1; // a stream carries T2 only (the settle said so, by name or at D)
|
||||
// The four SegmentRefs are what a spawn client MAPS (P6). Under inproc the mapping
|
||||
// already exists, so what they are good for here is the cross-check that the two
|
||||
// sides agree about the geometry at all - which is the assertion that would
|
||||
@@ -1127,7 +1130,10 @@ namespace MobileGL::MG_Remote::Client {
|
||||
return result;
|
||||
}
|
||||
ResetT0(false);
|
||||
m_adoptT0Asked = adoptAsk == 0;
|
||||
m_adoptT0Asked = Transport::AdoptAskIsT0(adoptAsk);
|
||||
m_adoptT0Quiet = Transport::AdoptTierIsDefault();
|
||||
if (stream && Transport::AdoptTierWantsT0())
|
||||
m_t0Fallbacks = 1; // a stream carries T2 only (the settle said so, by name or at D)
|
||||
if (stream) {
|
||||
// PH-7 (4). A Stream Welcome without a nonce of exactly the minted width names no
|
||||
// data connection this client could open; refused rather than guessed at.
|
||||
@@ -2728,6 +2734,13 @@ namespace MobileGL::MG_Remote::Client {
|
||||
"AHardwareBuffers the server imports");
|
||||
} else {
|
||||
m_adoptT0Decision = 0;
|
||||
++m_t0Fallbacks;
|
||||
if (m_adoptT0Quiet) {
|
||||
// T0 BY DEFAULT (knob unset) FALLS BACK QUIETLY - counted, said at MGLOG_D.
|
||||
MGLOG_D("MG_Remote client: T0 by default is not available (no kCapAdoptT0; the server's log "
|
||||
"says why at MGLOG_D); the session runs T2");
|
||||
return false;
|
||||
}
|
||||
MGLOG_W("MG_Remote client: Refuse{AdoptT0Unavailable, \"no kCapAdoptT0\"} - "
|
||||
"MOBILEGL_IPC_ADOPT_TIER=0 asked for T0 and the server did not publish kCapAdoptT0 (its "
|
||||
"log names why: its allow switch, no AHardwareBuffer, or its POST self-test); the "
|
||||
@@ -2853,21 +2866,34 @@ namespace MobileGL::MG_Remote::Client {
|
||||
}
|
||||
|
||||
void ClientSession::ResetT0(Bool releaseStores) {
|
||||
if (m_adoptT0Asked) {
|
||||
MGLOG_I("MG_Remote client: T0 session totals - %s; stores imported %llu, bytes %llu, declined %llu, "
|
||||
"released %llu, held at teardown %zu",
|
||||
m_adoptT0Decision == 1 ? "ran T0" : m_adoptT0Decision == 0 ? "fell back to T2" : "never decided",
|
||||
static_cast<unsigned long long>(m_t0Imported), static_cast<unsigned long long>(m_t0Bytes),
|
||||
static_cast<unsigned long long>(m_t0Declined), static_cast<unsigned long long>(m_t0Released),
|
||||
m_t0Stores.size());
|
||||
if (m_adoptT0Asked || m_t0Fallbacks != 0) {
|
||||
// A default (unset-knob) session that did not run T0 says its totals at MGLOG_D.
|
||||
const bool quiet = m_adoptT0Quiet && m_adoptT0Decision != 1;
|
||||
const char* ran =
|
||||
m_adoptT0Decision == 1 ? "ran T0" : m_adoptT0Decision == 0 || m_t0Fallbacks ? "fell back to T2" : "never decided";
|
||||
#define MGL_T0_CLIENT_TOTALS(LOG) \
|
||||
LOG("MG_Remote client: T0 session totals - %s%s; stores imported %llu, bytes %llu, declined %llu, " \
|
||||
"fallbacks %llu, released %llu, held at teardown %zu", \
|
||||
ran, m_adoptT0Quiet ? " (default)" : "", static_cast<unsigned long long>(m_t0Imported), \
|
||||
static_cast<unsigned long long>(m_t0Bytes), static_cast<unsigned long long>(m_t0Declined), \
|
||||
static_cast<unsigned long long>(m_t0Fallbacks), static_cast<unsigned long long>(m_t0Released), \
|
||||
m_t0Stores.size())
|
||||
if (quiet) {
|
||||
MGL_T0_CLIENT_TOTALS(MGLOG_D);
|
||||
} else {
|
||||
MGL_T0_CLIENT_TOTALS(MGLOG_I);
|
||||
}
|
||||
#undef MGL_T0_CLIENT_TOTALS
|
||||
(void)ran;
|
||||
}
|
||||
if (releaseStores) {
|
||||
for (auto& [key, store] : m_t0Stores) Transport::AdoptT0::ReleaseHeld(store);
|
||||
}
|
||||
m_t0Stores.clear();
|
||||
m_adoptT0Asked = false;
|
||||
m_adoptT0Quiet = false;
|
||||
m_adoptT0Decision = -1;
|
||||
m_t0Imported = m_t0Bytes = m_t0Declined = m_t0Released = 0;
|
||||
m_t0Imported = m_t0Bytes = m_t0Declined = m_t0Released = m_t0Fallbacks = 0;
|
||||
m_prePublish = nullptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -252,6 +252,10 @@ namespace MobileGL::MG_Remote::Client {
|
||||
Uint64 T0StoresImported() const { return m_t0Imported; }
|
||||
Uint64 T0BytesImported() const { return m_t0Bytes; }
|
||||
Uint64 T0Declined() const { return m_t0Declined; }
|
||||
// 1 when this session's knob asked for T0 (0, or unset) and it runs T2 instead: a stream
|
||||
// data plane, or no kCapAdoptT0 at the first map_persistent. Counted whether the fallback
|
||||
// was named (knob 0) or quiet (unset, the default).
|
||||
Uint64 T0Fallbacks() const { return m_t0Fallbacks; }
|
||||
// Test seam: 0 = queue each Offer before its record (the product order); > 0 = queue it
|
||||
// that many ms AFTER the record is published, from another thread; < 0 = never queue it.
|
||||
// What the host tests use to prove a late Offer still lands and a lost one is a named
|
||||
@@ -595,12 +599,14 @@ namespace MobileGL::MG_Remote::Client {
|
||||
// the counters; and the one-shot hook EmitAndWaitTails runs between EncodeRecord (the
|
||||
// seq exists) and PublishAndNotify (the record is visible) - where the Offer is queued.
|
||||
Bool m_adoptT0Asked = false;
|
||||
Bool m_adoptT0Quiet = false; // the knob is unset: fallbacks at MGLOG_D
|
||||
Int32 m_adoptT0Decision = -1;
|
||||
std::unordered_map<Uint64, Transport::AdoptT0::HeldStore> m_t0Stores;
|
||||
Uint64 m_t0Imported = 0;
|
||||
Uint64 m_t0Bytes = 0;
|
||||
Uint64 m_t0Declined = 0;
|
||||
Uint64 m_t0Released = 0;
|
||||
Uint64 m_t0Fallbacks = 0;
|
||||
std::function<void(Uint64)> m_prePublish;
|
||||
void ResetT0(Bool releaseStores);
|
||||
};
|
||||
|
||||
@@ -1247,6 +1247,10 @@ namespace MobileGL::MG_Remote::Client {
|
||||
Bool AdoptTierIsEmulate() {
|
||||
const Uint32 tier = MG_Config::Ipc.AdoptTier;
|
||||
if (tier == 2) return true;
|
||||
// P11 B2: UNSET (T0 by default) reaching the T2 path - settled or not - is T2, quietly: a
|
||||
// session-free caller (a unit case, a harness) runs the P5 default it always ran, and a
|
||||
// settled session already counted its fallback at the handshake or its first map_persistent.
|
||||
if (tier == MG_Config::kAdoptTierUnset) return true;
|
||||
// P11 A1 (CONTRACT-P11 §1): THE VERDICT IS THE HANDSHAKE'S, NOT THIS CALL'S. Both roles
|
||||
// settle the tier from the knob and the data plane before the first record
|
||||
// (Transport/AdoptTier.cpp): a stream refuses T0/T1 by name and runs T2, a client over
|
||||
|
||||
@@ -71,8 +71,9 @@ table LinkTerms {
|
||||
eventWindowBytes: ulong;
|
||||
// P11 B2 (MG_Remote/CONTRACT-P11.md B2), appended. In the Hello: the persistent-map adoption
|
||||
// tier the client ASKS for - 0 = T0 (it allocates each adopted store as an AHardwareBuffer and
|
||||
// hands it over the aux socket), 2 = T2 (emulate: shadow + push). 1 (T1) is closed and never
|
||||
// sent; a stream plane always asks 2. In the Welcome: the server's echo of the ask it
|
||||
// hands it over the aux socket), 0x80 = T0 by DEFAULT (the client's knob is unset: the same T0,
|
||||
// but the server names a refusal only at debug level), 2 = T2 (emulate: shadow + push). 1 (T1)
|
||||
// is closed and never sent; a stream plane always asks 2. In the Welcome: the server's echo of the ask it
|
||||
// recorded. It is not the tier: T0 needs the server's POST self-test, which runs at the first
|
||||
// native bind (the GPU context does not exist yet), and is published as kCapAdoptT0 in the
|
||||
// CapsSnapshot that bind republishes. Absent (an older peer) reads 2.
|
||||
|
||||
@@ -686,16 +686,20 @@ namespace MobileGL::MG_Remote::Server {
|
||||
// for, before a byte of Welcome. A stream refuses T0/T1 by name and serves T2; over
|
||||
// shared segments the client settles it (Transport/AdoptTier.h). 0/1 never die here.
|
||||
(void)Transport::SettleAdoptTierAtHandshake(stream, Transport::AdoptTierSide::Server);
|
||||
// ---- P11 B2: the client's ask (LinkTerms.adoptTier). 2 or, over shared segments, 0;
|
||||
// anything else is not an ask this revision knows. Recorded, echoed in the Welcome, and
|
||||
// granted or refused by name at the first native bind (SettleAdoptT0AtBind).
|
||||
if (terms->adoptTier() != 2 && !(terms->adoptTier() == 0 && !stream))
|
||||
// ---- P11 B2: the client's ask (LinkTerms.adoptTier). 2 or, over shared segments, 0 (T0
|
||||
// by name) or kAdoptAskT0Default (T0 by default: refusals quiet); anything else is not an
|
||||
// ask this revision knows. Recorded, echoed in the Welcome, and granted or refused at the
|
||||
// first native bind (SettleAdoptT0AtBind).
|
||||
if (terms->adoptTier() != 2 && !(Transport::AdoptAskIsT0(terms->adoptTier()) && !stream))
|
||||
return RefuseHandshake(transport, ::MobileGL::Wire::RefuseCode::LinkTerms,
|
||||
"adoptTier is neither 2 nor, over shared segments, 0", 2, terms->adoptTier());
|
||||
m_adoptT0Asked = terms->adoptTier() == 0;
|
||||
"adoptTier is neither 2 nor, over shared segments, a T0 ask (0 or 0x80)", 2,
|
||||
terms->adoptTier());
|
||||
m_adoptAsk = terms->adoptTier();
|
||||
m_adoptT0Asked = Transport::AdoptAskIsT0(m_adoptAsk);
|
||||
m_adoptT0Quiet = m_adoptAsk == Transport::kAdoptAskT0Default;
|
||||
m_adoptT0Settled = false;
|
||||
m_adoptT0 = false;
|
||||
m_t0Stores = m_t0Bytes = m_t0Declined = 0;
|
||||
m_t0Stores = m_t0Bytes = m_t0Declined = m_t0Refusals = 0;
|
||||
m_adoptInbox.Clear();
|
||||
m_adoptInbox.Attach(&transport);
|
||||
|
||||
@@ -794,7 +798,7 @@ namespace MobileGL::MG_Remote::Server {
|
||||
}
|
||||
auto negotiated = ::MobileGL::Wire::CreateLinkTerms(builder, terms->dataPlane(),
|
||||
::MobileGL::Wire::WireForm::StructImage, maxReply, cmdWindow, stageWindow, eventWindow,
|
||||
static_cast<Uint8>(m_adoptT0Asked ? 0 : 2));
|
||||
static_cast<Uint8>(m_adoptT0Asked ? m_adoptAsk : 2));
|
||||
auto welcome = ::MobileGL::Wire::CreateWelcome(
|
||||
builder, MOBILEGL_PROTOCOL_ABI_MAJOR, MOBILEGL_PROTOCOL_ABI_MINOR,
|
||||
// CONTRACT-P6 4.3: THE SERVER'S OWN PID, not an echo of the client's.
|
||||
@@ -1030,17 +1034,29 @@ namespace MobileGL::MG_Remote::Server {
|
||||
// P11 B2: the T0 arm's proof for this session, then the inbox's leftovers (an Offer whose
|
||||
// record never came; its client has released the store on the session's end).
|
||||
if (m_accepted && m_adoptT0Asked) {
|
||||
MGLOG_I("MG_Remote server: T0 session totals - %s; stores imported %llu, bytes %llu, declined %llu, "
|
||||
"stale offers %llu, malformed %llu, unclaimed %zu",
|
||||
m_adoptT0 ? "ran T0" : m_adoptT0Settled ? "not granted (T2)" : "no native bind (T2)",
|
||||
static_cast<unsigned long long>(m_t0Stores), static_cast<unsigned long long>(m_t0Bytes),
|
||||
static_cast<unsigned long long>(m_t0Declined),
|
||||
static_cast<unsigned long long>(m_adoptInbox.StaleOffers()),
|
||||
static_cast<unsigned long long>(m_adoptInbox.MalformedOffers()), m_adoptInbox.Kept());
|
||||
// A default ask that ended on T2 says its totals at MGLOG_D, like its refusal.
|
||||
const bool quiet = m_adoptT0Quiet && !m_adoptT0;
|
||||
const char* ran = m_adoptT0 ? "ran T0" : m_adoptT0Settled ? "not granted (T2)" : "no native bind (T2)";
|
||||
#define MGL_T0_SERVER_TOTALS(LOG) \
|
||||
LOG("MG_Remote server: T0 session totals - %s%s; stores imported %llu, bytes %llu, declined %llu, " \
|
||||
"refused %llu, stale offers %llu, malformed %llu, unclaimed %zu", \
|
||||
ran, m_adoptT0Quiet ? " (default ask)" : "", static_cast<unsigned long long>(m_t0Stores), \
|
||||
static_cast<unsigned long long>(m_t0Bytes), static_cast<unsigned long long>(m_t0Declined), \
|
||||
static_cast<unsigned long long>(m_t0Refusals), \
|
||||
static_cast<unsigned long long>(m_adoptInbox.StaleOffers()), \
|
||||
static_cast<unsigned long long>(m_adoptInbox.MalformedOffers()), m_adoptInbox.Kept())
|
||||
if (quiet) {
|
||||
MGL_T0_SERVER_TOTALS(MGLOG_D);
|
||||
} else {
|
||||
MGL_T0_SERVER_TOTALS(MGLOG_I);
|
||||
}
|
||||
#undef MGL_T0_SERVER_TOTALS
|
||||
(void)ran;
|
||||
}
|
||||
m_adoptInbox.Clear();
|
||||
m_adoptInbox.Attach(nullptr);
|
||||
m_adoptT0Asked = m_adoptT0Settled = m_adoptT0 = false;
|
||||
m_adoptT0Asked = m_adoptT0Settled = m_adoptT0 = m_adoptT0Quiet = false;
|
||||
m_adoptAsk = 2;
|
||||
m_consumer.Detach();
|
||||
*m_commands = Transport::RingConsumer();
|
||||
*m_events = Transport::EventRingProducer();
|
||||
@@ -1094,19 +1110,32 @@ namespace MobileGL::MG_Remote::Server {
|
||||
post.passed = ops->SelfTestExternal(detail, sizeof(detail));
|
||||
post.detail = detail;
|
||||
post.ran = true;
|
||||
MGLOG_I("MG_Remote server: T0 POST (%s, sustained-lock pattern) %s - %s", backendName,
|
||||
post.passed ? "PASSED" : "FAILED", post.detail.c_str());
|
||||
if (m_adoptT0Quiet) {
|
||||
MGLOG_D("MG_Remote server: T0 POST (%s, sustained-lock pattern) %s - %s", backendName,
|
||||
post.passed ? "PASSED" : "FAILED", post.detail.c_str());
|
||||
} else {
|
||||
MGLOG_I("MG_Remote server: T0 POST (%s, sustained-lock pattern) %s - %s", backendName,
|
||||
post.passed ? "PASSED" : "FAILED", post.detail.c_str());
|
||||
}
|
||||
}
|
||||
if (!post.passed) why = std::string("the ") + backendName + " POST self-test failed: " + post.detail;
|
||||
}
|
||||
}
|
||||
if (!why.empty()) {
|
||||
++m_t0Refusals;
|
||||
const char* word = MG_Config::Ipc.AllowAdoptT0 == 0 ? "disallowed"
|
||||
: !Transport::AdoptT0::PlatformHasAhb() ? "no AHardwareBuffer" : "POST";
|
||||
if (m_adoptT0Quiet) {
|
||||
// THE DEFAULT ASK (MOBILEGL_IPC_ADOPT_TIER unset) FALLS BACK QUIETLY: every host
|
||||
// session would otherwise carry this line. Counted (T0Refusals, the totals line).
|
||||
MGLOG_D("MG_Remote server: T0 by default not granted (%s) - %s; the session runs T2",
|
||||
word, why.c_str());
|
||||
return;
|
||||
}
|
||||
MGLOG_W("MG_Remote server: Refuse{AdoptT0Unavailable, \"%s\"} - the client asked T0 "
|
||||
"(MOBILEGL_IPC_ADOPT_TIER=0) and %s; kCapAdoptT0 is not published and the session "
|
||||
"runs T2 (emulate)",
|
||||
MG_Config::Ipc.AllowAdoptT0 == 0 ? "disallowed"
|
||||
: !Transport::AdoptT0::PlatformHasAhb() ? "no AHardwareBuffer" : "POST",
|
||||
why.c_str());
|
||||
word, why.c_str());
|
||||
return;
|
||||
}
|
||||
m_adoptT0 = true;
|
||||
|
||||
@@ -315,6 +315,11 @@ namespace MobileGL::MG_Remote::Server {
|
||||
Uint64 T0StoresImported() const { return m_t0Stores; }
|
||||
Uint64 T0BytesImported() const { return m_t0Bytes; }
|
||||
Uint64 T0Declined() const { return m_t0Declined; }
|
||||
// 1 when this session asked T0 and was not granted it (allow switch, no AHardwareBuffer,
|
||||
// POST): counted whether the refusal was named (knob 0) or quiet (the default ask).
|
||||
Uint64 T0Refusals() const { return m_t0Refusals; }
|
||||
// The ask was the client's DEFAULT (kAdoptAskT0Default): a refusal is said at MGLOG_D.
|
||||
Bool AdoptT0Quiet() const { return m_adoptT0Quiet; }
|
||||
AdoptInbox& T0Inbox() { return m_adoptInbox; }
|
||||
|
||||
private:
|
||||
@@ -355,12 +360,15 @@ namespace MobileGL::MG_Remote::Server {
|
||||
// P11 B2 (T0). Set by Accept from the Hello, by SettleAdoptT0AtBind on the apply thread;
|
||||
// the inbox and the counters are the apply thread's.
|
||||
Bool m_adoptT0Asked = false;
|
||||
Bool m_adoptT0Quiet = false;
|
||||
Uint8 m_adoptAsk = 2;
|
||||
Bool m_adoptT0Settled = false;
|
||||
Bool m_adoptT0 = false;
|
||||
AdoptInbox m_adoptInbox;
|
||||
Uint64 m_t0Stores = 0;
|
||||
Uint64 m_t0Bytes = 0;
|
||||
Uint64 m_t0Declined = 0;
|
||||
Uint64 m_t0Refusals = 0;
|
||||
};
|
||||
|
||||
// Leak-at-exit like every other MG_Remote singleton (ID-8): no frontend destructor may
|
||||
|
||||
@@ -22,15 +22,20 @@ namespace MobileGL::MG_Remote::Transport {
|
||||
const char* SideName(AdoptTierSide side) { return side == AdoptTierSide::Client ? "client" : "server"; }
|
||||
} // namespace
|
||||
|
||||
bool AdoptTierIsDefault() { return MG_Config::Ipc.AdoptTier == MG_Config::kAdoptTierUnset; }
|
||||
|
||||
bool AdoptTierWantsT0() { return MG_Config::Ipc.AdoptTier == 0 || AdoptTierIsDefault(); }
|
||||
|
||||
std::uint32_t AdoptTierAskFor(bool streamDataPlane) {
|
||||
return (MG_Config::Ipc.AdoptTier == 0 && !streamDataPlane) ? 0u : 2u;
|
||||
if (streamDataPlane || !AdoptTierWantsT0()) return 2u;
|
||||
return AdoptTierIsDefault() ? kAdoptAskT0Default : 0u;
|
||||
}
|
||||
|
||||
std::uint32_t SettleAdoptTierAtHandshake(bool streamDataPlane, AdoptTierSide side) {
|
||||
const std::uint32_t knob = MG_Config::Ipc.AdoptTier;
|
||||
if (knob > 2) {
|
||||
// Unreachable through ConfigLoader (it admits 0..2); a direct assignment is the only
|
||||
// way here, and "T<n>" of a 7 would be a lie.
|
||||
if (knob > 2 && knob != MG_Config::kAdoptTierUnset) {
|
||||
// Unreachable through ConfigLoader (it admits 0..2 or leaves the knob unset); a direct
|
||||
// assignment is the only way here, and "T<n>" of a 7 would be a lie.
|
||||
SessionFail(MGFatalFamily::UnimplementedAdoptTier,
|
||||
"MGPipe: Fatal{UnimplementedAdoptTier, \"%u\"} - MOBILEGL_IPC_ADOPT_TIER=%u is not an "
|
||||
"adoption tier; the values are 0 (T0), 1 (closed) and 2 (emulate, the default)",
|
||||
@@ -39,9 +44,17 @@ namespace MobileGL::MG_Remote::Transport {
|
||||
g_settled.store(true, std::memory_order_release);
|
||||
if (knob == 2) return 2;
|
||||
if (streamDataPlane) {
|
||||
// A1, UNCHANGED: ONE LINE PER SESSION, on the side that holds the knob. The tcp lane's
|
||||
// server is a shared fixture that never sees the client's environment, so each side
|
||||
// says it for itself; neither side dies, because T2 is the only tier a stream carries.
|
||||
// A1, UNCHANGED FOR A NAMED KNOB: ONE LINE PER SESSION, on the side that holds the knob.
|
||||
// The tcp lane's server is a shared fixture that never sees the client's environment,
|
||||
// so each side says it for itself; neither side dies, because T2 is the only tier a
|
||||
// stream carries. AN UNSET KNOB (T0 by default) SAYS IT AT MGLOG_D: every tcp session
|
||||
// would otherwise carry the line. The client counts it (ClientSession::T0Fallbacks).
|
||||
if (AdoptTierIsDefault()) {
|
||||
MGLOG_D("MG_Remote %s: T0 by default is not available on a stream data plane (tcp): the "
|
||||
"session runs T2 (MOBILEGL_IPC_ADOPT_TIER unset; set 0 to have this named)",
|
||||
SideName(side));
|
||||
return 2;
|
||||
}
|
||||
MGLOG_W("MG_Remote %s: Refuse{AdoptTierOnStream, \"T%u\"} - MOBILEGL_IPC_ADOPT_TIER=%u names a "
|
||||
"shared-mapping adoption tier and this session's data plane is a stream (tcp): the two "
|
||||
"sides share no memory to map, so the session runs T2 (emulate: the client keeps the "
|
||||
@@ -61,10 +74,11 @@ namespace MobileGL::MG_Remote::Transport {
|
||||
"could run it); the session runs T2 (emulate). Set 0 for T0 or 2 for T2");
|
||||
return 2;
|
||||
}
|
||||
// knob 0 over shared segments: asked in the Hello. Nothing is said yet - the answer is the
|
||||
// server's, at its first native bind, and a T0 this session cannot use is named once, at
|
||||
// the first map_persistent (ClientSession::AdoptT0).
|
||||
return 0;
|
||||
// knob 0 (or unset) over shared segments: asked in the Hello. Nothing is said yet - the
|
||||
// answer is the server's, at its first native bind, and a T0 this session cannot use is
|
||||
// named once (knob 0) or said at MGLOG_D (unset), at the first map_persistent
|
||||
// (ClientSession::AdoptT0).
|
||||
return AdoptTierAskFor(false);
|
||||
}
|
||||
|
||||
bool AdoptTierSettledAtHandshake() { return g_settled.load(std::memory_order_acquire); }
|
||||
|
||||
@@ -13,9 +13,11 @@
|
||||
// and the server imports it; T1 = the server exports an opaque fd (CLOSED, ID-P11-1); T2 = the
|
||||
// resource owner declines and the client keeps the shadow and pushes.
|
||||
//
|
||||
// MOBILEGL_IPC_ADOPT_TIER IS THE SWITCH (ruling ID-P11-14): 2, the default, is today's T2 byte
|
||||
// for byte; 0 asks for T0; 1 is refused by name and runs T2. T0 that this session cannot use is
|
||||
// never a Fatal - it is T2 plus one named line:
|
||||
// MOBILEGL_IPC_ADOPT_TIER IS THE SWITCH (ruling ID-P11-14). UNSET - the default since 2026-09-29,
|
||||
// the user's decision - asks for T0 and falls back to T2 QUIETLY (MGLOG_D only, still counted),
|
||||
// so a tcp session or a host session is not one line longer; 0 asks for T0 BY NAME (the table
|
||||
// below); 1 is refused by name and runs T2; 2 is T2 byte for byte. T0 that this session cannot use
|
||||
// is never a Fatal - it is T2 plus one named line (knob 0) or one D line (unset):
|
||||
//
|
||||
// data plane side knob 0 knob 1
|
||||
// Stream (tcp) either `Refuse{AdoptTierOnStream, "T0"}`, T2 `Refuse{AdoptTierOnStream, "T1"}`, T2
|
||||
@@ -40,15 +42,28 @@ namespace MobileGL::MG_Remote::Transport {
|
||||
|
||||
enum class AdoptTierSide : std::uint8_t { Client, Server };
|
||||
|
||||
// THE HELLO'S T0 ASK WHEN THE KNOB IS UNSET (LinkTerms.adoptTier, protocol.fbs): T0 as asked
|
||||
// by 0, except that the server names a refusal only at MGLOG_D. The ask travels because only
|
||||
// the server knows why it did not grant T0 (its allow switch, its platform, its POST).
|
||||
inline constexpr std::uint32_t kAdoptAskT0Default = 0x80;
|
||||
// An ask that is a T0 ask (0 by name, kAdoptAskT0Default by default).
|
||||
inline bool AdoptAskIsT0(std::uint32_t ask) { return ask == 0 || ask == kAdoptAskT0Default; }
|
||||
// This process's knob asks for T0 (0, or unset).
|
||||
bool AdoptTierWantsT0();
|
||||
// This process's knob is unset: T0 fallbacks are quiet.
|
||||
bool AdoptTierIsDefault();
|
||||
|
||||
// The tier the client's Hello asks for (LinkTerms.adoptTier): 0 when the knob says 0 and the
|
||||
// plane it proposes is shared segments, else 2. Pure - the lines are the settle's.
|
||||
// plane it proposes is shared segments, kAdoptAskT0Default when the knob is unset on shared
|
||||
// segments, else 2. Pure - the lines are the settle's.
|
||||
std::uint32_t AdoptTierAskFor(bool streamDataPlane);
|
||||
|
||||
// Settles this side's handshake answer from MOBILEGL_IPC_ADOPT_TIER and the negotiated data
|
||||
// plane and returns the tier this side asks (client) or serves by its own knob (server): 0
|
||||
// only for a client asking T0 over shared segments, 2 otherwise. Logs at most one line per
|
||||
// call (A1's stream refusal, the T1 refusal). Never aborts for 0/1; a knob above 2 (only a
|
||||
// direct assignment can make one) is still Fatal{UnimplementedAdoptTier}.
|
||||
// plane and returns the ask this side made (client) or serves by its own knob (server):
|
||||
// AdoptTierAskFor's value for a client asking T0 over shared segments, 2 otherwise. Logs at
|
||||
// most one line per call (A1's stream refusal - at MGLOG_D when the knob is unset - and the
|
||||
// T1 refusal). Never aborts for 0/1/unset; any other value (only a direct assignment can
|
||||
// make one) is still Fatal{UnimplementedAdoptTier}.
|
||||
std::uint32_t SettleAdoptTierAtHandshake(bool streamDataPlane, AdoptTierSide side);
|
||||
|
||||
// True once a handshake in this process has settled the tier. The at-use check trusts a
|
||||
|
||||
@@ -3,5 +3,5 @@
|
||||
"2": "b30928e6fc93ddc015fd86f634a6820f775a6f2f6de5a848d273981e706b2597",
|
||||
"3": "da09f0acb48cf245703f28556ef5a38bc9e25241ebbf7b6baa9ab1765b7ddd50",
|
||||
"4": "6357c3a07ae258d2825dc42bfd610712b15a38a3beb7a96b5f56ea2988705e7f",
|
||||
"5": "f83f4c5ba6d15fac9c9f00c12b246c5f706f10c80719accd4ce116cb1a090c10"
|
||||
"5": "4632750fd68b889cb6df709df9d150f9910468c0c530399de01bef87ba793904"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user