diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-20 02:33:02 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-09-20 02:33:02 -0300 |
| commit | ba7ec40782ba7020d82a56896a5eb1b52578d6aa (patch) | |
| tree | b6a5222d124255ae1e5d568c6ffbfe2e2050ae63 /docs | |
| parent | 66f2e492c348677ab3050f5e378b9eb4c04c98ce (diff) | |
| download | cloud9-ba7ec40782ba7020d82a56896a5eb1b52578d6aa.tar.gz cloud9-ba7ec40782ba7020d82a56896a5eb1b52578d6aa.zip | |
Add cloud9.serve: an std.Io runner around the file-server engine
Runner(Backend, Options, Limits) listens on Unix or TCP, runs a reader and a
serve task per connection in one Io.Group, pushes frames into an fs.Server,
and lets the backend answer now or later from any task or thread (reply,
flush, wake); Tflush, greet timeout, connection limit, close and stop with
cancellation are covered by tests over real sockets. The engine and the
backend contract stay Io-free, so the push/step mode for freestanding
targets is unchanged. Documented as the two ways to drive the engine.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/design.md | 47 |
1 files changed, 46 insertions, 1 deletions
diff --git a/docs/design.md b/docs/design.md index 8387a4d..3ad9338 100644 --- a/docs/design.md +++ b/docs/design.md @@ -130,6 +130,49 @@ engine allocates nothing and makes no OS calls; a session is `push()`, `retry()`, `next()`, `reply()`, `output()`, `wrote()`; `fidCount()` counts the fids held. +# Io runner + +There are two ways to run the engine. A freestanding target, or an +application with its own event loop, drives it directly: `push()` bytes in, +answer every `retry()` then every `next()` request through `reply()`, drain +`output()` and report `wrote()`, on whatever thread and schedule it likes +(the board firmware and the 9proc probe do this). A hosted target may +instead hand the engine to `serve.Runner(Backend, Options, Limits)`, an +`std.Io` adapter beside `http`: it owns listeners (`listen()` takes a +`transport.Address`, Unix or TCP, up to `Limits.listeners`), a table of +`Limits.connections` slots with their buffers (`Limits.msize` sizes them; a +connection past the table is accepted and closed), and two tasks per +connection in one `Io.Group`, one reading frames with `transport.readFrame` +and pushing them in, one stepping the engine and writing its output with +the stream's writer. The engine and the backend contract are untouched by +it, and it makes the engine no less Io-free. + +The backend is reached through a `Handler`: `serve(ctx, conn, req)` runs on +the connection's task with the engine unlocked and answers with +`Conn.reply()`, at once or later from any task or thread, or takes the +engine over between `Conn.lock()` and `Conn.unlock()`, drives `next()`, +`retry()` and `reply()` itself and calls `Conn.flush()` so the connection +task sends what that produced (the editor answers on its own thread this +way). `opened` and `closed` bracket a slot's life; `Conn.user` is the +application's. + +Wake-up is explicit. Each connection has a flag word and an `Io.Event`; the +reader raises "input", `reply()` and `flush()` raise "output", `Conn.wake()` +(or the runner's `wakeAll()`) raises "retry", and the connection task steps +the engine on every signal, retrying parked requests only for "retry". That +keeps a backend that answers `Status.again` from being polled by its own +replies: it is asked again when it says it has news. Tflush goes through the +engine as always. A connection ends on EOF, a read or write error, a +protocol error (`protocol.dead`), `Conn.close()`, the optional greet +timeout (`InitOptions.greet_timeout_ms`: no Tversion in time) or `stop()`; +the runner then calls `hangup()`, pays the backend every release `next()` +still yields through `serve`, closes the socket and frees the slot. +`stop()` cancels the group (`Io.Group.cancel` interrupts the blocking +accepts and reads), joins every task and closes the listeners; a `serve` +that waits on another thread must stop waiting once `stop()` has begun. +Unix socket paths are the application's: the runner neither unlinks, +chmods nor removes them. + # Related programs Programs built on the library ship from this repository as `cloud9/<name>/`, @@ -151,7 +194,9 @@ Pardes consumes the sibling package through build.zig.zon. Its control tree (`src/ninep/`) is an `fs.Server` backend using the contract types above; its `src/9p.zig` names the editor's and the board's `fs.Options`. `src/9p_io.zig` retains mounting, discovery, the editor's event-loop scheduling, -connection limits, and error presentation. Protocol bytes, session validation, +connection limits, and error presentation; its Unix and TCP listeners run on +`serve.Runner` with a handler that hands each request to the editor's thread, +while QUIC keeps its own poll loop. Protocol bytes, session validation, the file-server engine, and TCP/Unix/QUIC transport implementation come from cloud9. Pardes selects the existing `pardes-9p` ALPN for compatibility. |
