SchOS/docs/plan/foundations.md
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

5.6 KiB
Raw Blame History

Foundations

The kernel work that wayland.md and hybrid.md both stop at. This is the critical path, and it is the reason those two are one plan rather than two.

The insight is small and it decides the schedule: the substrate for passing a buffer to a compositor and the substrate for handing a device to a driver process are the same substrate. Descriptor passing and shared memory, built once.


What is actually in the tree

Measured against the source, not against a README. Each of these was checked before anything below was planned around it:

sendmsg/recvmsg, and therefore SCM_RIGHTS Do not exist. Not in kernel/sys/table.inc, not anywhere in kernel/.
Writable MAP_SHARED of a file Refused — kernel/sys/sys_mem.c:131 returns -ENODEV.
memfd_create Does not exist.
AF_UNIX names In a table in kernel/net/unix.c, not in the filesystem.
setsockopt return 0; unconditionally — kernel/sys/sys_net.c:436.
exec ET_EXEC only. No PT_INTERP, no ET_DYN.

projects/schcom/README.md says SCM_RIGHTS is done. That line is wrong, and it is the most load-bearing wrong line in the tree — an entire GUI plan was drawn on top of it. It is corrected as part of this work.

The MAP_SHARED refusal is worth defending rather than fixing carelessly. The code returns -ENODEV honestly: the contract of a writable shared mapping is that stores land in the file and other mappers see them, and there is no page cache that could make that true. Quietly handing back a private copy would be the same lie in a new place.


The five items

In dependency order. The first three are what Wayland cannot start without.

1. sendmsg / recvmsg with SCM_RIGHTS

Not optional and not substitutable. wl_shm_create_pool passes a file descriptor; there is no path in the Wayland protocol that passes an integer instead.

The handle_kind field in projects/schcom/proto.h was good foresight and it cannot help here — our protocol is the flexible one, and Wayland's is not.

Needs: struct msghdr/cmsghdr handling, ancillary data queued alongside the byte stream in kernel/net/unix.c, descriptor installation into the receiver's file table, and correct behaviour when a message carrying descriptors is never received (they must be closed, not leaked).

This is also item 1 of the hybrid work, where it is how a driver process is handed the device it is allowed to touch.

2. A shareable memory object

memfd_create, plus mmap(MAP_SHARED) on it genuinely working between two processes.

Narrower than a general page cache, and sufficient. An anonymous shared object needs no file behind it, which is exactly why memfd exists on Linux at all — and it means this can be built on the shared-memory machinery already in kernel/sys/sys_mem.c (shmget/shmat/shmdt work, and struct vma already carries shmid and a no_free flag for pages that are not ours to release).

The general answer — a page cache, and writable MAP_SHARED of a real file — stays owed. It is a larger project and nothing on this plan needs it.

3. AF_UNIX sockets in the filesystem namespace

Clients find a Wayland compositor by bind()ing $XDG_RUNTIME_DIR/wayland-0 as a real path, and libwayland flock()s the lock file beside it. A name table can express neither.

kernel/net/unix.c's own header comment already predicted this:

"What is lost is ls -l /tmp/schcom showing an s, and unlink() of a socket path failing with ENOENT. Both are worth fixing when the VFS next gets opened up; neither blocks anything."

They block something now. This is that moment, and it is a VFS change rather than a socket change: a socket inode type threaded through iget, dirlookup and stat, plus flock.

4. setsockopt that does not lie

At minimum SO_PASSCRED and SO_SNDBUF. Returning 0 for an option you ignored is worse than ENOPROTOOPT, because the caller adjusts its behaviour on the strength of the lie.

Small, and grouped here because it is in the same file as item 3 and will be found by the same testing.

5. Dynamic linking

PT_INTERP and ET_DYN in kernel/fs/exec.c.

Deferrable, and deferred. Static binaries are enough to reach a working desktop with software rendering. This becomes necessary when Mesa does — EGL means dlopen means a loader — and that is a separate decision made later.


Verification

Each item gets a test before the thing that needs it is built, because a substrate that is subtly wrong fails inside the consumer and looks like the consumer's bug.

  • Item 1: two processes, one passes an open descriptor, the other reads through it. Plus the leak case: a sender that exits with descriptors in flight.
  • Item 2: two processes map the same memfd, one writes, the other sees it.
  • Item 3: bind() a socket, then stat() and ls -l the path and see an s, then unlink() it.
  • Items 1–3 together: a third test that does all of it at once, because that combination is what Wayland actually performs and the three passing separately does not prove it.

These belong in bootcheck as a new switch, following the -Sock model.


What this does not deliver

  • No page cache, so writable MAP_SHARED of a real file stays refused.
  • No dlopen until item 5 is done, which means no Mesa and no third-party shared libraries.
  • SO_* coverage is the two options named, not the full set.
  • No credential passing (SCM_CREDENTIALS) — only descriptors. Nothing on this plan needs it, and a compositor that wants to know who connected will.