[idd] lgmp: use precise clipboard polling

Drive adaptive clipboard stream polling with a high-resolution waitable
timer instead of rounding microsecond delays into coarse wait-function
timeouts.

Preserve the explicit stop and local wake events while avoiding a clock-tick
stall at each file-transfer window.
This commit is contained in:
Geoffrey McRae
2026-08-15 16:03:43 +10:00
parent 6a590e343a
commit 9e9bf6b88c
2 changed files with 80 additions and 15 deletions

View File

@@ -31,6 +31,10 @@
#include <limits> #include <limits>
#include <string.h> #include <string.h>
#ifndef CREATE_WAITABLE_TIMER_HIGH_RESOLUTION
#define CREATE_WAITABLE_TIMER_HIGH_RESOLUTION 0x00000002
#endif
namespace namespace
{ {
static_assert(sizeof(LGMPStreamDescriptor) == static_assert(sizeof(LGMPStreamDescriptor) ==
@@ -50,6 +54,13 @@ namespace
1000, 1000,
}; };
bool ArmPollTimer(HANDLE timer, uint32_t waitUs)
{
LARGE_INTEGER due = {};
due.QuadPart = -static_cast<LONGLONG>(waitUs) * 10;
return SetWaitableTimer(timer, &due, 0, nullptr, nullptr, FALSE) != FALSE;
}
bool EmptyControl(const KVMFRClipboardMessage& message, bool EmptyControl(const KVMFRClipboardMessage& message,
bool keepToken = false) bool keepToken = false)
{ {
@@ -334,9 +345,11 @@ bool CLGMPClipboardTransport::Start(IClipboardTarget& target)
return true; return true;
CloseHandle(m_thread); CloseHandle(m_thread);
CloseHandle(m_pollTimer);
CloseHandle(m_wakeEvent); CloseHandle(m_wakeEvent);
CloseHandle(m_stopEvent); CloseHandle(m_stopEvent);
m_thread = nullptr; m_thread = nullptr;
m_pollTimer = nullptr;
m_wakeEvent = nullptr; m_wakeEvent = nullptr;
m_stopEvent = nullptr; m_stopEvent = nullptr;
} }
@@ -344,14 +357,37 @@ bool CLGMPClipboardTransport::Start(IClipboardTarget& target)
return false; return false;
m_stopEvent = CreateEventW(nullptr, TRUE, FALSE, nullptr); m_stopEvent = CreateEventW(nullptr, TRUE, FALSE, nullptr);
m_wakeEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); if (!m_stopEvent)
if (!m_stopEvent || !m_wakeEvent)
{ {
DEBUG_ERROR_HR(GetLastError(), const DWORD error = GetLastError();
"Failed to create LGMP clipboard worker events"); DEBUG_ERROR_HR(error,
if (m_wakeEvent) "Failed to create LGMP clipboard stop event");
m_stopEvent = nullptr;
return false;
}
m_wakeEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr);
if (!m_wakeEvent)
{
const DWORD error = GetLastError();
DEBUG_ERROR_HR(error,
"Failed to create LGMP clipboard wake event");
CloseHandle(m_stopEvent);
m_stopEvent = nullptr;
return false;
}
m_pollTimer = CreateWaitableTimerExW(nullptr, nullptr,
CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS);
if (!m_pollTimer)
m_pollTimer = CreateWaitableTimerExW(
nullptr, nullptr, 0, TIMER_ALL_ACCESS);
if (!m_pollTimer)
{
const DWORD error = GetLastError();
DEBUG_ERROR_HR(error,
"Failed to create LGMP clipboard poll timer");
CloseHandle(m_wakeEvent); CloseHandle(m_wakeEvent);
if (m_stopEvent)
CloseHandle(m_stopEvent); CloseHandle(m_stopEvent);
m_wakeEvent = nullptr; m_wakeEvent = nullptr;
m_stopEvent = nullptr; m_stopEvent = nullptr;
@@ -373,8 +409,10 @@ bool CLGMPClipboardTransport::Start(IClipboardTarget& target)
CSRWExclusiveLock lock(m_lock); CSRWExclusiveLock lock(m_lock);
m_target = nullptr; m_target = nullptr;
} }
CloseHandle(m_pollTimer);
CloseHandle(m_wakeEvent); CloseHandle(m_wakeEvent);
CloseHandle(m_stopEvent); CloseHandle(m_stopEvent);
m_pollTimer = nullptr;
m_wakeEvent = nullptr; m_wakeEvent = nullptr;
m_stopEvent = nullptr; m_stopEvent = nullptr;
return false; return false;
@@ -392,11 +430,14 @@ void CLGMPClipboardTransport::Stop()
if (m_thread) if (m_thread)
CloseHandle(m_thread); CloseHandle(m_thread);
if (m_pollTimer)
CloseHandle(m_pollTimer);
if (m_wakeEvent) if (m_wakeEvent)
CloseHandle(m_wakeEvent); CloseHandle(m_wakeEvent);
if (m_stopEvent) if (m_stopEvent)
CloseHandle(m_stopEvent); CloseHandle(m_stopEvent);
m_thread = nullptr; m_thread = nullptr;
m_pollTimer = nullptr;
m_wakeEvent = nullptr; m_wakeEvent = nullptr;
m_stopEvent = nullptr; m_stopEvent = nullptr;
@@ -1839,7 +1880,7 @@ void CLGMPClipboardTransport::Thread()
bool notifyFailed = false; bool notifyFailed = false;
for (;;) for (;;)
{ {
DWORD timeout = IDLE_POLL_MS; uint32_t waitUs = IDLE_POLL_MS * 1000U;
bool streamReceived = false; bool streamReceived = false;
bool notifyReady = false; bool notifyReady = false;
IClipboardTarget * readyTarget = nullptr; IClipboardTarget * readyTarget = nullptr;
@@ -1881,13 +1922,12 @@ void CLGMPClipboardTransport::Thread()
} }
if (m_pendingTarget.valid || m_internalTargetCount || if (m_pendingTarget.valid || m_internalTargetCount ||
m_streamTargetCount || m_ownerClientID) m_streamTargetCount || m_ownerClientID)
timeout = ACTIVE_POLL_MS; waitUs = ACTIVE_POLL_MS * 1000U;
if (m_ownerClientID) if (m_ownerClientID)
{ {
if (streamReceived) if (streamReceived)
lgmpStreamPollActivity(&streamPoll); lgmpStreamPollActivity(&streamPoll);
const uint32_t waitUs = lgmpStreamPollIdle(&streamPoll); waitUs = lgmpStreamPollIdle(&streamPoll);
timeout = waitUs ? (waitUs + 999U) / 1000U : 0U;
} }
else else
lgmpStreamPollActivity(&streamPoll); lgmpStreamPollActivity(&streamPoll);
@@ -1898,9 +1938,27 @@ void CLGMPClipboardTransport::Thread()
if (notifyReady) if (notifyReady)
readyTarget->ClipboardReceiveReady(); readyTarget->ClipboardReceiveReady();
const HANDLE handles[] = { m_stopEvent, m_wakeEvent }; if (!waitUs)
continue;
if (!ArmPollTimer(m_pollTimer, waitUs))
{
const DWORD error = GetLastError();
if (WaitForSingleObject(m_stopEvent, 0) == WAIT_OBJECT_0)
break;
DEBUG_ERROR_HR(error,
"Failed to arm LGMP clipboard poll timer");
notifyFailed = true;
break;
}
const HANDLE handles[] =
{
m_stopEvent,
m_wakeEvent,
m_pollTimer,
};
const DWORD wait = WaitForMultipleObjects( const DWORD wait = WaitForMultipleObjects(
_countof(handles), handles, FALSE, timeout); _countof(handles), handles, FALSE, INFINITE);
if (wait == WAIT_OBJECT_0) if (wait == WAIT_OBJECT_0)
break; break;
if (wait == WAIT_OBJECT_0 + 1) if (wait == WAIT_OBJECT_0 + 1)
@@ -1908,13 +1966,19 @@ void CLGMPClipboardTransport::Thread()
lgmpStreamPollActivity(&streamPoll); lgmpStreamPollActivity(&streamPoll);
continue; continue;
} }
if (wait != WAIT_OBJECT_0 + 1 && wait != WAIT_TIMEOUT) if (wait == WAIT_OBJECT_0 + 2)
continue;
if (wait == WAIT_FAILED)
{ {
DEBUG_ERROR_HR(GetLastError(), DEBUG_ERROR_HR(GetLastError(),
"LGMP clipboard worker wait failed"); "LGMP clipboard worker wait failed");
notifyFailed = true; notifyFailed = true;
break; break;
} }
DEBUG_ERROR("LGMP clipboard worker returned an unexpected wait "
"result: %lu", wait);
notifyFailed = true;
break;
} }
IClipboardTarget * target = nullptr; IClipboardTarget * target = nullptr;

View File

@@ -114,6 +114,7 @@ private:
IClipboardTarget * m_target = nullptr; IClipboardTarget * m_target = nullptr;
HANDLE m_stopEvent = nullptr; HANDLE m_stopEvent = nullptr;
HANDLE m_wakeEvent = nullptr; HANDLE m_wakeEvent = nullptr;
HANDLE m_pollTimer = nullptr;
HANDLE m_thread = nullptr; HANDLE m_thread = nullptr;
bool m_available = false; bool m_available = false;