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
135 lines
5.6 KiB
Markdown
135 lines
5.6 KiB
Markdown
# Foundations
|
||
|
||
The kernel work that [wayland.md](wayland.md) and [hybrid.md](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.
|