Commit graph SchOS/docs/plan/roadmap.md
Author SHA1 Message Date
Nexoniarz
d3c37f82b6 docs: the tree moved and the documentation did not
The site and several documents still described the system as it was before
virtual terminals, the new schinit, the hybrid work and descriptor passing.

docs/architecture/init.md described the wrong program. It documented a single
schinit that parses manifests and supervises jobs, which has not been true since
PID 1 was split: PID 1 forks a supervisor, spawns jobs on its behalf and reaps;
the job table lives in /proc/schinit; a heartbeat runs both ways; and
proc_reincarnate() re-execs PID 1 in place rather than panicking. Rewritten
around what exists, keeping the reasoning that is still load-bearing -- the five
failures of the sibling-init scheme, the escalation ladder, and the three bugs in
the reincarnation path that each had to happen before they were obvious.

docs/plan/init.md is deleted, which is the tree's own rule for finished work and
had not been applied. Fourteen source comments referenced it by part number, so
they are repointed at the architecture doc by section name rather than left
dangling -- a deleted document nobody notices is worse than a stale one.

docs/architecture/devices.md gained the section it has been missing since
/dev/pci existed: what a driver needs from a kernel, why mmap is checked against
the caller's claims, why DMA is a call and not a mapping, and why the write back
after an interrupt is not optional. Also that a released device does not come
back by itself, which is true and was nowhere.

docs/architecture/networking.md gained a descriptor-passing section, and
docs/architecture/README.md's stack diagram gained the two layers and the third
seam it was missing. "Two seams hold the whole thing together" has not been true
since /dev/pci.

docs/plan/README.md said the hybrid work was deliberately last, on the argument
that an interface with no consumer is wrong in ways nobody can see. The argument
was right; the conclusion was not, and the document now says why it changed --
the alternative to a driver compatibility layer is writing a driver for every
device that exists, and the original objection is answered rather than ignored
because SchOS's own drivers are the consumers.

The site: a Hybrid section with the eviction transcript, cards for virtual
terminals, schinit and drivers outside the kernel, and the numbers remeasured
rather than estimated -- 46,961 lines, 207 syscalls. The boot log in app.js is
from a boot taken today, and the lines are trimmed to what the console can show
without clipping, each still a verbatim prefix of real output.

Two small rendering fixes found by looking at the pages rather than assuming:
.console pre's min-height is now scoped to the hero, so a static transcript sizes
to its content instead of reserving eight lines it does not have; and the docs
reader's contents panel strips inline marks from headings, so a heading written
`proc_reincarnate()` no longer carries its backticks into the sidebar.

Every intra-doc link checked; none broken.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VQ7Qx8E1q1M1bbCq8QLHS2
2026-09-13 20:05:06 +02:00
Nexoniarz
3034efd300 net: a frame wakes the stack, instead of waiting for the clock
The network thread waited on the timer and nothing else, so a frame that landed
just after a poll sat in the ring for up to 10 ms -- the largest fixed latency in
the system. That was deliberate when the stack was new (a receive path woken by
an interrupt is much harder to debug than one that is asked) and there is now a
working stack to compare against, which is exactly when it becomes safe to do.

The frame is still *pulled* by the thread through .receive. It has to be: a call
into lwIP can reach the driver, the driver can sleep on the buffer cache, and an
interrupt handler may do neither. netdev_rx_signal() delivers nothing and reads
no ring -- it only ends the wait early.

The wait stays on the timer tick rather than moving to a channel of its own, and
that is the design. lwIP's timers must still run when the link is silent, so the
clock has to remain a floor under the wait, and sleep() cannot wait on two things
at once. Joining the tick's existing wakeup costs nothing and leaves one wait
with one predicate.

rx_signal lives under tickslock for the same reason it gets no lock of its own:
sleep() releases tickslock atomically, so a driver setting the flag and waking
under that lock cannot lose the wakeup by arriving between the predicate test and
the sleep. A private lock would not be held across the sleep, and that window
would be back. Calling it from interrupt context is safe on the same terms the
timer handler already relies on -- acquire() disables interrupts, so a CPU
holding tickslock cannot be interrupted into it.

The e1000 signals on RXT0 (a frame or burst has landed) and RXDMT0 (the ring has
fallen below its threshold, which is when waiting for the clock hurts most).

Measured rather than asserted: /proc/netif reports wake_rx and wake_tick, and
across three pings rx_frames and wake_rx both went 2 -> 6 -- every received frame
woke the thread through the interrupt. wake_tick keeps advancing as the idle
floor, which is what lwIP's timers need. socktest still passes and ping is still
0% loss.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VQ7Qx8E1q1M1bbCq8QLHS2
2026-09-12 17:23:46 +02:00
Nexoniarz
57aff40228 docs: four directories, and a rule for when a thing leaves the roadmap
docs/ was ten files where a plan, a description, a guide and a bug report all
sat next to each other. It is now architecture/ (what SchOS is), plan/ (what it
will be), guides/ (how to work on it) and history/ (why it is like this), with
an index that states the one rule holding it together: when something is
finished it moves from plan/ to architecture/ and is rewritten as a description
of the thing rather than a record of building it.

A ticked checkbox says the work happened. It does not say what the work
*produced*, and six months later the checkbox is all that is left. The network
stack proved the point: finished, verified end to end, and for a month the only
description of it anywhere was a checkbox four levels of indentation deep.

So roadmap.md went from 534 lines to 181 -- nothing deleted, the done work
graduated. Seven subsystems that were finished and undescribed now have
descriptions: boot, kernel, syscalls, filesystem, networking, graphics, usb,
init. Every one ends with "What it does not do", which is the section that pays;
a document listing only strengths is marketing, and the reader who needs it most
is the one about to trip over a limitation nobody wrote down.

schfs.md still opened with "phases 1 through 3 1/2 are done, phase 4 is next"
long after all five had landed. It is a description now, with the phase record
and the hard-won bugs moved to history/.

Three corrections found on the way, all load-bearing:

  * projects/schcom/README.md claimed SCM_RIGHTS was done. There is no
    sendmsg/recvmsg in the kernel at all, and an entire GUI plan rested on it.
  * The root README said "No TCP/IP" months after the stack landed.
  * history/kernel.md sec.7 was marked "in progress" on a problem that process
    groups solved.

Also adds plan/1.0.md, which draws a finish line so the open list stops being
infinite, and marks schwm/ and schde/ superseded: in Wayland the compositor is
the window manager, so that split dissolves rather than being abandoned.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VQ7Qx8E1q1M1bbCq8QLHS2
2026-09-12 17:13:35 +02:00