library: the envelope — one packet shape for every protocol
A protocol is now defined through envelope.Define rather than beside it.
Every packet begins with the same 16-byte prefix: a Header of {operation,
target} for a request or event, a Status for a reply. The header is folded
into each protocol's own layout, never stacked on top of it — Define walks
a spec's types and refuses one that carries a Header or Status field, so
the rule cannot be missed by reading. Operations number from 16, leaving
describe, enumerate, subscribe and unsubscribe reserved and answerable the
same way everywhere; describe the envelope answers itself, and an unknown
verb is -ENOSYS without a provider writing a line.
The size floor becomes something protocols can compile against: 256 bytes
for a call, 64 for a push, matching the kernel's own limits, checked at the
Define call with the prefix counted in. A protocol that outgrows either
fails the build with the reason and the remedy — shrink, or move the bulk
to shared memory, because packets never fragment. Events carry the header
too and number in their own space, so appending an operation can never
renumber a shipped event.
Beside it, the client half of the model: a Channel is what opening a
/protocol name yields, wrapping the endpoint capability so a program holds
a conversation rather than a handle. Nothing speaks through either yet —
the vfs protocol gains NodeKind.protocol and the convention that an open
reply may carry a capability, and that is the whole runtime change.
Suite 107/107, unchanged: P1 converts nothing.
This commit is contained in:
@@ -13,8 +13,17 @@
|
||||
//! written against has retired — path routing moved into the kernel (system/kernel/vfs.zig,
|
||||
//! fs_resolve) — but the protocol module outlived it.
|
||||
|
||||
//! **An `open` reply may carry a capability.** The vfs `open` request rides
|
||||
//! `ipc_call`, and the reply direction of a call can hand back an endpoint
|
||||
//! (`ipc.callCap`'s `Reply.cap`). A file backend never uses it — FAT answers
|
||||
//! with a node id and nothing else — but a *synthetic* backend does: opening a
|
||||
//! `NodeKind.protocol` node under `/protocol` returns the provider's endpoint,
|
||||
//! which is the channel (docs/os-development/protocol-namespace.md). The
|
||||
//! convention is per-backend, not per-operation: a client that did not ask a
|
||||
//! synthetic backend simply gets no capability back, exactly as today.
|
||||
|
||||
pub const Operation = enum(u32) {
|
||||
open, // open(path) -> node id
|
||||
open, // open(path) -> node id (a synthetic backend may reply with a capability instead)
|
||||
close, // close(node)
|
||||
read, // read(node, offset, len) -> bytes
|
||||
write, // write(node, offset, bytes) -> count
|
||||
@@ -44,6 +53,12 @@ pub const NodeKind = enum(u32) {
|
||||
symbolic_link = 4,
|
||||
fifo = 5,
|
||||
socket = 6,
|
||||
/// A node that names a *contract*, not a file: opening it establishes a
|
||||
/// channel to whatever process currently provides that protocol, delivered
|
||||
/// as an endpoint capability in the reply rather than a node id. This is
|
||||
/// what lives under `/protocol`; `readdir` lists these like any other node,
|
||||
/// so the tree stays browsable for diagnosis.
|
||||
protocol = 7,
|
||||
};
|
||||
|
||||
/// One directory entry, returned by `readdir`: a fixed header followed inline in
|
||||
@@ -109,6 +124,9 @@ test "protocol struct sizes and node kinds" {
|
||||
const std = @import("std");
|
||||
try std.testing.expectEqual(@as(u32, 0), @intFromEnum(NodeKind.regular));
|
||||
try std.testing.expectEqual(@as(u32, 1), @intFromEnum(NodeKind.directory));
|
||||
// Appended with the protocol namespace; every earlier value keeps its own.
|
||||
try std.testing.expectEqual(@as(u32, 6), @intFromEnum(NodeKind.socket));
|
||||
try std.testing.expectEqual(@as(u32, 7), @intFromEnum(NodeKind.protocol));
|
||||
try std.testing.expectEqual(@as(usize, 16), @sizeOf(DirectoryEntry));
|
||||
// The appended operations keep the original values.
|
||||
try std.testing.expectEqual(@as(u32, 0), @intFromEnum(Operation.open));
|
||||
|
||||
Reference in New Issue
Block a user