[idd] clipboard: pipeline helper channel

Publish ordered four-record prefixes through the Helper mapping and ring
once per accepted burst. Wake blocked producers when the peer returns
credits while retaining the bounded polling fallback.

Move received payload ownership into manager work items and place remote
file-read data directly into the waiting caller’s bounded output buffer.
This removes avoidable 256 KiB copies without changing record ordering,
timeouts, cancellation, or reset semantics.
This commit is contained in:
Geoffrey McRae
2026-08-15 14:11:30 +10:00
parent b353b5ef06
commit 89b1ced8fc
6 changed files with 344 additions and 148 deletions

View File

@@ -27,7 +27,9 @@
#include <Windows.h>
#include <atomic>
#include <stddef.h>
#include <stdint.h>
#include <vector>
enum class ClipboardChannelResult
{
@@ -36,16 +38,24 @@ enum class ClipboardChannelResult
FAILED,
};
struct ClipboardChannelWrite
{
KVMFRClipboardMessage record = {};
const void * data = nullptr;
};
class IClipboardChannelHandler
{
public:
virtual ~IClipboardChannelHandler() = default;
virtual void ClipboardState(bool available, uint64_t epoch) = 0;
// data is borrowed and remains valid only for the duration of this call.
// BUSY leaves the shared ring slot occupied so it can be retried later.
// data owns record.length bytes and may be moved by the handler. BUSY
// leaves the shared ring slot occupied so it can be reconstructed and
// retried later.
virtual ClipboardChannelResult ClipboardRecord(
const KVMFRClipboardMessage& record, const uint8_t * data) = 0;
const KVMFRClipboardMessage& record,
std::vector<uint8_t>&& data) = 0;
virtual void ClipboardReset(uint64_t epoch, uint32_t reason) = 0;
};
@@ -75,16 +85,17 @@ private:
CSRWLock m_handlerLock;
CSRWLock m_writeLock;
HANDLE m_mapping = nullptr;
ClipboardMapping * m_view = nullptr;
ClipboardRing * m_in = nullptr;
ClipboardRing * m_out = nullptr;
HANDLE m_stop = nullptr;
HANDLE m_kick = nullptr;
HANDLE m_thread = nullptr;
DWORD m_threadId = 0;
uint64_t m_epoch = 0;
uint64_t m_instance = 0;
HANDLE m_mapping = nullptr;
ClipboardMapping * m_view = nullptr;
ClipboardRing * m_in = nullptr;
ClipboardRing * m_out = nullptr;
HANDLE m_stop = nullptr;
HANDLE m_kick = nullptr;
HANDLE m_writeReady = nullptr;
HANDLE m_thread = nullptr;
DWORD m_threadId = 0;
uint64_t m_epoch = 0;
uint64_t m_instance = 0;
bool m_deferredDetach = false;
IClipboardChannelHandler * m_handler = nullptr;
@@ -97,7 +108,8 @@ private:
void CleanupDeferredDetach();
void PublishState(bool available, uint64_t epoch);
ClipboardChannelResult PublishRecord(
const KVMFRClipboardMessage& record, const uint8_t * data);
const KVMFRClipboardMessage& record,
std::vector<uint8_t>&& data);
void PublishReset(uint64_t epoch, uint32_t reason);
static DWORD WINAPI ThreadProc(void * context);
@@ -114,10 +126,17 @@ public:
void Detach();
void Kick(uint64_t epoch);
void Reset(uint64_t epoch, uint32_t reason);
bool WaitWritable(HANDLE stop, DWORD timeout);
ClipboardChannelResult Send(
const KVMFRClipboardMessage& record, const void * data = nullptr);
// Publish an ordered prefix of records, bounded by the physical ring
// window. BUSY may return a non-zero accepted count; the caller must resume
// at that prefix boundary. A single doorbell covers the entire prefix.
ClipboardChannelResult SendBatch(const ClipboardChannelWrite * records,
size_t count, size_t& accepted);
void SetHandler(IClipboardChannelHandler * handler);
void ClearHandler(IClipboardChannelHandler * handler);