Skip to content
Frank edited this page Apr 17, 2026 · 1 revision

Opt-in Swap in CupidOS

CupidOS has a handle-based swap system for callers that want more logical memory than physical RAM holds. Swap is explicit — standard kmalloc stays untouched.

Quick start

#include "swap.h"

/* One-time init, e.g. from the shell or a program: */
swap_init("/disk/swap.bin", 4 * 1024 * 1024);  /* 4 MB resident pool */

swap_handle_t h = swap_kmalloc(60 * 1024);  /* class 3 (64K) */
void *p = swap_pin(h);
/* ... read/write up to class_size bytes of p ... */
swap_unpin(h);

/* Later, maybe after other pins evicted us: */
p = swap_pin(h);   /* loaded from disk if needed */
/* ... */
swap_unpin(h);
swap_free(h);

API

Function Returns Notes
swap_init(path, pool_bytes) 0 / -errno Create/open 16 MB backing file. Pool split evenly across 4 size classes. Call once.
swap_kmalloc(size) swap_handle_t or SWAP_INVALID Rounded up to smallest class: 1K / 4K / 16K / 64K. Allocates disk slot; no RAM yet.
swap_pin(h) void * or NULL Loads handle into RAM. May evict LRU-unpinned handles of the same class to make room. NULL if class is fully pinned.
swap_unpin(h) — Decrement pin count. When count hits 0, handle becomes LRU-eligible for eviction.
swap_free(h) — Release disk + RAM. Panics if currently pinned. Invalid handles are silent no-op.
swap_stats(&out) — Dump per-class usage + eviction counter.

Size classes

  • Class 0: 1 KB — 4096 disk slots (4 MB region).
  • Class 1: 4 KB — 1024 disk slots.
  • Class 2: 16 KB — 256 disk slots.
  • Class 3: 64 KB — 64 disk slots.

Shell commands

  • swapinit [pool_kb] — default 4096 KB. Uses /disk/swap.bin.
  • swapstats — dump current stats.

CupidC bindings

All 5 core functions are bound for CupidC .cc programs: swap_init, swap_kmalloc, swap_pin, swap_unpin, swap_free.

Example CupidC usage:

void main() {
    swap_init("/disk/swap.bin", 1024 * 1024);
    int h = swap_kmalloc(8000);
    char *p = (char *)swap_pin(h);
    p[0] = 'X';
    swap_unpin(h);
    swap_free(h);
}

Limitations

  • Opt-in only. Standard kmalloc does not swap. Callers must be swap-aware.
  • 16 MB hard cap total swap file size.
  • 1024 handles max. Too many small allocations exhaust the handle table before disk fills.
  • 64 KB max per allocation. Class 3's 64 KB limit is the per-alloc ceiling; bigger buffers need to be split or use kmalloc.
  • No auto-cleanup. Handles must be freed by the owner before process exit; otherwise disk slot leaks until reboot.
  • No persistence. Swap file contents are scratch; don't rely on surviving reboot.
  • Single-threaded. No locks (CupidOS kernel is single-threaded in this subsystem).

Why opt-in?

Classic page-fault swap is architecturally hostile on a ring-0 identity-mapped kernel — every C dereference would need to be page-fault-safe, including IRQ handlers. Opt-in handles deliver the same user-facing capability (logical > physical memory) while leaving the rest of the kernel untouched.

Testing

  • bin/feature18_swap.cc — end-to-end smoke test covering per-class round-trip, disk-cap exhaustion, nested-pin refcount, invalid-handle benign ops. Run after init:
    > swapinit
    > feature18_swap
    
    Expected output: PASS feature18_swap.

Clone this wiki locally