How the EXECUTIVE System Manages Jobs and Tasks in the Apollo Guidance Computer

The EXECUTIVE system implements a preemptive priority scheduler that maintains job queues in 12‑word core sets, allocates VAC memory areas for tasks requiring private address space, and dispatches execution via the NOVAC, FINDVAC, and CHANJOB routines triggered by hardware interrupts.

The Apollo Guidance Computer (AGC) relied on a sophisticated multitasking kernel known as the EXECUTIVE to manage concurrent operations ranging from guidance calculations to I/O handling. Found in the Comanche055/EXECUTIVE.agc file of the chrislgarry/Apollo‑11 repository—the Command Module’s flight software—this system demonstrates how 1960s spaceflight code achieved deterministic multitasking within severe hardware constraints. Understanding how the EXECUTIVE system manages jobs and tasks reveals the architectural decisions that enabled safe lunar landing operations through priority‑driven scheduling and banked memory management.

Core Data Structures: Core Sets and VAC Areas

The EXECUTIVE organizes jobs using core sets—fixed 12‑word blocks in erasable memory. The first word stores the 2‑CADR (address of the job’s entry point), the second holds the priority (signed 9‑bit value), and the remaining words preserve registers required for resumption. When a job must yield the processor, its complete context is saved into this structure, allowing the CHANJOB routine (lines 207‑242) to restore it later, including the Superbank (SUPERBNK) register that tracks the current memory bank.

For tasks requiring dedicated address space, the EXECUTIVE provides VAC (Virtual Addressable Core) areas. When FINDVAC is invoked, the system scans the VAC1USE through VAC5USE registers to locate a free area, reserving the first available one before inserting the job into the queue. Jobs that do not need private memory use NOVAC instead, skipping the VAC allocation overhead.

Job Entry and Memory Allocation

Submitting Lightweight Jobs with NOVAC

The NOVAC routine (lines 33‑49) handles jobs that execute within the existing core set without requiring a VAC. The caller loads the accumulator with the job’s entry address and priority, then triggers an interrupt:

        TS      NEWLOC          ; Store entry address
        TS      NEWPRIO         ; Store priority (e.g., 5)
        INHINT                  ; Trigger EXECUTIVE entry

The EXECUTIVE catches the INHINT, saves these values into the next available core set, and returns control to the interrupted program. The new job remains dormant until the priority scanner selects it.

Allocating Private Memory with FINDVAC

When a job needs isolation, FINDVAC (lines 50‑61) executes a VAC‑allocation loop in FINDVAC2. It searches the VAC‑use registers and, upon finding a free area, reserves it before calling FINDVAC2 to complete the insertion. This mechanism prevents memory collisions between interpretive jobs and basic jobs sharing the same bank space.

Job Suspension and Context Switching

Suspending Active Jobs via CHANG1 and CHANG2

The EXECUTIVE provides distinct suspension paths for different execution modes. Basic jobs use CHANG1 (lines 72‑76), which saves the current core set and transfers control to CHANJOB. Interpretive jobs—which run using the AGC’s vector processing interpreter—use CHANG2 (lines 78‑86), performing extra bookkeeping for the negative LOC flag that distinguishes interpretive state.

The CHANJOB routine performs the heavy lifting of context switching (lines 207‑242). It swaps all general registers, updates SUPERBNK to reflect the new job’s memory bank, and jumps to the restored program counter. This bank‑aware switching ensures that jobs residing in different fixed memory banks execute correctly despite the AGC’s 15‑bit address space limitations.

Job Synchronization: Sleep and Wake Primitives

Putting Jobs to Sleep with JOBSLEEP

Jobs awaiting external events (such as telemetry I/O) call JOBSLEEP (lines 90‑94). This routine marks the job as inactive by storing its priority in a sleep‑priority register, effectively making the priority negative. The job remains in its core set but is ignored by the priority scanner until reawakened.

        TS      PRIORITY        ; Mark as sleeping (negative priority)
        INHINT                  ; EXECUTIVE runs JOBSLEEP

Awakening Jobs via JOBWAKE

The JOBWAKE routine (lines 95‑104) scans all core sets for a job whose saved location matches NEWLOC. Upon finding a match, it restores the job’s positive priority value and re‑queues it for execution. This event‑driven model allows hardware interrupts to trigger job resumption without polling loops.

