[idd] common: centralize nonzero sequences

This commit is contained in:
Geoffrey McRae
2026-08-13 21:44:07 +10:00
parent cd6bcc3a41
commit 5d12ee4bce
11 changed files with 97 additions and 62 deletions

View File

@@ -77,6 +77,7 @@
<ClInclude Include="InputPipeProtocol.h" /> <ClInclude Include="InputPipeProtocol.h" />
<ClInclude Include="PipeMsg.h" /> <ClInclude Include="PipeMsg.h" />
<ClInclude Include="RefreshRate.h" /> <ClInclude Include="RefreshRate.h" />
<ClInclude Include="Seq.h" />
</ItemGroup> </ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets" /> <ImportGroup Label="ExtensionTargets" />

View File

@@ -44,5 +44,8 @@
<ClInclude Include="RefreshRate.h"> <ClInclude Include="RefreshRate.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Seq.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>

54
idd/LGCommon/Seq.h Normal file
View File

@@ -0,0 +1,54 @@
/**
* Looking Glass
* Copyright © 2017-2026 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc., 59
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#pragma once
#include <type_traits>
namespace Seq
{
template<typename T>
T Next(T value)
{
static_assert(std::is_integral<T>::value &&
std::is_unsigned<T>::value && !std::is_same<T, bool>::value,
"sequence type must be an unsigned integer");
const T next = value + static_cast<T>(1);
return next ? next : static_cast<T>(1);
}
template<typename T>
T Inc(T& value)
{
value = Next(value);
return value;
}
template<typename T>
T Take(T& value)
{
if (!value)
value = static_cast<T>(1);
const T result = value;
value = Next(value);
return result;
}
}

View File

@@ -21,6 +21,7 @@
#include "capture/CFrameScheduler.h" #include "capture/CFrameScheduler.h"
#include "CDebug.h" #include "CDebug.h"
#include "Seq.h"
#include <string.h> #include <string.h>
@@ -210,8 +211,7 @@ bool CFrameScheduler::ElectOwner(uint64_t now, uint32_t resetClientID)
{ {
if (m_scheduling) if (m_scheduling)
{ {
if (!++m_epoch) Seq::Inc(m_epoch);
++m_epoch;
m_schedule.epoch = m_epoch; m_schedule.epoch = m_epoch;
} }
m_nextDeadline = m_scheduling ? fastest->nextDelivery : 0; m_nextDeadline = m_scheduling ? fastest->nextDelivery : 0;
@@ -517,8 +517,7 @@ void CFrameScheduler::AdvanceDeadlineSerial(uint64_t count)
return; return;
for (; epochAdvances; --epochAdvances) for (; epochAdvances; --epochAdvances)
if (!++m_epoch) Seq::Inc(m_epoch);
++m_epoch;
m_schedule.epoch = m_epoch; m_schedule.epoch = m_epoch;
Client * client = FindClient(m_schedule.clientID); Client * client = FindClient(m_schedule.clientID);

View File

@@ -21,6 +21,7 @@
#include "transport/CControlHub.h" #include "transport/CControlHub.h"
#include "CDebug.h" #include "CDebug.h"
#include "Seq.h"
#include <algorithm> #include <algorithm>
#include <cstring> #include <cstring>
@@ -105,12 +106,6 @@ DWORD WINAPI CControlHub::WorkerProc(void * opaque)
return 0; return 0;
} }
uint64_t CControlHub::NextRevision(uint64_t revision)
{
++revision;
return revision ? revision : 1;
}
bool CControlHub::TokenMatches( bool CControlHub::TokenMatches(
const Sink& sink, const ControlToken& token) const Sink& sink, const ControlToken& token)
{ {
@@ -160,8 +155,8 @@ bool CControlHub::Add(
selected->deliveredTransform = 0; selected->deliveredTransform = 0;
memset(selected->retryAt, 0, sizeof(selected->retryAt)); memset(selected->retryAt, 0, sizeof(selected->retryAt));
selected->nextWork = 0; selected->nextWork = 0;
selected->bindingSerial = NextRevision(selected->bindingSerial); selected->bindingSerial = Seq::Next(selected->bindingSerial);
selected->replaySerial = NextRevision(selected->replaySerial); selected->replaySerial = Seq::Next(selected->replaySerial);
selected->calling = false; selected->calling = false;
selected->active = false; selected->active = false;
selected->failed = false; selected->failed = false;
@@ -174,7 +169,7 @@ bool CControlHub::Add(
if (selected->target == &control && selected->backend == backend && if (selected->target == &control && selected->backend == backend &&
selected->epoch == epoch && selected->reserved && !selected->failed) selected->epoch == epoch && selected->reserved && !selected->failed)
{ {
selected->replaySerial = NextRevision(selected->replaySerial); selected->replaySerial = Seq::Next(selected->replaySerial);
selected->active = true; selected->active = true;
selected->reserved = false; selected->reserved = false;
attached = true; attached = true;
@@ -285,7 +280,7 @@ void CControlHub::OnControlReplay(const ControlToken& token)
sink.deliveredPosition = 0; sink.deliveredPosition = 0;
sink.deliveredShape = 0; sink.deliveredShape = 0;
sink.deliveredTransform = 0; sink.deliveredTransform = 0;
sink.replaySerial = NextRevision(sink.replaySerial); sink.replaySerial = Seq::Next(sink.replaySerial);
memset(sink.retryAt, 0, sizeof(sink.retryAt)); memset(sink.retryAt, 0, sizeof(sink.retryAt));
SetEvent(sink.wake); SetEvent(sink.wake);
return; return;
@@ -529,14 +524,14 @@ void CControlHub::SendCursor(const IDARG_OUT_QUERY_HWCURSOR& info,
m_state.cursor.X = info.X; m_state.cursor.X = info.X;
m_state.cursor.Y = info.Y; m_state.cursor.Y = info.Y;
m_state.sdrWhiteLevel = sdrWhiteLevel; m_state.sdrWhiteLevel = sdrWhiteLevel;
m_state.positionRevision = NextRevision(m_state.positionRevision); m_state.positionRevision = Seq::Next(m_state.positionRevision);
if (shape) if (shape)
{ {
m_state.cursor.IsCursorShapeUpdated = info.IsCursorShapeUpdated; m_state.cursor.IsCursorShapeUpdated = info.IsCursorShapeUpdated;
m_state.cursor.CursorShapeInfo = info.CursorShapeInfo; m_state.cursor.CursorShapeInfo = info.CursorShapeInfo;
m_state.cursorData = std::move(cursorData); m_state.cursorData = std::move(cursorData);
m_state.shapeRevision = NextRevision(m_state.shapeRevision); m_state.shapeRevision = Seq::Next(m_state.shapeRevision);
} }
} }
@@ -551,7 +546,7 @@ void CControlHub::SetColorTransform(
{ {
CSRWExclusiveLock lock(m_stateLock); CSRWExclusiveLock lock(m_stateLock);
m_state.transform = std::move(transform); m_state.transform = std::move(transform);
m_state.transformRevision = NextRevision(m_state.transformRevision); m_state.transformRevision = Seq::Next(m_state.transformRevision);
} }
WakeAll(WorkType::TRANSFORM); WakeAll(WorkType::TRANSFORM);
} }

View File

@@ -104,7 +104,6 @@ private:
bool m_valid = false; bool m_valid = false;
static DWORD WINAPI WorkerProc(void * opaque); static DWORD WINAPI WorkerProc(void * opaque);
static uint64_t NextRevision(uint64_t revision);
static bool TokenMatches(const Sink& sink, const ControlToken& token); static bool TokenMatches(const Sink& sink, const ControlToken& token);
bool BeginWork(Sink& sink, Work& work, DWORD& wait); bool BeginWork(Sink& sink, Work& work, DWORD& wait);

View File

@@ -21,6 +21,7 @@
#include "transport/CInputHub.h" #include "transport/CInputHub.h"
#include "input/IInputSink.h" #include "input/IInputSink.h"
#include "Seq.h"
static bool SameClient(const SourceKey& left, const SourceKey& right) static bool SameClient(const SourceKey& left, const SourceKey& right)
{ {
@@ -510,9 +511,7 @@ void CInputHub::InvalidateInteraction()
void CInputHub::AdvanceInteractionSerial() void CInputHub::AdvanceInteractionSerial()
{ {
++m_interactionSerial; Seq::Inc(m_interactionSerial);
if (!m_interactionSerial)
++m_interactionSerial;
} }
bool CInputHub::CheckState() bool CInputHub::CheckState()

View File

@@ -20,6 +20,8 @@
#include "transport/CRecoveryHub.h" #include "transport/CRecoveryHub.h"
#include "Seq.h"
#include <Windows.h> #include <Windows.h>
namespace namespace
@@ -99,16 +101,6 @@ bool CRecoveryHub::ActionMatchesLocked(
action.active == m_operation.action.active; action.active == m_operation.action.active;
} }
uint64_t CRecoveryHub::NextNonzero(uint64_t& value)
{
uint64_t result = value++;
if (!result)
result = value++;
if (!value)
++value;
return result;
}
uint32_t CRecoveryHub::NextSerial() uint32_t CRecoveryHub::NextSerial()
{ {
uint32_t result = m_nextSerial; uint32_t result = m_nextSerial;
@@ -134,7 +126,7 @@ void CRecoveryHub::SetWaitingLocked(Request& request,
request.source = source; request.source = source;
request.session = session; request.session = session;
request.operation = operation; request.operation = operation;
request.sequence = NextNonzero(m_nextSequence); request.sequence = Seq::Take(m_nextSequence);
request.serial = serial; request.serial = serial;
request.active = active; request.active = active;
request.state = SlotState::WAITING; request.state = SlotState::WAITING;
@@ -265,8 +257,8 @@ RecoveryAdmission CRecoveryHub::Submit(const SourceKey& source,
m_operation = Operation {}; m_operation = Operation {};
m_operation.phase = OperationPhase::IN_FLIGHT; m_operation.phase = OperationPhase::IN_FLIGHT;
m_operation.id = NextNonzero(m_nextOperation); m_operation.id = Seq::Take(m_nextOperation);
m_operation.action.route = NextNonzero(m_nextRoute); m_operation.action.route = Seq::Take(m_nextRoute);
m_operation.action.session = m_session; m_operation.action.session = m_session;
m_operation.action.serial = NextSerial(); m_operation.action.serial = NextSerial();
m_operation.action.active = active; m_operation.action.active = active;

View File

@@ -106,7 +106,6 @@ private:
unsigned FindSourceLocked(const SourceKey& source) const; unsigned FindSourceLocked(const SourceKey& source) const;
unsigned FindFreeLocked() const; unsigned FindFreeLocked() const;
bool ActionMatchesLocked(const RecoveryAction& action) const; bool ActionMatchesLocked(const RecoveryAction& action) const;
uint64_t NextNonzero(uint64_t& value);
uint32_t NextSerial(); uint32_t NextSerial();
void ClearRequestLocked(Request& request); void ClearRequestLocked(Request& request);
void SetWaitingLocked(Request& request, const SourceKey& source, void SetWaitingLocked(Request& request, const SourceKey& source,

View File

@@ -21,6 +21,7 @@
#include "transport/CTransportManager.h" #include "transport/CTransportManager.h"
#include "CDebug.h" #include "CDebug.h"
#include "Seq.h"
#include <Windows.h> #include <Windows.h>
#include <new> #include <new>
@@ -737,9 +738,7 @@ void CTransportManager::RetryEntry(Entry& entry, uint64_t now,
entry.inputAbsent = false; entry.inputAbsent = false;
entry.frameAbsent = false; entry.frameAbsent = false;
entry.serviceRetryAt = 0; entry.serviceRetryAt = 0;
++entry.epoch; Seq::Inc(entry.epoch);
if (!entry.epoch)
++entry.epoch;
} }
if (OpenEntry(entry) != OpenResult::SUCCESS) if (OpenEntry(entry) != OpenResult::SUCCESS)

View File

@@ -23,6 +23,7 @@
#include "transport/lgmp/CLGMPHost.h" #include "transport/lgmp/CLGMPHost.h"
#include "CDebug.h" #include "CDebug.h"
#include "CSRWLock.h" #include "CSRWLock.h"
#include "Seq.h"
#include "common/KVMFRInput.h" #include "common/KVMFRInput.h"
#include "common/LGMPConfig.h" #include "common/LGMPConfig.h"
@@ -136,8 +137,7 @@ void CLGMPInputTransport::UpdateTargetState(
if (state.state != m_targetState.state) if (state.state != m_targetState.state)
{ {
if (++m_endpointGeneration == 0) Seq::Inc(m_endpointGeneration);
++m_endpointGeneration;
} }
m_targetState = state; m_targetState = state;
m_statusDirty = true; m_statusDirty = true;
@@ -183,9 +183,7 @@ bool CLGMPInputTransport::PublishStatus()
status.maxButtons = KVMFR_INPUT_MOUSE_BUTTON_COUNT; status.maxButtons = KVMFR_INPUT_MOUSE_BUTTON_COUNT;
memcpy(lgmpHostMemPtr(memory), &status, sizeof(status)); memcpy(lgmpHostMemPtr(memory), &status, sizeof(status));
uint32_t serial = m_statusSerial + 1; const uint32_t serial = Seq::Next(m_statusSerial);
if (!serial)
++serial;
const LGMP_STATUS result = lgmpHostQueuePost(m_queue, serial, memory); const LGMP_STATUS result = lgmpHostQueuePost(m_queue, serial, memory);
if (result == LGMP_OK) if (result == LGMP_OK)
{ {
@@ -263,8 +261,7 @@ bool CLGMPInputTransport::Start(IInputTarget& target)
{ {
CSRWExclusiveLock statusLock(m_statusLock); CSRWExclusiveLock statusLock(m_statusLock);
m_targetState = target.GetState({}); m_targetState = target.GetState({});
if (++m_endpointGeneration == 0) Seq::Inc(m_endpointGeneration);
++m_endpointGeneration;
m_statusDirty = true; m_statusDirty = true;
} }
m_statusFailed.store(false, std::memory_order_release); m_statusFailed.store(false, std::memory_order_release);
@@ -505,9 +502,7 @@ bool CLGMPInputTransport::ProcessMessage(
return true; return true;
} }
uint32_t expectedSequence = m_ownerSequence + 1; const uint32_t expectedSequence = Seq::Next(m_ownerSequence);
if (!expectedSequence)
expectedSequence = 1;
if (message.sequence != expectedSequence) if (message.sequence != expectedSequence)
{ {
++m_statistics.sequenceErrors; ++m_statistics.sequenceErrors;