[idd] scheduler: preserve concurrent force requests

Replace the shared force and republish booleans with request tickets.
A completed publication now acknowledges only requests captured when it
began, so a concurrent immediate or cadence-break request survives.
This commit is contained in:
Geoffrey McRae
2026-08-06 14:49:30 +10:00
parent 92f46f693f
commit 909271bfe1
2 changed files with 50 additions and 23 deletions

View File

@@ -147,8 +147,16 @@ bool CFrameScheduler::ElectOwner(uint64_t now)
m_nextDeadline = m_scheduling ? fastest->nextDelivery : 0; m_nextDeadline = m_scheduling ? fastest->nextDelivery : 0;
if (m_scheduling && !m_nextDeadline) if (m_scheduling && !m_nextDeadline)
m_nextDeadline = now + m_schedule.period; m_nextDeadline = now + m_schedule.period;
m_forceNext = m_scheduling; if (m_scheduling)
m_republishNext = m_scheduling; {
++m_forceRequestTicket;
++m_republishRequestTicket;
}
else
{
m_forceAckTicket = m_forceRequestTicket;
m_republishAckTicket = m_republishRequestTicket;
}
if (fastest) if (fastest)
fastest->lastFeedbackFrameSerial = 0; fastest->lastFeedbackFrameSerial = 0;
@@ -178,11 +186,12 @@ void CFrameScheduler::Reset()
AcquireSRWLockExclusive(&m_lock); AcquireSRWLockExclusive(&m_lock);
for (Client& client : m_clients) for (Client& client : m_clients)
client = {}; client = {};
m_schedule = {}; m_schedule = {};
m_scheduling = false; m_scheduling = false;
m_forceNext = false; m_epoch = 0;
m_republishNext = false;
m_epoch = 0; m_forceAckTicket = m_forceRequestTicket;
m_republishAckTicket = m_republishRequestTicket;
m_lastArrival = 0; m_lastArrival = 0;
m_guestPeriod = 0; m_guestPeriod = 0;
@@ -359,11 +368,12 @@ bool CFrameScheduler::UpdateSchedule(uint32_t sourceClientID,
} }
wake |= ElectOwner(now); wake |= ElectOwner(now);
if (m_scheduling && client->clientID == m_schedule.clientID && if (m_scheduling && client->clientID == m_schedule.clientID &&
client->generation == m_schedule.generation && client->immediate) client->generation == m_schedule.generation &&
(schedule.flags & KVMFR_FRAME_SCHEDULE_IMMEDIATE))
{ {
m_forceNext = true; ++m_forceRequestTicket;
m_republishNext = true; ++m_republishRequestTicket;
wake = true; wake = true;
} }
wake |= ApplyFeedback(*client, schedule); wake |= ApplyFeedback(*client, schedule);
ReleaseSRWLockExclusive(&m_lock); ReleaseSRWLockExclusive(&m_lock);
@@ -447,6 +457,7 @@ bool CFrameScheduler::GetSchedule(Schedule& schedule) const
void CFrameScheduler::ObserveFrame(uint64_t now) void CFrameScheduler::ObserveFrame(uint64_t now)
{ {
bool wake = false;
AcquireSRWLockExclusive(&m_lock); AcquireSRWLockExclusive(&m_lock);
++m_acquiredFrames; ++m_acquiredFrames;
if (m_lastArrival && now > m_lastArrival) if (m_lastArrival && now > m_lastArrival)
@@ -455,7 +466,8 @@ void CFrameScheduler::ObserveFrame(uint64_t now)
if (m_guestPeriod && interval > m_guestPeriod * CADENCE_BREAK) if (m_guestPeriod && interval > m_guestPeriod * CADENCE_BREAK)
{ {
m_guestPeriod = 0; m_guestPeriod = 0;
m_forceNext = true; ++m_forceRequestTicket;
wake = true;
} }
else if (interval >= MIN_SOURCE_PERIOD_NS && else if (interval >= MIN_SOURCE_PERIOD_NS &&
interval <= MAX_PERIOD_NS) interval <= MAX_PERIOD_NS)
@@ -468,12 +480,14 @@ void CFrameScheduler::ObserveFrame(uint64_t now)
} }
m_lastArrival = now; m_lastArrival = now;
ReleaseSRWLockExclusive(&m_lock); ReleaseSRWLockExclusive(&m_lock);
if (wake)
WakePublisher();
} }
void CFrameScheduler::ForceFrame() void CFrameScheduler::ForceFrame()
{ {
AcquireSRWLockExclusive(&m_lock); AcquireSRWLockExclusive(&m_lock);
m_forceNext = true; ++m_forceRequestTicket;
ReleaseSRWLockExclusive(&m_lock); ReleaseSRWLockExclusive(&m_lock);
WakePublisher(); WakePublisher();
} }
@@ -492,8 +506,10 @@ bool CFrameScheduler::GetPublishTarget(uint64_t now, uint64_t& target,
return true; return true;
} }
schedule = m_schedule; schedule = m_schedule;
republish = m_republishNext; schedule.forceTicket = m_forceRequestTicket;
schedule.republishTicket = m_republishRequestTicket;
republish = schedule.republishTicket != m_republishAckTicket;
const uint64_t safety = const uint64_t safety =
max(MIN_SAFETY_NS, m_workEstimate / 8); max(MIN_SAFETY_NS, m_workEstimate / 8);
@@ -502,7 +518,7 @@ bool CFrameScheduler::GetPublishTarget(uint64_t now, uint64_t& target,
const uint64_t periodicTarget = m_nextDeadline > lead ? const uint64_t periodicTarget = m_nextDeadline > lead ?
m_nextDeadline - lead : now; m_nextDeadline - lead : now;
if (m_forceNext) if (schedule.forceTicket != m_forceAckTicket)
{ {
periodic = periodicTarget <= now; periodic = periodicTarget <= now;
ReleaseSRWLockExclusive(&m_lock); ReleaseSRWLockExclusive(&m_lock);
@@ -536,13 +552,16 @@ void CFrameScheduler::FramePublished(const Schedule& schedule,
schedule.generation == m_schedule.generation && schedule.generation == m_schedule.generation &&
schedule.epoch == m_schedule.epoch) schedule.epoch == m_schedule.epoch)
{ {
m_forceNext = false; if (schedule.forceTicket > m_forceAckTicket)
m_republishNext = false; m_forceAckTicket = schedule.forceTicket;
if (schedule.republishTicket > m_republishAckTicket)
m_republishAckTicket = schedule.republishTicket;
Client * client = FindClient(m_schedule.clientID); Client * client = FindClient(m_schedule.clientID);
if (client) if (client)
{ {
client->immediate = false; if (m_republishAckTicket == m_republishRequestTicket)
client->immediate = false;
client->lastDeliveredFrameSerial = frameSerial; client->lastDeliveredFrameSerial = frameSerial;
client->deliveredFrameValid = true; client->deliveredFrameValid = true;
} }
@@ -567,12 +586,14 @@ void CFrameScheduler::FrameRepublished(const Schedule& schedule,
schedule.generation == m_schedule.generation && schedule.generation == m_schedule.generation &&
schedule.epoch == m_schedule.epoch) schedule.epoch == m_schedule.epoch)
{ {
m_republishNext = false; if (schedule.republishTicket > m_republishAckTicket)
m_republishAckTicket = schedule.republishTicket;
Client * client = FindClient(m_schedule.clientID); Client * client = FindClient(m_schedule.clientID);
if (client) if (client)
{ {
client->immediate = false; if (m_republishAckTicket == m_republishRequestTicket)
client->immediate = false;
client->lastDeliveredFrameSerial = frameSerial; client->lastDeliveredFrameSerial = frameSerial;
client->deliveredFrameValid = true; client->deliveredFrameValid = true;
client->nextDelivery = m_nextDeadline; client->nextDelivery = m_nextDeadline;

View File

@@ -39,6 +39,8 @@ public:
uint32_t epoch; uint32_t epoch;
uint64_t period; uint64_t period;
uint64_t targetSlack; uint64_t targetSlack;
uint64_t forceTicket;
uint64_t republishTicket;
}; };
private: private:
@@ -65,10 +67,14 @@ private:
Client m_clients[LGMP_MAX_CLIENTS] = {}; Client m_clients[LGMP_MAX_CLIENTS] = {};
Schedule m_schedule = {}; Schedule m_schedule = {};
bool m_scheduling = false; bool m_scheduling = false;
bool m_forceNext = false;
bool m_republishNext = false;
uint32_t m_epoch = 0; uint32_t m_epoch = 0;
// A result acknowledges only the request tickets captured by its attempt.
uint64_t m_forceRequestTicket = 0;
uint64_t m_forceAckTicket = 0;
uint64_t m_republishRequestTicket = 0;
uint64_t m_republishAckTicket = 0;
uint64_t m_lastArrival = 0; uint64_t m_lastArrival = 0;
uint64_t m_guestPeriod = 0; uint64_t m_guestPeriod = 0;
uint64_t m_workEstimate = 0; uint64_t m_workEstimate = 0;