Dynamic Priority Management and Termination

Changing Priorities Mid‑Execution with PRIOCHNG

Real‑time constraints sometimes require elevating or demoting a running job’s urgency. The PRIOCHNG routine (lines 106‑114) accepts a new priority value in the accumulator, stores it in the current core set, and forces a rescan of the priority list. This can trigger immediate preemption if a higher‑priority job becomes runnable.

Job Completion with ENDOFJOB

When a task finishes, it calls ENDOFJOB (lines 115‑119). This routine clears the job’s entry from the core set, restores the EXECUTIVE bank, and immediately invokes the priority scanner to dispatch the next eligible task. There is no “return to caller”; control flows directly to the highest‑priority ready job or enters the idle loop.

The Priority Scheduling Algorithm

The heart of the EXECUTIVE is the EJSCAN routine (lines 85‑110), implemented through the EJ1 and EJ2 subroutines. This scanner iterates over core sets in 12‑word steps, examining the priority registers to locate the highest positive value (active job). Because priorities are signed 9‑bit numbers, negative values (sleeping jobs) are automatically skipped. Once identified, the dispatcher loads the corresponding 2‑CADR and initiates a context switch via CHANJOB.

This deterministic scan ensures that critical guidance tasks—typically assigned priorities in the range 16‑31—always preempt lower‑priority housekeeping jobs, maintaining the millisecond‑level timing guarantees required for navigation.

System Idle and Interrupt Handling

When no jobs are pending, the EXECUTIVE enters an idle state through ADVAN, DUMMYJOB, and SELFBANK (lines 121‑133). This loop turns off the green activity light and repeatedly checks for new job requests via the interrupt system. Entry into the EXECUTIVE always occurs through the INHINT (interrupt inhibit) mechanism, ensuring atomic access to the job queue during insertion, deletion, or priority modification operations.

Summary

  • Core sets provide 12‑word containers for job state, storing 2‑CADR addresses, priorities, and resumption registers in contiguous erasable memory.
  • VAC allocation via FINDVAC gives jobs private address space, while NOVAC offers lightweight entry for stateless tasks.
  • Context switching relies on CHANJOB to swap registers and Superbank settings, enabling preemptive multitasking across the AGC’s banked memory architecture.
  • Synchronization primitives JOBSLEEP and JOBWAKE support event‑driven programming without polling overhead.
  • Priority management through PRIOCHNG allows dynamic urgency adjustment, while ENDOFJOB provides clean termination and immediate redispatch.
  • EJSCAN implements a deterministic priority queue scan, ensuring highest‑urgency tasks execute first.

Frequently Asked Questions

What is the difference between NOVAC and FINDVAC in the AGC EXECUTIVE?

NOVAC (lines 33‑49) inserts a job that runs in the existing core set without private memory, making it suitable for simple, self‑contained tasks. FINDVAC (lines 50‑61) first allocates a VAC area from the limited pool of five available spaces, then inserts the job, providing isolated address space for complex interpretive routines that might otherwise collide with other processes.

How does the EXECUTIVE system handle job preemption?

Preemption occurs when a higher‑priority job enters the queue or when PRIOCHNG elevates an existing job’s priority above the currently running task. The EJSCAN routine detects the priority inversion during its next execution cycle, and CHANJOB (lines 207‑242) performs the context switch by saving the current job’s registers—including the SUPERBNK value—and loading those of the higher‑priority job.

What are VAC areas and why are they necessary?

VAC (Virtual Addressable Core) areas are dedicated memory regions assigned to jobs that require persistent local variables or interpretive execution context. Because the AGC uses a shared memory model with bank switching, VAC areas prevent data corruption between concurrent jobs. The EXECUTIVE maintains five VAC registers (VAC1USE through VAC5USE) and grants them on a first‑available basis during FINDVAC processing.

How does the AGC EXECUTIVE enter the idle state?

When EJSCAN finds no active (positive priority) jobs, control flows to ADVAN and DUMMYJOB (lines 121‑133). This idle loop disables the activity indicator and halts meaningful execution until the next hardware interrupt arrives. The SELFBANK routine ensures the EXECUTIVE remains in its own memory bank while waiting, allowing immediate response to INHINT signals that indicate new job requests or wake events.

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 →