Motion Master 6.0.0-alpha.50
Next-generation motion control software
Loading...
Searching...
No Matches
GameLoop Class Reference

Fixed-period real-time loop. More...

#include <game_loop.h>

Public Member Functions

 GameLoop (std::chrono::microseconds period)
 Constructs the loop with the given cycle period.
 
 ~GameLoop ()=default
 Destructor. Does not call stop() — the caller is responsible for stopping the loop before destroying it.
 
 GameLoop (const GameLoop &)=delete
 Copying is deleted — the loop owns real-time scheduling state that cannot be shared.
 
GameLoopoperator= (const GameLoop &)=delete
 Copy assignment is deleted — see copy constructor.
 
void addTask (CyclicTask *task)
 Registers a task to be executed every cycle.
 
void run ()
 Blocks the calling thread, running one cycle per period until stop() is called.
 
void stop ()
 Signals the loop to stop after the current cycle completes.
 
void setPeriod (std::chrono::microseconds period)
 Changes the cycle period while the loop is running.
 
uint64_t executedCycles () const
 Returns the number of cycles actually executed since run() was called.
 
uint64_t skippedCycles () const
 Returns the total number of cycles skipped since run() was called.
 
GameLoopHealth health () const
 Returns a snapshot of real-time loop health for diagnostics.
 

Detailed Description

Fixed-period real-time loop.

The caller drives the loop by blocking the calling thread in run(). The main thread becomes the RT thread — no separate thread is created. All other subsystems should start their own threads before calling run(), and stop them after run() returns.

Each cycle waits for the next absolute deadline via CyclicTimer, then executes the loop body. The period is set at construction and may be retimed while running via setPeriod() (see below).

Shutdown is cooperative: stop() sets an atomic flag that run() checks after each cycle completes. The loop exits cleanly within one period.

Constructor & Destructor Documentation

◆ GameLoop() [1/2]

GameLoop::GameLoop ( std::chrono::microseconds  period)
explicit

Constructs the loop with the given cycle period.

Parameters
periodTime between cycle starts. Typical value: 1000 µs (1 ms).

◆ ~GameLoop()

GameLoop::~GameLoop ( )
default

Destructor. Does not call stop() — the caller is responsible for stopping the loop before destroying it.

◆ GameLoop() [2/2]

GameLoop::GameLoop ( const GameLoop )
delete

Copying is deleted — the loop owns real-time scheduling state that cannot be shared.

Member Function Documentation

◆ addTask()

void GameLoop::addTask ( CyclicTask task)

Registers a task to be executed every cycle.

Tasks are called in registration order after each timer tick. Must be called before run() — not safe to call concurrently with a running loop.

Parameters
taskNon-owning pointer. The task must outlive every call to run() — its pointer is only dereferenced while the loop is executing, never after run() returns.

◆ executedCycles()

uint64_t GameLoop::executedCycles ( ) const

Returns the number of cycles actually executed since run() was called.

This counts loop iterations (calls to a task's execute()), which is distinct from grid periods elapsed: a stall that skips N cycles advances this by 1 (one iteration ran) while wall-clock time advanced by 1 + N periods. CycleContext::elapsed = executedCycles() + skippedCycles().

Returns
Executed-cycle count. Reads with relaxed ordering — suitable for diagnostics and logging, not for synchronisation.

◆ health()

GameLoopHealth GameLoop::health ( ) const

Returns a snapshot of real-time loop health for diagnostics.

Reads the counters, task-execution aggregates, and RT-scheduling flags with relaxed ordering, and computes the cumulative achievedHz from uptime. Safe to call from any thread; the dynamic fields are zero before run() starts.

◆ operator=()

GameLoop & GameLoop::operator= ( const GameLoop )
delete

Copy assignment is deleted — see copy constructor.

◆ run()

void GameLoop::run ( )

Blocks the calling thread, running one cycle per period until stop() is called.

On Linux, raises the calling thread to SCHED_FIFO priority and locks all memory pages before entering the loop. Both steps fail gracefully with a warning when the process lacks the required privileges (e.g. not run as root and no CAP_SYS_NICE / CAP_IPC_LOCK).

Note
Call this on the main thread and start all other subsystem threads beforehand — it does not return until the loop stops.

◆ setPeriod()

void GameLoop::setPeriod ( std::chrono::microseconds  period)

Changes the cycle period while the loop is running.

Stores the new period; the running loop picks it up on its next iteration and re-anchors the CyclicTimer's deadline grid to that instant (see CyclicTimer::setPeriod). Takes effect within one cycle. Safe to call from any thread — the store is a relaxed atomic and the RT loop is the only reader. Also updates the period reported by health().

Applying a change also starts a fresh health epoch: the loop resets its cumulative counters (executed/skipped cycles, task-time max/avg) and re-anchors the achievedHz baseline to that instant, so health() reflects only the new period. Without this the old, worse figures would linger and mask the improvement the change was meant to produce.

Changing the period only re-times the master cadence; it does not touch the process-data recorder ring or any drive-side watchdog. Raising the period toward a drive's PDO/SM watchdog window can fault that drive — the caller is responsible for choosing a sane value.

Parameters
periodNew cycle period. Must be > 0 (validated by the caller).

◆ skippedCycles()

uint64_t GameLoop::skippedCycles ( ) const

Returns the total number of cycles skipped since run() was called.

When a deadline is already past (an overrun or a scheduling stall — the latter routine on a non-RT OS), the timer skips the backlog and re-syncs to the grid rather than running missed cycles back-to-back (which would flood the bus with stale process data). This is the running total of cycles skipped that way — a nonzero, growing value means the loop is not meeting its period. Read via health() (GET /api/game-loop, the console Game Loop page). CycleContext::elapsed = executedCycles() + skippedCycles().

Returns
Skipped-cycle count. Reads with relaxed ordering — suitable for diagnostics, not for synchronisation.

◆ stop()

void GameLoop::stop ( )

Signals the loop to stop after the current cycle completes.

Safe to call from a signal handler. run() returns within one period.


The documentation for this class was generated from the following files: