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;