The visible goal was a Web app: type a URL, see the page, fetched over the
TCP stack SUB-OS built. Getting there surfaced -- and forced fixes to --
two deeper problems.
Async HTTP client (net/http_client.c)
tcp_connect/recv all block, so fetching from the GUI would freeze the
compositor. Fetches now run on one long-lived kernel worker thread that
services a single-slot mailbox; the requester posts a job and polls its
state. Ownership follows the state, and the two hand-off points (worker
completion, requester release) run under interrupts-off, so a window can
close mid-fetch with neither leak nor use-after-free. do_fetch returns
its terminal state rather than publishing it, closing a window where the
requester could free the job before finalize read it.
Cooperative scheduling for the idle thread (the core fix)
The login prompt, the shell and the GUI compositor all run on the pid-0
idle thread, which the scheduler by design never preempts (sched_tick
skips pid 0) and never requeues on a yield (weave_on clear). So it could
neither be preempted to let the worker run, nor cleanly yield -- the
worker was simply starved, and an early attempt to yield from it froze
the shell outright. The idle thread now joins the weave rotation once
hardware interrupts are live, and the network wait loops (tcp, dns, ping,
the worker's idle) yield through a new net_wait() instead of halting the
CPU. The compositor spends its frame-budget slack yielding too. Result:
a background fetch progresses while the desktop holds 54 FPS.
Web app (gui/gui_app_web.c)
A text browser: URL bar, Go, and a Raw/Reader toggle. Raw shows the
response verbatim; Reader strips markup (dropping <script>/<style>
bodies), decodes the common entities, and word-wraps the body. The line
index is cached against content/view/width so scrolling and idle
repaints are free. It only ever polls the worker, so it never stalls.
TCP throughput (the limit flagged last time)
The 32-slot table with a 2 s TIME_WAIT linger capped sustained serving
at ~16 req/s. The table is now 64 slots, a connection this end closed
after serving a request lingers 250 ms rather than 2 s, and expired
TIME_WAIT entries are reaped from the count path so a quiet table still
drains. netstat/netmon gained served-since-boot and peak-slots counters.
Also: a `webget` CLI (the async client from a shell), listen/accept
introspection already present, and a globe icon for the app.
Verified on x86_64: `webget` fetched an 812-byte page (HTTP 200, 10 ms) on
the worker thread; the GUI Web app rendered the same page in Reader mode
while the desktop held 54 FPS; an 80-request burst through the 64-slot
table returned 80/80 (was 39/40 before) and netstat reported "80 served,
peak 33 of 64 slots" -- a peak that would have overflowed the old table.
Builds clean on x86_64, aarch64 and armv8i.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Fh5z6V7nGPbHvqVG5p4CXX
Kernel: the passive-open half of TCP. tcp_listen claims a port, inbound
SYNs to it are completed by the receive path, and the finished
connections queue in a backlog until tcp_accept collects them. Accepted
connections run the same stream state machine as active opens, so
tcp_send/tcp_recv/tcp_close work on them unchanged. sys_listen and
sys_accept expose this through the BSD socket API, with sys_accept
returning a fresh descriptor and leaving the listener available for the
next caller. The built-in sshd and httpd predate this and are still
answered inline from the receive path; the role they use is now named
TCP_ROLE_SERVICE to keep that distinction explicit.
GUI: a Network Monitor app. Interface configuration and link state, a
rolling dual-line chart of receive and transmit rates sampled from the
NIC counters on a fixed 2 Hz cadence (so it reads in packets per half
second no matter how often the compositor repaints), byte and packet
totals, and the TCP engine's connection table with each connection's real
state and direction, scrollable when it outgrows the window.
Two bugs the monitor made visible, both fixed:
- Served HTTP connections were never closed. The response advertises
"Connection: close" but the engine left the connection ESTABLISHED
forever, so the 32-entry table filled up and the server stopped
answering after 32 requests. The service path now sends its FIN after
the response and lingers in TIME_WAIT until the reaper takes it. 40
sequential requests through a 32-slot table now yield 39 successes
where the 33rd onwards previously failed permanently.
- tcp_close gave up in FIN_WAIT2 after 500 ms and freed the slot, so a
peer whose own FIN arrived later got an RST instead of an ACK. It now
falls into TIME_WAIT instead, and TIME_WAIT acknowledges a first FIN
rather than only a retransmitted one. Expired TIME_WAIT entries are
also reaped from tcp_get_connections_count, so a table that sees no
further connections still empties out.
Verified on x86_64 against real peers, checked packet by packet in a
capture: a host client connected to `tcpserve 9000` in the guest and got
its reply -- SYN/SYN-ACK/ACK with a random ISN, 30-byte request, 43-byte
reply, and a clean four-way close whose final ACK is correct even when
the peer's FIN arrives 1.2 s late. Zero bad checksums throughout. The
monitor was screenshotted under live load showing connections moving
through TIME_WAIT and being reclaimed. Builds clean on x86_64, aarch64
and armv8i.
Known limit: 32 connection slots with a 2 s TIME_WAIT linger means
sustained rates much above ~16 requests/second can transiently exhaust
the table; it recovers on its own as entries expire.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Fh5z6V7nGPbHvqVG5p4CXX
A new desktop app whose whole point is to say sorry, and to look like
saying it took effort. Nothing in it is a static bitmap.
The heart is the classic parametric heart curve, x = 16sin^3(t) and
y = 13cos(t) - 5cos(2t) - 2cos(3t) - cos(4t), precomputed as a 96-point
integer polygon normalised to a half-width of 1000 and scanline-filled at
whatever size the beat currently has it at. Even-odd crossing counting is
what keeps the notch between the lobes open. The beat is a two-thump
cardiac envelope -- a strong systolic beat and a softer echo -- and the
fill carries a vertical gradient, a soft specular highlight on the upper
lobe, and a six-layer glow. The kernel is built -mno-sse with no floating
point, so every curve, gradient, easing and physics step is integer-only
and needs no trigonometry at runtime.
Around it: three apology letters that type themselves out a character at
a time, and a slow drift of small hearts using the same fill routine.
Answering "I forgive you" brightens the heart and bursts the drift
outward; answering "Not yet" dims it, slows the beat, and starts an
honest count of how long it has been waiting. Neither answer is an exit.
Supporting changes, all of them general rather than app-specific:
- gui_desktop_request_animation_frame(), so an app can opt into
full-rate recompositing instead of the ~10 Hz live-content
heartbeat. It is renewed per paint, so it lapses by itself when the
app stops animating or its window closes.
- gui_button_styled() and gui_hitzone() in SUB-WT, letting an app with
its own palette keep the toolkit's click handling. gui_button_colored
is now a thin wrapper over the former.
- A heart glyph in the icon set.
The glow layers skip whatever the heart body is about to cover, which
cuts their blended-pixel cost by roughly 3.5x and pays for the extra
layers that turn contour rings into a smooth halo.
Verified in QEMU on x86_64: all three states driven by real clicks --
hover, forgiveness (brighter heart, burst, live typewriter) and waiting
(dimmed heart, slower beat, running counter). Builds clean on x86_64,
aarch64 and armv8i.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Fh5z6V7nGPbHvqVG5p4CXX
Kernel (C++17 freestanding):
- New Analytics Engine (kernel/cpp/cpp_analytics.cpp): templated rolling
time-series (TimeSeries<N>) sampling four live channels -- CPU load %,
memory %, kernel-heap %, network pkt/interval -- with windowed statistics
(min/max/mean/stddev) computed in pure integer math (kernel is -mno-sse, so
no FP; stddev uses a Newton integer isqrt). Demonstrates virtual dispatch
via an Observer pattern (IAnalyticsObserver + a ThresholdAlarmObserver that
counts breaches) and RAII singletons.
- Extended cpp_containers.hpp with Optional<T>, Pair<A,B>, and the kmin/kmax/
kclamp/kswap algorithms.
- Full C fallback (cpp_fallback.c) so the engine is functionally identical on
aarch64/armv8i, which don't build the .cpp path.
- Wired cpp_analytics_init() into boot [8/14]; seeds a few samples so graphs
are populated immediately.
GUI:
- New "Analytics" desktop app (gui/gui_apps.c): a 2x2 grid of live line-charts
backed by the C++ engine, each with gridlines, a soft baseline fill, and
min/avg/max(/stddev) overlays; click a panel to focus one channel full-size,
click again to return. Throttled to ~2 Hz sampling off the compositor's
repaint cadence. Registered on the desktop and in the start menu.
Userland: new `cppstat [samples]` applet dumps the engine's per-channel stats
and Observer breach counters.
Verified in QEMU (x86_64): boots clean on x86_64/aarch64/armv8i; `cppstat`
prints live stats (CPU 6%, Mem 7%, Heap 22%, computed min/avg/max/stddev,
Observer breaches); the GUI Analytics window renders all four graphs with the
Kernel Heap curve visibly climbing 22->55% as windows open, compositor steady
at ~53 FPS.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Fh5z6V7nGPbHvqVG5p4CXX
Kernel (NT I/O subsystem):
- kernel/nt/io.c + include/kernel/nt/io.h (new): DRIVER_OBJECTs with a
MajorFunction dispatch table, DEVICE_OBJECTs that can be stacked (attached),
and IRPs pushed down the stack via io_call_driver / completed with
io_complete_request. Ships three demo drivers: \Driver\Null (write sink,
EOF reads), \Driver\Zero (zero-filled reads), and \Driver\Monitor -- a filter
attached above \Device\Null that counts and forwards each IRP down the stack.
Wired into the [12/14] boot step.
- LazyBox `iodev` lists drivers/devices with the stack and IRP counters, then
runs a live demo: a WRITE IRP through the filtered Null stack and a READ from
the Zero device.
GUI:
- gui/gui_apps.c: "Registry Editor" -- navigate the NT \Registry hive tree,
click subkeys to descend and ".." to go up, with a values pane showing each
value's name/type/data. Registered in the app table (start menu).
Verified live in the GUI terminal (screenshotted): 3 drivers / 3 devices, the
NullMonitor->Null device stack, a 16-byte WRITE sunk through the filter
(status 0x0), and an 8-byte zeroed READ from \Device\Zero. Clean build on
x86_64/aarch64/armv8i; 0 panics / 0 OOM.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Fh5z6V7nGPbHvqVG5p4CXX
Kernel (NT Configuration Manager):
- kernel/nt/reg.c + include/kernel/nt/reg.h (new): a hive/key/value registry
rooted at "\Registry", with typed values (REG_SZ/DWORD/QWORD/BINARY/MULTI_SZ,
type codes matching Win32). reg_create_key/reg_open_key walk backslash paths;
setters/getters, enumeration, and value->string rendering. reg_init() seeds
\Registry\Machine (Hardware, System\CurrentControlSet\Control, Software\SUB-OS)
and \Registry\User\.DEFAULT. Wired into the [12/14] boot step.
- LazyBox `reg query|add|set|stats` explores and edits the registry.
GUI:
- gui/gui_apps.c: "Object Browser" -- a WinObj-style live tree view of the NT
object namespace (\), flattening directories/events/semaphores/mutants with
indentation, per-type colouring, ref/handle counts, live object/handle stats,
and click-to-scroll. Registered in the app table (start menu).
Verified live in the GUI terminal (screenshotted): registry reports 13 keys /
11 values; `reg query \Registry\Machine\Software\SUB-OS` lists Version,
BuildArch (REG_SZ), GrowableHeap/ObjectManager (REG_DWORD) and InstallCookie
(REG_QWORD) with correct types. Clean build on x86_64/aarch64/armv8i; 0 panics.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Fh5z6V7nGPbHvqVG5p4CXX
Rust kernel expansion:
- rust/src/compress/mod.rs (new): memory-safe PackBits-style run-length
encoding codec (rle_compress / rle_decompress) with C-ABI shims, registered
in lib.rs. C fallbacks added to rust_fallback.c so aarch64/armv8i match.
- include/kernel/rust.h: FFI declarations for the codec.
- LazyBox: new `rle <text>` applet that compresses, decompresses, prints the
ratio and verifies the round-trip is lossless.
GUI expansion:
- gui/gui_apps.c: "Rust Lab" app -- a live dashboard for the Rust subsystem.
Shows CRC-32C/Adler-32 of a sample, measured ChaCha20/SHA3-256/AES-128
throughput as scaled bars plus a composite score (benchmark run once at
launch and cached), and a live ChaCha20 CSPRNG byte stream refreshed
periodically. Per-window state freed on close.
- Registered "Rust Lab" (info icon) in the desktop app table and on the
desktop; desktop icon indices updated for the new entry.
Verified: clean build on x86_64/aarch64/armv8i; boots through the SUB login to
the desktop with the new Rust Lab icon rendering (screenshotted); checksum
self-test prints, 0 panics / 0 OOM.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Fh5z6V7nGPbHvqVG5p4CXX
Rust kernel expansion:
- rust/src/checksum/mod.rs (new): memory-safe CRC-32C (Castagnoli), Adler-32,
and FNV-1a-64 with thin C-ABI shims. Registered in lib.rs with a boot-time
self-test (crc32c("SUB-OS")=0x61e96ce9, verified against a reference impl).
- include/kernel/rust.h: FFI declarations; rust/rust_fallback.c: matching C
fallbacks so aarch64/armv8i (no native rustc target) get identical results.
- LazyBox: new `cksum <text>` applet printing all three via the Rust engine.
GUI expansion:
- gui/gui_apps.c: Conway's Game of Life -- an interactive B3/S23 cellular
automaton with Play/Pause/Step/Random/Clear toolbar, click-to-toggle cells,
a live generation/population readout, and a board that scales with the
window. The Random button seeds from the Rust ChaCha20 CSPRNG. Toolbar and
cell input are gated on the MOUSE_DOWN edge so they do not re-fire while held.
- Registered "Life" (flask icon) in the desktop app table and on the desktop.
Verified: clean build on x86_64/aarch64/armv8i; boots through the SUB login to
the desktop (screenshotted) with the checksum self-test and 0 panics/0 OOM.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Fh5z6V7nGPbHvqVG5p4CXX
The GUI terminal recognised four hardcoded strings and answered everything else
with "Executed: '<cmd>'". It now dispatches to the same LazyBox applet table and
shell builtins the kernel TTY uses, so ls, free, uname, lspci, ktest, neofetch,
sort, cd and the rest all work, with cwd tracked across commands.
LazyBox reports through printk, so before running a command the terminal
installs a printk sink and streams the output into its own scrollback:
- ANSI SGR codes become per-line colours instead of being stripped.
- CP437 box-drawing and block characters fall back to ASCII, so the colour
swatch in neofetch renders as '#' rather than a row of '?'.
- 256 lines of scrollback, command history on Up/Down, PgUp/PgDn/Home/End.
- Applets that read the keyboard directly (nano, snake, sh, top) are refused
with a pointer to the TTY, since they would block the compositor.
The window's paint and event handlers moved out of gui_apps.c into
gui/gui_terminal.c, and gui_gfx.c now draws from the shared lib/font8x8.c table
rather than its own copy.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01L5yKJT4Wo2cV3rfPrwY5MP
- Create separate feature branch 'feat/gui-desktop'
- Implement double-buffered 2D graphics engine with alpha blending, gradients, rounded rects, and font rasterization in gui/gui_gfx.c and include/gui/gui_gfx.h
- Implement alpha-blended mouse pointer overlay in gui/gui_cursor.c and include/gui/gui_cursor.h
- Implement SUB-WM Window Manager with draggable titlebars, close/minimize buttons, drop shadows, and event routing in gui/gui_wm.c and include/gui/gui_wm.h
- Implement Cyberpunk/Nord desktop environment with wallpaper, taskbar, start menu popup, and system tray in gui/gui_desktop.c and include/gui/gui_desktop.h
- Implement built-in GUI apps: System Performance Monitor, GUI Terminal Emulator, File Explorer, Calculator, Paint Studio, and About dialog in gui/gui_apps.c and include/gui/gui_apps.h
- Add 'startx', 'gui', and 'desktop' applets in LazyBox suite
- Verified multi-architecture compilation across x86_64, AArch64, and ARMv8i