mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 01:53:24 +09:00
[Fix] (MG_Remote): bound socket buffers in log flood tests
This commit is contained in:
@@ -663,6 +663,16 @@ int RunSession(std::unique_ptr<SocketTransport> control, std::vector<std::uint8_
|
||||
|
||||
const char* forwarding = std::getenv("MOBILEGL_IPC_LOG_FORWARD");
|
||||
if (tcp && (!forwarding || std::strcmp(forwarding, "0") != 0)) {
|
||||
// F2 fault injection: bound the kernel queue as well as the log queue so a
|
||||
// non-reading peer reliably blocks the sender, regardless of host autotuning.
|
||||
if (const char* stalled = std::getenv("MOBILEGL_TEST_LOG_SMALL_SNDBUF");
|
||||
stalled && std::strcmp(stalled, "1") == 0) {
|
||||
const int bytes = 16 * 1024;
|
||||
if (::setsockopt(control->StreamFd(), SOL_SOCKET, SO_SNDBUF, &bytes, sizeof(bytes)) != 0) {
|
||||
WireLogError("MG_Remote server: could not set F2 control send buffer");
|
||||
return endSession(70);
|
||||
}
|
||||
}
|
||||
// P9 W3: the forward is a queue with a sender thread of its own, graded by severity
|
||||
// (LogForward.h): a client that stops reading control no longer holds any logging thread -
|
||||
// the apply thread above all - inside a socket write.
|
||||
|
||||
@@ -141,7 +141,7 @@ namespace {
|
||||
// F2 (P9 W3). The flood: kFloodRecords records published while the peer reads nothing, each of
|
||||
// which makes the server's apply thread log kFloodWarnLinesPerRecord WARN lines of ~650 bytes and
|
||||
// one ERROR line (ServerLoop.cpp, MOBILEGL_TEST_APPLY_LOG_FLOOD) - about 16 MiB, against a
|
||||
// server send buffer this host caps at 4 MiB and a forward queue of 1 MiB for <= WARN.
|
||||
// deliberately small server send buffer and a forward queue of 1 MiB for <= WARN.
|
||||
constexpr std::uint32_t kFloodWarnLinesPerRecord = 64;
|
||||
constexpr std::uint32_t kFloodRecords = 400;
|
||||
// THE PEER'S RECEIVE BUFFER WHILE IT IS NOT READING. Without this the kernel absorbs the flood
|
||||
@@ -225,7 +225,10 @@ namespace {
|
||||
env.emplace_back("MOBILEGL_IPC_ROLE=server");
|
||||
env.emplace_back("MOBILEGL_IPC_DIAL=no");
|
||||
env.emplace_back(forwardLog ? "MOBILEGL_IPC_LOG_FORWARD=1" : "MOBILEGL_IPC_LOG_FORWARD=0");
|
||||
if (floodLines != 0) env.emplace_back("MOBILEGL_TEST_APPLY_LOG_FLOOD=" + std::to_string(floodLines));
|
||||
if (floodLines != 0) {
|
||||
env.emplace_back("MOBILEGL_TEST_APPLY_LOG_FLOOD=" + std::to_string(floodLines));
|
||||
env.emplace_back("MOBILEGL_TEST_LOG_SMALL_SNDBUF=1");
|
||||
}
|
||||
env.emplace_back(WaitKnobEntry(waitMs));
|
||||
env.emplace_back("MOBILEGL_LOG_FILE_PATH=" + logBase);
|
||||
const std::string image = ServerImage();
|
||||
@@ -358,6 +361,7 @@ namespace {
|
||||
// F2 (P9 W3).
|
||||
kNoControlReader = 22,
|
||||
kFloodPublish = 23,
|
||||
kControlBuffer = 24,
|
||||
};
|
||||
|
||||
// A pbuffer context on the server's apply thread, through the same forwarders
|
||||
@@ -381,11 +385,19 @@ namespace {
|
||||
// kFloodRecords set_patch_state records are published without waiting. set_patch_state because it
|
||||
// is pure applier state: no GL call, no reply, no event, so the only thing each one produces on
|
||||
// the server is the flood's log lines.
|
||||
int StopReadingControlAndFlood(Client::ClientSession& client) {
|
||||
int StopReadingControlAndFlood(Client::ClientSession& client, int& originalReceiveBuffer) {
|
||||
auto* control = client.ControlSocketForTest();
|
||||
if (control == nullptr) return kNoControlReader;
|
||||
socklen_t size = sizeof(originalReceiveBuffer);
|
||||
if (::getsockopt(control->StreamFd(), SOL_SOCKET, SO_RCVBUF, &originalReceiveBuffer, &size) != 0)
|
||||
return kControlBuffer;
|
||||
#if defined(__linux__)
|
||||
// Linux reports twice the SO_RCVBUF request, including bookkeeping space.
|
||||
originalReceiveBuffer /= 2;
|
||||
#endif
|
||||
const int receiveBuffer = kStalledReceiveBufferBytes;
|
||||
(void)::setsockopt(control->StreamFd(), SOL_SOCKET, SO_RCVBUF, &receiveBuffer, sizeof(receiveBuffer));
|
||||
if (::setsockopt(control->StreamFd(), SOL_SOCKET, SO_RCVBUF, &receiveBuffer, sizeof(receiveBuffer)) != 0)
|
||||
return kControlBuffer;
|
||||
if (!client.PauseControlReaderForTest(true)) return kNoControlReader;
|
||||
for (std::uint32_t i = 0; i < kFloodRecords; ++i) {
|
||||
MGP::MGPPatchState patch{};
|
||||
@@ -900,13 +912,16 @@ namespace {
|
||||
ConfigureClient(control);
|
||||
auto& client = Client::ClientSessionInstance();
|
||||
if (client.StartSpawned() != MOBILEGL_OK) ::_exit(kNoWelcome);
|
||||
int originalReceiveBuffer = 0;
|
||||
if (alsoStopDraining) {
|
||||
const int filled = FillTheEventRingWithoutDraining(client, [&client] { return StopReadingControlAndFlood(client); });
|
||||
const int filled = FillTheEventRingWithoutDraining(client, [&] {
|
||||
return StopReadingControlAndFlood(client, originalReceiveBuffer);
|
||||
});
|
||||
if (filled != kChildOk) ::_exit(filled);
|
||||
} else {
|
||||
const int up = BringUpPbufferContext();
|
||||
if (up != kChildOk) ::_exit(up);
|
||||
const int flooded = StopReadingControlAndFlood(client);
|
||||
const int flooded = StopReadingControlAndFlood(client, originalReceiveBuffer);
|
||||
if (flooded != kChildOk) ::_exit(flooded);
|
||||
}
|
||||
const char one = 1;
|
||||
@@ -914,7 +929,11 @@ namespace {
|
||||
char go = 0;
|
||||
(void)::read(release, &go, 1);
|
||||
if (alsoStopDraining) ::_exit(kChildOk);
|
||||
client.PauseControlReaderForTest(false);
|
||||
// End the receive-window fault before waiting for the ack behind the queued logs.
|
||||
if (::setsockopt(client.ControlSocketForTest()->StreamFd(), SOL_SOCKET, SO_RCVBUF,
|
||||
&originalReceiveBuffer, sizeof(originalReceiveBuffer)) != 0)
|
||||
::_exit(kControlBuffer);
|
||||
if (!client.PauseControlReaderForTest(false)) ::_exit(kNoControlReader);
|
||||
client.SyncPeerLog();
|
||||
(void)::write(synced, &one, 1);
|
||||
(void)::read(release, &go, 1);
|
||||
|
||||
Reference in New Issue
Block a user