Latch mouse deltas before sending to prevent starvation

It's possible a client sending rapid relative mouse motion
could completely monopolize the input thread and prevent it
from exiting the loop.
This commit is contained in:
Cameron Gutman committed 2026-10-22 20:38:22 -05:00
1 parent 04053843c9
commit 448b2c6868
1 file changed
+23 -23
+23 -23
View File
@@ -405,57 +405,57 @@ static void inputSendThreadProc(void* context) {
PltLockMutex(&batchedInputMutex); PltLockMutex(&batchedInputMutex);
int deltaX = currentRelativeMouseState.deltaX;
int deltaY = currentRelativeMouseState.deltaY;
currentRelativeMouseState.deltaX = 0;
currentRelativeMouseState.deltaY = 0;
// The state change is no longer pending
currentRelativeMouseState.dirty = false;
PltUnlockMutex(&batchedInputMutex);
// Send as many packets as it takes to get the entire delta through // Send as many packets as it takes to get the entire delta through
while (currentRelativeMouseState.deltaX != 0 || currentRelativeMouseState.deltaY != 0) { while (deltaX != 0 || deltaY != 0) {
bool more = false; bool more = false;
if (currentRelativeMouseState.deltaX < INT16_MIN) { if (deltaX < INT16_MIN) {
holder->packet.mouseMoveRel.deltaX = BE16(INT16_MIN); holder->packet.mouseMoveRel.deltaX = BE16(INT16_MIN);
currentRelativeMouseState.deltaX -= INT16_MIN; deltaX -= INT16_MIN;
more = true; more = true;
} }
else if (currentRelativeMouseState.deltaX > INT16_MAX) { else if (deltaX > INT16_MAX) {
holder->packet.mouseMoveRel.deltaX = BE16(INT16_MAX); holder->packet.mouseMoveRel.deltaX = BE16(INT16_MAX);
currentRelativeMouseState.deltaX -= INT16_MAX; deltaX -= INT16_MAX;
more = true; more = true;
} }
else { else {
holder->packet.mouseMoveRel.deltaX = BE16(currentRelativeMouseState.deltaX); holder->packet.mouseMoveRel.deltaX = BE16(deltaX);
currentRelativeMouseState.deltaX = 0; deltaX = 0;
} }
if (currentRelativeMouseState.deltaY < INT16_MIN) { if (deltaY < INT16_MIN) {
holder->packet.mouseMoveRel.deltaY = BE16(INT16_MIN); holder->packet.mouseMoveRel.deltaY = BE16(INT16_MIN);
currentRelativeMouseState.deltaY -= INT16_MIN; deltaY -= INT16_MIN;
more = true; more = true;
} }
else if (currentRelativeMouseState.deltaY > INT16_MAX) { else if (deltaY > INT16_MAX) {
holder->packet.mouseMoveRel.deltaY = BE16(INT16_MAX); holder->packet.mouseMoveRel.deltaY = BE16(INT16_MAX);
currentRelativeMouseState.deltaY -= INT16_MAX; deltaY -= INT16_MAX;
more = true; more = true;
} }
else { else {
holder->packet.mouseMoveRel.deltaY = BE16(currentRelativeMouseState.deltaY); holder->packet.mouseMoveRel.deltaY = BE16(deltaY);
currentRelativeMouseState.deltaY = 0; deltaY = 0;
} }
// Don't hold the batching lock while we're doing network I/O
PltUnlockMutex(&batchedInputMutex);
// Encrypt and send the split packet // Encrypt and send the split packet
if (!sendInputPacket(holder, more)) { if (!sendInputPacket(holder, more)) {
freePacketHolder(holder); freePacketHolder(holder);
return; return;
} }
PltLockMutex(&batchedInputMutex);
} }
// The state change is no longer pending
currentRelativeMouseState.dirty = false;
PltUnlockMutex(&batchedInputMutex);
lastMousePacketTime = now; lastMousePacketTime = now;
// We sent everything we needed in the loop above, so we can just free the // We sent everything we needed in the loop above, so we can just free the