From 5bdfc0fe80293a717d4d342d7ab2719ef1d36e3a Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Sat, 15 Aug 2026 16:17:23 +1000 Subject: [PATCH] [idd] clipboard: remove stream payload restaging Keep inbound stream payloads in the bounded stream-target window while the Helper channel is busy and publish directly from those buffers. Retain the pending target only for LGMP queue controls. Their credits remain outstanding across retries. This removes one full payload copy per client-to-Helper record without changing delivery order, backpressure, or reset behavior. --- .../lgmp/CLGMPClipboardTransport.cpp | 145 +++++++++++++----- .../transport/lgmp/CLGMPClipboardTransport.h | 11 +- 2 files changed, 114 insertions(+), 42 deletions(-) diff --git a/idd/LGIdd/transport/lgmp/CLGMPClipboardTransport.cpp b/idd/LGIdd/transport/lgmp/CLGMPClipboardTransport.cpp index a1d199e5..d53285af 100644 --- a/idd/LGIdd/transport/lgmp/CLGMPClipboardTransport.cpp +++ b/idd/LGIdd/transport/lgmp/CLGMPClipboardTransport.cpp @@ -596,8 +596,9 @@ void CLGMPClipboardTransport::QueueFileDisconnect() bool CLGMPClipboardTransport::QueueInternalTarget( const KVMFRClipboardMessage& record) { - if (!m_pendingTarget.valid && !m_internalTargetCount) - return BeginTarget(record, nullptr, false); + if (!m_pendingTarget.valid && !m_streamTargetBusy && + !m_internalTargetCount) + return BeginTarget(record, false); if (m_internalTargetCount == INTERNAL_TARGET_COUNT) { m_failed = true; @@ -609,14 +610,15 @@ bool CLGMPClipboardTransport::QueueInternalTarget( bool CLGMPClipboardTransport::PumpInternalTarget() { - if (m_pendingTarget.valid || !m_internalTargetCount) + if (m_pendingTarget.valid || m_streamTargetBusy || + !m_internalTargetCount) return true; const KVMFRClipboardMessage record = m_internalTarget[0]; for (unsigned i = 1; i < m_internalTargetCount; ++i) m_internalTarget[i - 1] = m_internalTarget[i]; m_internalTarget[--m_internalTargetCount] = {}; - return BeginTarget(record, nullptr, false); + return BeginTarget(record, false); } void CLGMPClipboardTransport::ClearStreamTargets() @@ -625,6 +627,24 @@ void CLGMPClipboardTransport::ClearStreamTargets() target.Clear(); m_streamTargetHead = 0; m_streamTargetCount = 0; + m_streamTargetBusy = false; +} + +void CLGMPClipboardTransport::ClearQueuedStreamTargets() +{ + if (!m_streamTargetBusy) + { + ClearStreamTargets(); + return; + } + + // The BUSY head has already crossed the target boundary and must receive + // the same drain treatment as a BUSY PendingTarget. Only discard records + // which have not yet been presented to the target. + for (unsigned i = 1; i < m_streamTargetCount; ++i) + m_streamTarget[ + (m_streamTargetHead + i) % STREAM_TARGET_COUNT].Clear(); + m_streamTargetCount = 1; } bool CLGMPClipboardTransport::QueueStreamTarget( @@ -643,17 +663,79 @@ bool CLGMPClipboardTransport::QueueStreamTarget( return true; } -bool CLGMPClipboardTransport::ProcessStreamTarget( - const KVMFRClipboardMessage& record, const uint8_t * data) +void CLGMPClipboardTransport::PopStreamTarget() { + StreamTarget& target = m_streamTarget[m_streamTargetHead]; + target.Clear(); + m_streamTargetHead = + (m_streamTargetHead + 1) % STREAM_TARGET_COUNT; + --m_streamTargetCount; + m_streamTargetBusy = false; +} + +bool CLGMPClipboardTransport::PublishStreamTarget() +{ + StreamTarget& target = m_streamTarget[m_streamTargetHead]; + const ClipboardChannelResult result = m_target ? + m_target->SendClipboard(target.record, + target.record.length ? target.data : nullptr) : + ClipboardChannelResult::FAILED; + if (result == ClipboardChannelResult::BUSY) + { + m_streamTargetBusy = true; + if (m_ownerClientID) + RenewLease(); + return true; + } + + if (result == ClipboardChannelResult::ACCEPTED) + { + ApplyInbound(target.record); + if (m_ownerClientID && !m_ownerReleasing) + RenewLease(); + } + PopStreamTarget(); + + if (result == ClipboardChannelResult::FAILED) + { + ReleaseOwner("Helper delivery failed", false); + m_failed = true; + } + return true; +} + +bool CLGMPClipboardTransport::RetryStreamTarget() +{ + if (!m_streamTargetBusy || m_pendingTarget.valid) + return true; + + // The retained head is already validated and stamped. Retry it exactly; + // owner-release state may have changed while the target was BUSY. + m_streamTargetBusy = false; + return PublishStreamTarget(); +} + +bool CLGMPClipboardTransport::ProcessStreamTarget() +{ + StreamTarget& target = m_streamTarget[m_streamTargetHead]; + const KVMFRClipboardMessage record = target.record; if (!m_ownerClientID) + { + PopStreamTarget(); return true; + } if (m_ownerReleasing && !m_releaseClearHelper) + { + PopStreamTarget(); return true; + } if (record.type == KVMFR_CLIPBOARD_MESSAGE_DATA && record.transfer == m_discardClientToHelper) + { + PopStreamTarget(); return true; + } const bool fileData = record.type == KVMFR_CLIPBOARD_MESSAGE_FILE_DATA; @@ -666,6 +748,7 @@ bool CLGMPClipboardTransport::ProcessStreamTarget( ValidateChunk(m_clientToHelper, record)); if (!validData) { + PopStreamTarget(); ReleaseOwner("invalid clipboard stream data", true); return true; } @@ -673,32 +756,21 @@ bool CLGMPClipboardTransport::ProcessStreamTarget( if (!m_ownerReleasing) RenewLease(); if (staleFileData) - return true; - - KVMFRClipboardMessage forwarded = record; - forwarded.generation = m_endpointGeneration; - if (!BeginTarget(forwarded, data, false)) { - ReleaseOwner("failed to stage clipboard stream data", true); + PopStreamTarget(); return true; } - return true; + + target.record.generation = m_endpointGeneration; + return PublishStreamTarget(); } bool CLGMPClipboardTransport::PumpStreamTarget() { - while (!m_pendingTarget.valid && m_streamTargetCount) - { - StreamTarget& target = m_streamTarget[m_streamTargetHead]; - const KVMFRClipboardMessage record = target.record; - const uint8_t * data = record.length ? target.data : nullptr; - target.Clear(); - m_streamTargetHead = - (m_streamTargetHead + 1) % STREAM_TARGET_COUNT; - --m_streamTargetCount; - if (!ProcessStreamTarget(record, data)) + while (!m_pendingTarget.valid && !m_streamTargetBusy && + m_streamTargetCount) + if (!ProcessStreamTarget()) return false; - } return true; } @@ -820,7 +892,7 @@ void CLGMPClipboardTransport::FinishOwnerRelease() m_ownerDeadline = 0; m_ownerDrainDeadline = 0; m_replayPending = false; - ClearStreamTargets(); + ClearQueuedStreamTargets(); m_discardClientToHelper = 0; m_clientToHelper.Clear(); m_helperToClient.Clear(); @@ -1312,19 +1384,14 @@ void CLGMPClipboardTransport::ApplyOutbound( } bool CLGMPClipboardTransport::BeginTarget( - const KVMFRClipboardMessage& message, const uint8_t * data, - bool acknowledge) + const KVMFRClipboardMessage& message, bool acknowledge) { - if (m_pendingTarget.valid || - (message.length && !data) || - message.length > KVMFR_CLIPBOARD_DATA_BYTES) + if (m_pendingTarget.valid || message.length) return false; m_pendingTarget.valid = true; m_pendingTarget.acknowledge = acknowledge; m_pendingTarget.record = message; - if (message.length) - memcpy(m_pendingTarget.data, data, message.length); return RetryTarget(); } @@ -1352,10 +1419,8 @@ bool CLGMPClipboardTransport::RetryTarget() return true; const bool acknowledge = m_pendingTarget.acknowledge; - const uint8_t * data = m_pendingTarget.record.length ? - m_pendingTarget.data : nullptr; const ClipboardChannelResult result = m_target ? - m_target->SendClipboard(m_pendingTarget.record, data) : + m_target->SendClipboard(m_pendingTarget.record, nullptr) : ClipboardChannelResult::FAILED; if (result == ClipboardChannelResult::BUSY) { @@ -1493,7 +1558,7 @@ bool CLGMPClipboardTransport::ProcessMessage( KVMFRClipboardMessage forwarded = message; forwarded.generation = m_endpointGeneration; RenewLease(); - BeginTarget(forwarded, nullptr, true); + BeginTarget(forwarded, true); return false; } @@ -1896,6 +1961,7 @@ void CLGMPClipboardTransport::Thread() if (m_ownerClientID && !OwnerSubscribed()) { DropPendingTarget(); + ClearStreamTargets(); ReleaseOwner("subscriber disappeared", true, true); } else if (m_ownerClientID && !m_ownerReleasing && @@ -1904,9 +1970,11 @@ void CLGMPClipboardTransport::Thread() // A restarted client can reuse dataset and transfer IDs. Deliver every // old-owner cleanup record before admitting messages from a new owner. - if (!RetryTarget() || !PumpInternalTarget() || + if (!RetryTarget() || !RetryStreamTarget() || + !PumpInternalTarget() || !PumpStreamTarget() || - (m_internalTargetCount == 0 && !DrainMessage()) || + (!m_streamTargetBusy && m_internalTargetCount == 0 && + !DrainMessage()) || !DrainStream(streamReceived) || !RetryOwnerRelease() || !PublishStatus() || @@ -1986,6 +2054,7 @@ void CLGMPClipboardTransport::Thread() { CSRWExclusiveLock lock(m_lock); DropPendingTarget(); + ClearStreamTargets(); if (m_ownerClientID) ReleaseOwner("transport stopped", false, true); target = m_target; diff --git a/idd/LGIdd/transport/lgmp/CLGMPClipboardTransport.h b/idd/LGIdd/transport/lgmp/CLGMPClipboardTransport.h index 5b4ab89e..a05c97e5 100644 --- a/idd/LGIdd/transport/lgmp/CLGMPClipboardTransport.h +++ b/idd/LGIdd/transport/lgmp/CLGMPClipboardTransport.h @@ -83,7 +83,6 @@ private: bool valid = false; bool acknowledge = false; KVMFRClipboardMessage record = {}; - uint8_t data[KVMFR_CLIPBOARD_DATA_BYTES] = {}; void Clear() { @@ -150,6 +149,7 @@ private: StreamTarget m_streamTarget[STREAM_TARGET_COUNT]; unsigned m_streamTargetHead = 0; unsigned m_streamTargetCount = 0; + bool m_streamTargetBusy = false; KVMFRClipboardMessage m_internalTarget[INTERNAL_TARGET_COUNT] = {}; unsigned m_internalTargetCount = 0; CLGMPClipboardFiles m_files; @@ -187,12 +187,15 @@ private: bool QueueInternalTarget(const KVMFRClipboardMessage& record); bool PumpInternalTarget(); void ClearStreamTargets(); + void ClearQueuedStreamTargets(); bool QueueStreamTarget(const KVMFRClipboardMessage& record, const uint8_t * data); + void PopStreamTarget(); + bool PublishStreamTarget(); + bool RetryStreamTarget(); bool PumpStreamTarget(); bool DrainStream(bool& received); - bool ProcessStreamTarget(const KVMFRClipboardMessage& record, - const uint8_t * data); + bool ProcessStreamTarget(); PLGMPMemory FindAvailable(PLGMPMemory (&memory)[MEMORY_COUNT]) const; PostResult PostForOwner(uint64_t udata, PLGMPMemory memory); @@ -217,7 +220,7 @@ private: void ApplyInbound(const KVMFRClipboardMessage& message); void ApplyOutbound(const KVMFRClipboardMessage& message); bool BeginTarget(const KVMFRClipboardMessage& message, - const uint8_t * data, bool acknowledge); + bool acknowledge); ClipboardChannelResult SendControl( const KVMFRClipboardMessage& record);