diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-29 19:25:00 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 00:12:17 -0300 |
| commit | 57b30ba3e38153a4446626449b0fed5120da954c (patch) | |
| tree | 7b9381327a05791181a855bd8d4ba3cfb4df5301 /docs/cloud9.md | |
| parent | 0fd908eea63d04886b269438aa7529d3dd422256 (diff) | |
| download | pardes-57b30ba3e38153a4446626449b0fed5120da954c.tar.gz pardes-57b30ba3e38153a4446626449b0fed5120da954c.zip | |
The docs and the 9P skill say each fact once, in the file that owns it, and say only what a live session does
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'docs/cloud9.md')
| -rw-r--r-- | docs/cloud9.md | 139 |
1 files changed, 39 insertions, 100 deletions
diff --git a/docs/cloud9.md b/docs/cloud9.md index 7365bf65..cd92fd05 100644 --- a/docs/cloud9.md +++ b/docs/cloud9.md @@ -1,107 +1,46 @@ -# cloud9 integration +# cloud9 -The published `cloud9` package owns the base 9P2000 wire format, client and server -connections, and TCP/Unix/QUIC transports. `build.zig.zon` pins a commit from -`[email protected]:~gbrls/cloud9`, so `zig build` fetches it into `zig-pkg/` like every -other dependency; no sibling checkout is required. Re-pin with -`zig fetch --save=cloud9 git+https://git.sr.ht/~gbrls/cloud9#<commit>`, and swap in -`.cloud9 = .{ .path = "../cloud9" }` while editing both packages at once. +The `cloud9` package owns the 9P2000 wire format, client and server +connections, the file-server engine and the Unix/TCP/QUIC transports. +`build.zig.zon` pins a commit from `git.sr.ht/~gbrls/cloud9`, fetched into +`zig-pkg/` like any dependency. Re-pin with +`zig fetch --save=cloud9 git+https://git.sr.ht/~gbrls/cloud9#<commit>`, or +use `.cloud9 = .{ .path = "../cloud9" }` while editing both. -The file-server engine (fids, jobs, parking, flush, hangup) is cloud9's -`fs.Server`; the control tree in `src/ninep/` is its backend, using cloud9's -`fs.Req`, `fs.Op`, `fs.Status`, `fs.E` and `fs.ReplyWith` (extended with the -editor's reply payload locator). `src/9p.zig` names the editor's and the -board's `fs.Options` and re-exports the wire names the transports use. -Mounting, Unix namespace discovery and permissions, the editor event loop, -connection limits, and exported tree policy remain here. The Unix and TCP -listeners run on cloud9's `serve.Runner` (`std.Io`: an accept task per -listener, a reader and a writer task per connection, four slots); its handler -answers every backend request on the connection's task, taking the editor's -turn with the core (`pardes.turn`) while the editor waits for input or is out -in a syscall. A request that would change a pane while the editor is mid-step -is parked with `Status.again` -- the engine parks reads, writes, opens, -truncations, clunks and removes -- and retried by `Runner.wakeAll` when the -editor next rests. A read with nothing yet parks the same way, but is never -retried for news: the core holds it (`ctlfs.hold`) and `answerHeld` answers -it through the ticket `Conn.hold` gave its park, with `Conn.answerWith`, -which makes the answer only while that very park still waits (not flushed, -its fid not clunked, not out being retried) and under the same lock. `src/9p_quic.zig` selects the existing `pardes-9p` ALPN for -cloud9's optional OpenSSL transport; QUIC still runs on the poll loop in -`src/9p_io.zig` on the editor's thread, since cloud9's QUIC adapter is -nonblocking-descriptor based rather than `std.Io` based. -The standalone protocol/GPIO tests import the same module. The separate -`05-zig-p4` build also supplies cloud9 for the GPIO firmware entry. +- The engine (fids, jobs, parking, flush, hangup) is cloud9's `fs.Server`; + the control tree in `src/ninep/` is its backend. `src/9p.zig` names the + editor's and the board's `fs.Options` (msize 8192, 256 fids). +- Unix and TCP listeners run on cloud9's `serve.Runner` (`std.Io`: an accept + task per listener, a reader and a writer task per connection, 16 + connections). Requests are answered on the connection's task, which takes + the editor's turn (`pardes.turn`) while the editor waits for input or is + out in a syscall. A request that would change a pane while the editor is + mid-step parks (`Status.again`) and is retried when the editor rests. A + read with nothing to answer yet is held by the core and answered through + the ticket `Conn.hold` gave it, only while that park still waits. +- QUIC (`src/9p_quic.zig`, ALPN `pardes-9p`) still runs on the editor's + poll loop in `src/9p_io.zig`, since cloud9's QUIC adapter is + nonblocking-descriptor based. -Run `zig build 9p-test` for the engine configurations and -`zig build 9p-io-test -Dquic=true` for native transport/client integration. Run cloud9's `zig build test`, -`transport-test`, `quic-test -Dquic=true`, `fuzz`, and `differential` steps for the -shared implementation. See cloud9's `docs/validation.md` for recorded runs and -known test-environment limits. - -Invalid framing now terminates a server connection. Cloud9 also checks reply -counts and reserves tags until flush completion. Client metadata is slightly -larger to track those reservations, and its bounds tests reflect that fixed cost. +Tests: `zig build 9p-test` (engine configurations), `zig build 9p-io-test +-Dquic=true` (transports and client). cloud9's own `zig build test`, +`transport-test`, `quic-test -Dquic=true`, `fuzz` and `differential` cover +the shared code. ## The posted-9P registry -`$XDG_RUNTIME_DIR/9p` is this machine's `/srv`: a server posts itself in it -under a name, and clients dial names rather than paths. cloud9 owns both -sides (`cloud9.post`), and `9ns --mntgen` mounts the whole registry at -`/mnt/9p` for programs that want it as a filesystem. pardes's only part in -it is to put itself there. - -**Serving.** A listening editor advertises itself at -`$XDG_RUNTIME_DIR/9p/pardes/<name>`, a symlink to the socket it already -binds. One directory for the program, one entry per editor, so several -editors group instead of crowding the registry root — the layout zmx posts -its sessions under. The socket itself does not move: adopting the registry -only advertises. Only the runtime-directory socket posts; an instance that -fell back to `~/.local/state/pardes` stays out of the user's registry, the -way a private `ZMX_DIR` does for zmx. Stopping unposts, and only while the -entry is still ours, so a name another editor has since claimed is never -unlinked. - -An exit that cannot run any code of its own — an aborted test, a kill, a -crash — leaves its entry and its socket behind, so posting first sweeps the -group: every entry that is a symlink and whose socket answers a connect with -a definite ECONNREFUSED is unlinked, along with the socket it points at when -a `stat` agrees that is a socket of ours. Anything that is not a symlink is -somebody else's, and any other answer — connected, busy, refused permission, -a surprise — counts as live, because uncertainty belongs to the server that -owns the socket rather than to the sweeper. That is `cloud9.post.Probe`'s -classification, repeated in `src/9p_io.zig` only because `post.probe` is raw -Linux syscalls and pardes also builds for darwin. - -**Consuming.** Nothing. `9ns --mntgen` mounts the whole registry at -`/mnt/9p`, and an interactive fish already self-wraps in one, so a pardes -started from a terminal sees every posted service as ordinary files — -`/mnt/9p/harness/active/...` is read with the same code that reads any other -path. Teaching pardes to dial the registry itself would put discovery in a -second place for no gain: mounting is the client's job and 9ns is the -client. `--mount=<name>=<dial>` keeps meaning exactly what it always did, -and a dial keeps resolving exactly as it always did — a bare name is another -pardes session, and anything with a slash is a path, relative ones included. - -The one case that is not free: a pardes started outside a mntgen mount has -no `/mnt/9p`. That is 9ns's problem to solve — by being in the namespace — -not a reason for pardes to carry its own registry client. - -### What this diverges from, deliberately +`$XDG_RUNTIME_DIR/9p` is this machine's `/srv`: servers post themselves +there by name, and `9ns --mntgen` mounts the whole registry (default +`/mnt/9p`). A pardes whose socket is in the runtime directory posts +`$XDG_RUNTIME_DIR/9p/pardes/<name>`, a symlink to its socket (one directory +per program, as zmx posts its sessions); a socket that fell back to +`~/.local/state/pardes` is not posted. Stopping unposts the entry if it is +still ours. Posting first sweeps the group: an entry that is a symlink whose +socket refuses a connect (ECONNREFUSED) is removed with its socket; anything +else counts as live. -* **pardes binds its own socket; it does not post through `cloud9.post`.** - `post` would give us its hardened claim protocol (temp-bind plus atomic - rename under a lock) instead of the stale-socket retry in `listen`, but it - claims *flat* names only: `legalName` rejects `/`, and `claimName` derives - its lock directory by stripping `/9p` from the registry path, so a name - inside a subdirectory cannot go through it. zmx hand-rolls the same - symlink for the same reason. Unifying them means teaching `post` a group — - passing the lock directory in rather than deriving it — and that is a - change to adversarially-hardened code, not a rename. -* **The registry entry is a symlink, not the socket.** A reader that expects - every registry entry to be a socket must `stat` following symlinks. - `9ns --mntgen` and `cloud9.post.dial` both do. -* **Dialing is untouched.** An earlier draft taught `resolve` to fall back - to the registry for a bare name and to read `<group>/<name>` as a - subdirectory entry. Both were reverted: the second reinterpreted relative - dials, which are a feature, and the first duplicated what 9ns already - does. `src/9p_io.zig`'s `resolve` is byte-identical to what it was. +pardes does not dial the registry: `9ns` is the client, and `--mount` dials +resolve as always (a bare name is a pardes session, anything with a slash a +path). pardes binds its own socket instead of posting through `cloud9.post`, +because `post` takes only flat names and pardes posts into a group +directory. A reader of the registry must `stat` through the symlink. |
