Files
danos/library/client/build.zig
T
Daniel Samson d2dfbcabf8 library: five protocols speak the envelope
The folded header stops being a rule in a document and becomes the layout
on the wire. Verbs number from sixteen, leaving describe, enumerate,
subscribe and unsubscribe reserved and answered the same way by every
provider — none of them writes a line to do it. What each protocol used to
carry in a field of its own now travels in the header: a vfs node and a
display layer are the packet's target, and a reply opens with a status the
envelope stamps rather than one each protocol spelled for itself.

Display gains the most. One forty-byte request had served eleven verbs, so
attach_scanout smuggled stride through x, refresh through y and format
through colour, and every coordinate crossed as a bitcast. Per-operation
structs end all three: the fields have their own names and their own signs,
and the tile payload grows to 224 bytes because the prefix shrank. Scanout
loses a message maximum of 64 it had no business declaring — it answers
calls, and the floor for a call is 256 — and virtio-gpu stops hard-coding
that number at its harness.

Two changes are semantic rather than notational. A directory now ends at an
entry with no name, because the fixed part of a reply always travels and a
zero-length reply no longer exists to mean anything. And input joins the
service harness, the last loop in the tree that answered no ping and heard
no terminate; its subscriber table, its pruning and its fan-out are the
same code, and a shutdown now asks it to stop instead of killing it.

A new conformance case reads the registry's own listing and asks every
protocol it finds for its name, its version and its verb count, then offers
a verb nobody defines and requires -ENOSYS — the envelope's promise,
checked against providers rather than against itself. What it cannot reach
in that boot it names on the serial line instead of passing quietly.

Suite 110/110.
2026-08-01 06:15:25 +01:00

51 lines
2.2 KiB
Zig

//! The "client" library domain (library/client): userspace-service clients —
//! they talk to services over IPC, not to the kernel. Client modules end in
//! `-client` the way wire protocols end in `-protocol`, so a service, its
//! protocol, and its client never share a name (`display` the service,
//! `display-protocol` the wire contract, `display-client` a program's view).
const std = @import("std");
pub fn build(b: *std.Build) void {
const kernel = b.dependency("kernel", .{});
const protocol = b.dependency("protocol", .{});
const ipc = kernel.module("ipc");
const time = kernel.module("time");
// Every client reaches its service by name now: resolve `/protocol/<name>`,
// open it, and take the provider's endpoint out of the reply
// (docs/os-development/protocol-namespace.md).
const channel = kernel.module("channel");
// A client frames its own packets, so it needs the envelope alongside the
// protocol whose verbs it speaks.
const envelope = protocol.module("envelope");
_ = b.addModule("display-client", .{
.root_source_file = b.path("display/display-client.zig"),
.imports = &.{
.{ .name = "channel", .module = channel },
.{ .name = "envelope", .module = envelope },
.{ .name = "ipc", .module = ipc },
.{ .name = "time", .module = time },
.{ .name = "display-protocol", .module = protocol.module("display-protocol") },
},
});
_ = b.addModule("input-client", .{
.root_source_file = b.path("input/input-client.zig"),
.imports = &.{
.{ .name = "channel", .module = channel },
.{ .name = "envelope", .module = envelope },
.{ .name = "ipc", .module = ipc },
.{ .name = "time", .module = time },
.{ .name = "input-protocol", .module = protocol.module("input-protocol") },
},
});
// Standalone `zig build test`, kept for uniformity across the domains (the
// root aggregate depends on every domain's test step). The clients have no
// host-runnable unit tests yet — they are thin IPC conversation wrappers —
// so the step is empty until one grows some.
_ = b.step("test", "Run the client unit tests (none yet)");
}