[MG_Remote, MG_Test] (Disaggregated): P5f fv - reserve the reverse channel for one accepting session

This commit is contained in:
2026-09-19 23:52:12 -04:00
parent 626d773ba3
commit d0e54d1b90
2 changed files with 45 additions and 8 deletions
+31 -8
View File
@@ -19,6 +19,7 @@
#include <MG_Pipe/MGPipeCallbacks.h>
#include <MG_Util/Debug/Log.h>
#include <atomic>
#include <cstdlib>
#include <cstring>
#include <vector>
@@ -357,7 +358,11 @@ namespace MobileGL::MG_Remote::Server {
entry = producer;
}
ServerSession* g_active = nullptr;
std::atomic<ServerSession*> g_active{nullptr};
// One callback table and one process segment resolver: an in-progress Accept
// reserves their owner too. CAS closes the race between distinct session objects
// without making concurrent sessions a supported mode.
std::atomic<ServerSession*> g_sessionOwner{nullptr};
} // namespace
@@ -369,7 +374,7 @@ namespace MobileGL::MG_Remote::Server {
return *instance;
}
ServerSession* ServerSession::Active() { return g_active; }
ServerSession* ServerSession::Active() { return g_active.load(std::memory_order_acquire); }
ServerSession::~ServerSession() { Close(); }
@@ -407,9 +412,24 @@ namespace MobileGL::MG_Remote::Server {
Bool ServerSession::Accepted() const { return m_accepted; }
MobileGLResult ServerSession::Accept(Transport::ITransport& transport) {
if (m_accepted) {
return MOBILEGL_ERR_INVALID_ARGUMENT;
ServerSession* expectedOwner = nullptr;
if (!g_sessionOwner.compare_exchange_strong(expectedOwner, this,
std::memory_order_acq_rel, std::memory_order_acquire)) {
if (expectedOwner == this) return MOBILEGL_ERR_INVALID_ARGUMENT;
MGLOG_F("MGPipe: Fatal{RoleViolation, \"callback-double-install\"} - another "
"ServerSession already owns or is accepting the process reverse channel");
std::abort();
}
struct ReleaseFailedClaim {
ServerSession* self;
~ReleaseFailedClaim() {
if (!self->Accepted()) {
ServerSession* expected = self;
g_sessionOwner.compare_exchange_strong(expected, nullptr,
std::memory_order_release, std::memory_order_relaxed);
}
}
} releaseOnFailure{this};
m_transport = &transport;
// MOBILEGL_IPC_RING_MB / _STAGE_MB unless SetSegmentSizes overrode them. Unconditional
// on purpose - see SizesFromConfig.
@@ -538,7 +558,6 @@ namespace MobileGL::MG_Remote::Server {
m_segments.InstallProcessResolver();
m_accepted = true;
g_active = this;
// ---- P5c ev: the four reverse-channel producers are THIS session's (CONTRACT-P5C
// §4.1), installed before the apply thread can apply a record that produces one and
@@ -552,6 +571,7 @@ namespace MobileGL::MG_Remote::Server {
InstallReverseCallback(MG_Pipe::gMGPipeCallbacks.OnGpuWritten, &ServerOnGpuWritten);
InstallReverseCallback(MG_Pipe::gMGPipeCallbacks.OnSurfaceChanged,
&ServerOnSurfaceChanged);
g_active.store(this, std::memory_order_release);
LogMemory("accept");
@@ -624,9 +644,9 @@ namespace MobileGL::MG_Remote::Server {
}
void ServerSession::Close() {
if (g_active == this) {
g_active = nullptr;
}
ServerSession* expectedActive = this;
g_active.compare_exchange_strong(expectedActive, nullptr,
std::memory_order_acq_rel, std::memory_order_acquire);
if (m_accepted) {
// Uninstall AFTER the apply thread has joined, never before: a record still in
// flight can still resolve a segment offset (table 3's fourth column).
@@ -653,6 +673,9 @@ namespace MobileGL::MG_Remote::Server {
m_shm.Close();
m_transport = nullptr;
m_accepted = false;
ServerSession* expectedOwner = this;
g_sessionOwner.compare_exchange_strong(expectedOwner, nullptr,
std::memory_order_release, std::memory_order_relaxed);
}
Transport::RingConsumer& ServerSession::CommandRing() { return m_commands; }
+14
View File
@@ -2375,6 +2375,20 @@ TEST(P5fReverseChannel, GlErrorCallbackRejectsDoubleInstallation) {
EXPECT_NE(ReadLog().find("callback-double-install"), std::string::npos);
}
TEST(P5fReverseChannel, ASecondSessionCannotClaimTheSameReverseChannel) {
EXPECT_EXIT({
FvSession owner;
if (!owner.Handshake()) std::_Exit(7);
std::unique_ptr<Transport::InProcessTransport> client, server;
Transport::InProcessTransport::CreatePair(client, server);
Server::ServerSession other;
// The owner refusal precedes receiving a Hello or replacing the segment resolver.
(void)other.Accept(*server);
std::_Exit(9);
}, ::testing::KilledBySignal(SIGABRT), "");
EXPECT_NE(ReadLog().find("another ServerSession already owns"), std::string::npos);
}
TEST(P5fReverseChannel, RecordErrorWithoutCallbackIsNamedFatal) {
EXPECT_EXIT({
MG_Config::Ipc.StrictErrors = true;