WAITLIST System in the Apollo Guidance Computer (AGC): The Native Delayed-Task Scheduler

The WAITLIST system is the Apollo Guidance Computer's native delayed-task scheduler that queues programs to execute after precise centisecond delays without busy-waiting, enabling deterministic real-time guidance operations.

The WAITLIST subsystem in the LM (Luminary) AGC allows guidance software to schedule future tasks with millisecond precision. As implemented in the chrislgarry/Apollo-11 repository, this mechanism maintains a sorted queue of pending operations, freeing the processor for continuous navigation calculations rather than wasting cycles on busy-waiting loops.

Architecture of the WAITLIST Scheduler

The WAITLIST system maintains two parallel erase-mode lists in memory to track pending operations. According to the source in Luminary099/WAITLIST.agc, these structures handle up to nine simultaneous delayed tasks.

Task Queue Structure (LST1 and LST2)

The scheduler uses a dual-list architecture to separate timing data from executable addresses:

  • LST1: Contains the relative delay values (in centiseconds) for up to nine pending tasks, stored as sorted offsets from the current time.
  • LST2: Holds the corresponding 2CADR (2-word addresses) of those tasks, allowing the dispatcher to locate the executable code when delays expire.

When a new task enters the queue, the system inserts it into the sorted position and adjusts the remaining delays for subsequent entries to maintain accurate relative timing.

Time Base and Precision

The WAITLIST system operates on a centisecond granularity (1 cs = 0.01 s) using the TIME3 accumulator. As defined in the source code, TIME3 counts down from 16384 centiseconds (approximately 162.5 seconds). The scheduler calculates delay values using the formula C(TIME3) = 16384 - (T1 - T), where T represents the current time and T1 the target execution time.

How WAITLIST Schedules Tasks

Software modules invoke the scheduler through a standardized calling convention that places the delay in the accumulator and follows with the task address.

Standard WAITLIST Calling Sequence

A typical invocation follows this exact sequence documented in Luminary099/WAITLIST.agc (lines 64-70):

; L = address of the task to start (2-CADR)
; A = delay in centiseconds (Δt)
L-1    CA   DELTAT          ; Δt = time until task start
L      TC   WAITLIST        ; queue the task
L+1    2CADR DESIRED_TASK   ; high word of task address
L+2    (MINOR OF 2CADR)    ; low word (often 0)
L+3    RELINT             ; return here after insertion

The WAITLIST routine inserts the new entry into the sorted list, adjusting remaining delays for existing entries to maintain the relative timebase.

The TWIDDLE Optimization for Same-Bank Tasks

When the target task resides in the same memory bank as the caller, the TWIDDLE pseudo-instruction provides a space optimization. As implemented in Luminary099/WAITLIST.agc (lines 71-78), TWIDDLE encodes the address directly rather than using the split 2CADR format, saving one word of memory:

L-1    CA   DELTAT
L      TC   TWIDDLE          ; same-bank optimisation
L+1    ADRES DESIRED_TASK   ; full address (no 2-CADR split)
L+2    RELINT

TWIDDLE otherwise behaves identically to the standard WAITLIST call, entering the task into the same LST1/LST2 queues.

Task Dispatch and Execution

Once queued, tasks await execution through a hardware-triggered interrupt mechanism that guarantees deterministic timing for critical guidance functions.

T3RUPT Interrupt Handling

The T3RUPT interrupt—triggered by the 3-second "RUPT" clock—scans the head of the WAITLIST queue during each period. If the earliest entry's delay has elapsed, the interrupt handler dequeues the task, restores its 2CADR from LST2, and branches to it using DCS ENDTASK. This dispatch logic appears in Luminary099/WAITLIST.agc (lines 78-94) and Luminary099/T3RUPT_PROGRAM.agc.

Interrupt-Inhibited Execution Model

All tasks scheduled through WAITLIST execute with interrupts inhibited, as explicitly documented in the source (lines 58-63 of Luminary099/WAITLIST.agc). This design choice guarantees deterministic timing for critical guidance functions by preventing higher-priority interrupts from preempting time-sensitive operations.

Overflow Protection

The system enforces a hard limit of nine concurrent tasks. If software attempts to queue a tenth task, the scheduler triggers a special abort with code OCT 1203 — WAITLIST OVERFLOW (lines 84-87), preventing memory corruption in the fixed-size LST1/LST2 buffers.

Integration with Delay Routines

Higher-level timing utilities FIXDELAY and VARDELAY provide convenient wrappers around the core WAITLIST mechanism. These helper routines, defined in Luminary099/WAITLIST.agc (lines 51-57), invoke the scheduler under the same control flow but accept either fixed or variable delay parameters for auxiliary functions.

Additional integration points appear in Luminary099/LONGCALL.agc, which schedules tasks via WAITLIST or TWIDDLE depending on address space requirements, and Luminary099/RESTARTS_ROUTINE.agc, which distinguishes WAITLIST calls from other restart types during system recovery.

Summary

  • WAITLIST serves as the AGC's deterministic delayed-task scheduler, managing execution timing without busy-waiting.
  • The system maintains two sorted erase-mode lists (LST1 for delays, LST2 for 2CADR addresses) supporting up to nine concurrent tasks.
  • Tasks are queued via TC WAITLIST with delays specified in centiseconds, or via TWIDDLE for same-bank optimizations.
  • The T3RUPT interrupt dispatches ready tasks while the TIME3 accumulator provides the 16384-centisecond timing base.
  • Execution occurs with interrupts inhibited to ensure deterministic guidance calculations, with OCT 1203 aborts preventing queue overflow.

Frequently Asked Questions

How does the WAITLIST system differ from modern operating system timers?

Unlike modern preemptive multitasking systems, the AGC's WAITLIST operates as a cooperative, interrupt-inhibited scheduler with fixed queue slots. It lacks process isolation and priority inheritance, instead offering deterministic, millisecond-precision timing specifically optimized for the LM's guidance calculations. The system maintains hardware-level control through the TIME3 accumulator rather than software clock interrupts.

What happens when the WAITLIST queue fills up?

When software attempts to schedule a tenth concurrent task, the system generates an OCT 1203 abort code labeled "WAITLIST OVERFLOW" and halts execution. This hard limit protects the fixed-size LST1 and LST2 erase-mode buffers from corruption. Mission software was designed to avoid this condition through careful scheduling analysis during development.

Why does the WAITLIST system use centiseconds instead of milliseconds?

The centisecond granularity (0.01 seconds) represents a compromise between timing precision and computational overhead suitable for 1960s hardware. The TIME3 accumulator's 16384-centisecond range (approximately 162.5 seconds) provides sufficient duration for lunar descent phases while minimizing the interrupt frequency required to update the countdown timer.

Can WAITLIST tasks themselves schedule additional WAITLIST calls?

Yes, tasks executing under WAITLIST control can recursively invoke the scheduler to chain subsequent operations. Because tasks run with interrupts inhibited, they must complete quickly to avoid delaying the T3RUPT handler. The TASKOVER.agc module manages proper cleanup and return to the scheduler, enabling complex sequenced operations during critical flight phases.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →