From 5d12ee4bce17e22e3e671bf990955c9b86761ec1 Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Thu, 13 Aug 2026 21:44:07 +1000 Subject: [PATCH] [idd] common: centralize nonzero sequences --- idd/LGCommon/LGCommon.vcxproj | 1 + idd/LGCommon/LGCommon.vcxproj.filters | 3 ++ idd/LGCommon/Seq.h | 54 +++++++++++++++++++ idd/LGIdd/capture/CFrameScheduler.cpp | 7 ++- idd/LGIdd/transport/CControlHub.cpp | 39 ++++++-------- idd/LGIdd/transport/CControlHub.h | 1 - idd/LGIdd/transport/CInputHub.cpp | 5 +- idd/LGIdd/transport/CRecoveryHub.cpp | 20 +++---- idd/LGIdd/transport/CRecoveryHub.h | 1 - idd/LGIdd/transport/CTransportManager.cpp | 5 +- .../transport/lgmp/CLGMPInputTransport.cpp | 23 ++++---- 11 files changed, 97 insertions(+), 62 deletions(-) create mode 100644 idd/LGCommon/Seq.h diff --git a/idd/LGCommon/LGCommon.vcxproj b/idd/LGCommon/LGCommon.vcxproj index e838bd83..a8b5a342 100644 --- a/idd/LGCommon/LGCommon.vcxproj +++ b/idd/LGCommon/LGCommon.vcxproj @@ -77,6 +77,7 @@ + diff --git a/idd/LGCommon/LGCommon.vcxproj.filters b/idd/LGCommon/LGCommon.vcxproj.filters index c363bd92..dee4af59 100644 --- a/idd/LGCommon/LGCommon.vcxproj.filters +++ b/idd/LGCommon/LGCommon.vcxproj.filters @@ -44,5 +44,8 @@ Header Files + + Header Files + diff --git a/idd/LGCommon/Seq.h b/idd/LGCommon/Seq.h new file mode 100644 index 00000000..3f5c06ff --- /dev/null +++ b/idd/LGCommon/Seq.h @@ -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 + +namespace Seq +{ + template + T Next(T value) + { + static_assert(std::is_integral::value && + std::is_unsigned::value && !std::is_same::value, + "sequence type must be an unsigned integer"); + + const T next = value + static_cast(1); + return next ? next : static_cast(1); + } + + template + T Inc(T& value) + { + value = Next(value); + return value; + } + + template + T Take(T& value) + { + if (!value) + value = static_cast(1); + const T result = value; + value = Next(value); + return result; + } +} diff --git a/idd/LGIdd/capture/CFrameScheduler.cpp b/idd/LGIdd/capture/CFrameScheduler.cpp index 187865d7..fbc40e2b 100644 --- a/idd/LGIdd/capture/CFrameScheduler.cpp +++ b/idd/LGIdd/capture/CFrameScheduler.cpp @@ -21,6 +21,7 @@ #include "capture/CFrameScheduler.h" #include "CDebug.h" +#include "Seq.h" #include @@ -210,8 +211,7 @@ bool CFrameScheduler::ElectOwner(uint64_t now, uint32_t resetClientID) { if (m_scheduling) { - if (!++m_epoch) - ++m_epoch; + Seq::Inc(m_epoch); m_schedule.epoch = m_epoch; } m_nextDeadline = m_scheduling ? fastest->nextDelivery : 0; @@ -517,8 +517,7 @@ void CFrameScheduler::AdvanceDeadlineSerial(uint64_t count) return; for (; epochAdvances; --epochAdvances) - if (!++m_epoch) - ++m_epoch; + Seq::Inc(m_epoch); m_schedule.epoch = m_epoch; Client * client = FindClient(m_schedule.clientID); diff --git a/idd/LGIdd/transport/CControlHub.cpp b/idd/LGIdd/transport/CControlHub.cpp index 09813c9e..c97af36d 100644 --- a/idd/LGIdd/transport/CControlHub.cpp +++ b/idd/LGIdd/transport/CControlHub.cpp @@ -21,6 +21,7 @@ #include "transport/CControlHub.h" #include "CDebug.h" +#include "Seq.h" #include #include @@ -105,12 +106,6 @@ DWORD WINAPI CControlHub::WorkerProc(void * opaque) return 0; } -uint64_t CControlHub::NextRevision(uint64_t revision) -{ - ++revision; - return revision ? revision : 1; -} - bool CControlHub::TokenMatches( const Sink& sink, const ControlToken& token) { @@ -159,12 +154,12 @@ bool CControlHub::Add( selected->deliveredShape = 0; selected->deliveredTransform = 0; memset(selected->retryAt, 0, sizeof(selected->retryAt)); - selected->nextWork = 0; - selected->bindingSerial = NextRevision(selected->bindingSerial); - selected->replaySerial = NextRevision(selected->replaySerial); - selected->calling = false; - selected->active = false; - selected->failed = false; + selected->nextWork = 0; + selected->bindingSerial = Seq::Next(selected->bindingSerial); + selected->replaySerial = Seq::Next(selected->replaySerial); + selected->calling = false; + selected->active = false; + selected->failed = false; selected->failurePending = false; } control.SetControlEvents(this, token); @@ -174,10 +169,10 @@ bool CControlHub::Add( if (selected->target == &control && selected->backend == backend && selected->epoch == epoch && selected->reserved && !selected->failed) { - selected->replaySerial = NextRevision(selected->replaySerial); - selected->active = true; - selected->reserved = false; - attached = true; + selected->replaySerial = Seq::Next(selected->replaySerial); + selected->active = true; + selected->reserved = false; + attached = true; } } if (!attached) @@ -285,7 +280,7 @@ void CControlHub::OnControlReplay(const ControlToken& token) sink.deliveredPosition = 0; sink.deliveredShape = 0; sink.deliveredTransform = 0; - sink.replaySerial = NextRevision(sink.replaySerial); + sink.replaySerial = Seq::Next(sink.replaySerial); memset(sink.retryAt, 0, sizeof(sink.retryAt)); SetEvent(sink.wake); return; @@ -529,14 +524,14 @@ void CControlHub::SendCursor(const IDARG_OUT_QUERY_HWCURSOR& info, m_state.cursor.X = info.X; m_state.cursor.Y = info.Y; m_state.sdrWhiteLevel = sdrWhiteLevel; - m_state.positionRevision = NextRevision(m_state.positionRevision); + m_state.positionRevision = Seq::Next(m_state.positionRevision); if (shape) { m_state.cursor.IsCursorShapeUpdated = info.IsCursorShapeUpdated; m_state.cursor.CursorShapeInfo = info.CursorShapeInfo; - m_state.cursorData = std::move(cursorData); - m_state.shapeRevision = NextRevision(m_state.shapeRevision); + m_state.cursorData = std::move(cursorData); + m_state.shapeRevision = Seq::Next(m_state.shapeRevision); } } @@ -550,8 +545,8 @@ void CControlHub::SetColorTransform( { { CSRWExclusiveLock lock(m_stateLock); - m_state.transform = std::move(transform); - m_state.transformRevision = NextRevision(m_state.transformRevision); + m_state.transform = std::move(transform); + m_state.transformRevision = Seq::Next(m_state.transformRevision); } WakeAll(WorkType::TRANSFORM); } diff --git a/idd/LGIdd/transport/CControlHub.h b/idd/LGIdd/transport/CControlHub.h index 010ff195..8c5b725a 100644 --- a/idd/LGIdd/transport/CControlHub.h +++ b/idd/LGIdd/transport/CControlHub.h @@ -104,7 +104,6 @@ private: bool m_valid = false; static DWORD WINAPI WorkerProc(void * opaque); - static uint64_t NextRevision(uint64_t revision); static bool TokenMatches(const Sink& sink, const ControlToken& token); bool BeginWork(Sink& sink, Work& work, DWORD& wait); diff --git a/idd/LGIdd/transport/CInputHub.cpp b/idd/LGIdd/transport/CInputHub.cpp index f5183270..627f93d0 100644 --- a/idd/LGIdd/transport/CInputHub.cpp +++ b/idd/LGIdd/transport/CInputHub.cpp @@ -21,6 +21,7 @@ #include "transport/CInputHub.h" #include "input/IInputSink.h" +#include "Seq.h" static bool SameClient(const SourceKey& left, const SourceKey& right) { @@ -510,9 +511,7 @@ void CInputHub::InvalidateInteraction() void CInputHub::AdvanceInteractionSerial() { - ++m_interactionSerial; - if (!m_interactionSerial) - ++m_interactionSerial; + Seq::Inc(m_interactionSerial); } bool CInputHub::CheckState() diff --git a/idd/LGIdd/transport/CRecoveryHub.cpp b/idd/LGIdd/transport/CRecoveryHub.cpp index cd6ae584..bc4e9f5d 100644 --- a/idd/LGIdd/transport/CRecoveryHub.cpp +++ b/idd/LGIdd/transport/CRecoveryHub.cpp @@ -20,6 +20,8 @@ #include "transport/CRecoveryHub.h" +#include "Seq.h" + #include namespace @@ -99,16 +101,6 @@ bool CRecoveryHub::ActionMatchesLocked( 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 result = m_nextSerial; @@ -134,7 +126,7 @@ void CRecoveryHub::SetWaitingLocked(Request& request, request.source = source; request.session = session; request.operation = operation; - request.sequence = NextNonzero(m_nextSequence); + request.sequence = Seq::Take(m_nextSequence); request.serial = serial; request.active = active; request.state = SlotState::WAITING; @@ -264,9 +256,9 @@ RecoveryAdmission CRecoveryHub::Submit(const SourceKey& source, } m_operation = Operation {}; - m_operation.phase = OperationPhase::IN_FLIGHT; - m_operation.id = NextNonzero(m_nextOperation); - m_operation.action.route = NextNonzero(m_nextRoute); + m_operation.phase = OperationPhase::IN_FLIGHT; + m_operation.id = Seq::Take(m_nextOperation); + m_operation.action.route = Seq::Take(m_nextRoute); m_operation.action.session = m_session; m_operation.action.serial = NextSerial(); m_operation.action.active = active; diff --git a/idd/LGIdd/transport/CRecoveryHub.h b/idd/LGIdd/transport/CRecoveryHub.h index d5e6a968..d3d05481 100644 --- a/idd/LGIdd/transport/CRecoveryHub.h +++ b/idd/LGIdd/transport/CRecoveryHub.h @@ -106,7 +106,6 @@ private: unsigned FindSourceLocked(const SourceKey& source) const; unsigned FindFreeLocked() const; bool ActionMatchesLocked(const RecoveryAction& action) const; - uint64_t NextNonzero(uint64_t& value); uint32_t NextSerial(); void ClearRequestLocked(Request& request); void SetWaitingLocked(Request& request, const SourceKey& source, diff --git a/idd/LGIdd/transport/CTransportManager.cpp b/idd/LGIdd/transport/CTransportManager.cpp index 83b47196..104b161c 100644 --- a/idd/LGIdd/transport/CTransportManager.cpp +++ b/idd/LGIdd/transport/CTransportManager.cpp @@ -21,6 +21,7 @@ #include "transport/CTransportManager.h" #include "CDebug.h" +#include "Seq.h" #include #include @@ -737,9 +738,7 @@ void CTransportManager::RetryEntry(Entry& entry, uint64_t now, entry.inputAbsent = false; entry.frameAbsent = false; entry.serviceRetryAt = 0; - ++entry.epoch; - if (!entry.epoch) - ++entry.epoch; + Seq::Inc(entry.epoch); } if (OpenEntry(entry) != OpenResult::SUCCESS) diff --git a/idd/LGIdd/transport/lgmp/CLGMPInputTransport.cpp b/idd/LGIdd/transport/lgmp/CLGMPInputTransport.cpp index 83b79daa..481c4cad 100644 --- a/idd/LGIdd/transport/lgmp/CLGMPInputTransport.cpp +++ b/idd/LGIdd/transport/lgmp/CLGMPInputTransport.cpp @@ -23,6 +23,7 @@ #include "transport/lgmp/CLGMPHost.h" #include "CDebug.h" #include "CSRWLock.h" +#include "Seq.h" #include "common/KVMFRInput.h" #include "common/LGMPConfig.h" @@ -127,17 +128,16 @@ void CLGMPInputTransport::UpdateTargetState( const InputTargetState& state) { CSRWExclusiveLock lock(m_statusLock); - if (state.state == m_targetState.state && - state.available == m_targetState.available && - state.owned == m_targetState.owned && - state.owner.client == m_targetState.owner.client && + if (state.state == m_targetState.state && + state.available == m_targetState.available && + state.owned == m_targetState.owned && + state.owner.client == m_targetState.owner.client && state.owner.generation == m_targetState.owner.generation) return; if (state.state != m_targetState.state) { - if (++m_endpointGeneration == 0) - ++m_endpointGeneration; + Seq::Inc(m_endpointGeneration); } m_targetState = state; m_statusDirty = true; @@ -183,9 +183,7 @@ bool CLGMPInputTransport::PublishStatus() status.maxButtons = KVMFR_INPUT_MOUSE_BUTTON_COUNT; memcpy(lgmpHostMemPtr(memory), &status, sizeof(status)); - uint32_t serial = m_statusSerial + 1; - if (!serial) - ++serial; + const uint32_t serial = Seq::Next(m_statusSerial); const LGMP_STATUS result = lgmpHostQueuePost(m_queue, serial, memory); if (result == LGMP_OK) { @@ -263,8 +261,7 @@ bool CLGMPInputTransport::Start(IInputTarget& target) { CSRWExclusiveLock statusLock(m_statusLock); m_targetState = target.GetState({}); - if (++m_endpointGeneration == 0) - ++m_endpointGeneration; + Seq::Inc(m_endpointGeneration); m_statusDirty = true; } m_statusFailed.store(false, std::memory_order_release); @@ -505,9 +502,7 @@ bool CLGMPInputTransport::ProcessMessage( return true; } - uint32_t expectedSequence = m_ownerSequence + 1; - if (!expectedSequence) - expectedSequence = 1; + const uint32_t expectedSequence = Seq::Next(m_ownerSequence); if (message.sequence != expectedSequence) { ++m_statistics.sequenceErrors;