C2: migrate consumers off the runtime shim to direct concern-module imports

Every user binary and the two device-logic library modules (pci, usb) now
`@import` the concern modules directly instead of aliasing through `runtime`:

  runtime.ipc/process/time/service/input/block/display  -> @import("<module>")
  runtime.device / runtime.device_manager               -> @import("driver")
  runtime.fs                                             -> @import("file-system")
  runtime.Thread                                         -> @import("thread").Thread
  runtime.system.{write,writeRecord,klog*}              -> logging.*
  runtime.system.{sleep,timerOnce,wallClock,clock}     -> time.*
  runtime.system.{spawn*,kill,exit,yield,processes,...}-> process.*
  runtime.system.{mmap,munmap,PROT_*}                  -> memory.*
  runtime.dma.* / runtime.shared_memory.* / runtime.allocator -> memory.*

Each consumer keeps its own alias name (e.g. `const device = @import("driver")`),
so call sites are unchanged and there are no collisions with local `driver`
variables. build.zig now injects the concern modules into every user binary via
`default_imports`; pci/usb module import lists were updated to match.

The `runtime` and `system` shims remain for one more step (root.zig still uses
runtime); they are deleted in C5. Nothing but root.zig imports `runtime` now.

Verified: zig build, zig build test, and 17 QEMU cases (smoke, device-manager,
logger, fat-mount, fat-mutations, usb-storage, usb-hid, display-native,
virtio-gpu, input, thread-spawn, thread-mutex, process-kill, shared-memory,
driver-restart, acpi-ps2, pci-scan).
This commit is contained in:
Daniel Samson
2026-07-22 23:28:34 +01:00
parent dded46726b
commit 23bcd77c58
37 changed files with 783 additions and 692 deletions
+12 -11
View File
@@ -6,12 +6,13 @@
//! slots in beside it later (V4); the compositor never learns which is active.
const std = @import("std");
const runtime = @import("runtime");
const device = @import("driver");
const ipc = @import("ipc");
const time = @import("time");
const memory = @import("memory");
const logging = @import("logging");
const compositor = @import("compositor.zig");
const system = runtime.system;
const device = runtime.device;
const ipc = runtime.ipc;
const scanout_protocol = @import("scanout-protocol");
const Rect = compositor.Rect;
const Surface = compositor.Surface;
@@ -66,26 +67,26 @@ pub const Gop = struct {
var tries: u32 = 0;
const found = while (tries < 100) : (tries += 1) {
if (findDisplay()) |f| break f;
system.sleep(50);
time.sleepMillis(50);
} else {
_ = system.write("display: no framebuffer device (headless?)\n");
_ = logging.write("display: no framebuffer device (headless?)\n");
return null;
};
if (!device.claim(found.id)) {
_ = system.write("display: could not claim the framebuffer\n");
_ = logging.write("display: could not claim the framebuffer\n");
return null;
}
// Resource 0 is the framebuffer memory window; the kernel maps it write-combining
// because the resource carries that flag (docs/display-plan.md D1).
const front_base = device.mmioMap(found.id, 0) orelse {
_ = system.write("display: could not map the framebuffer\n");
_ = logging.write("display: could not map the framebuffer\n");
return null;
};
const size = @as(usize, found.height) * found.pitch;
const back_base = system.mmap(size, system.PROT_READ | system.PROT_WRITE);
if (system.mmapFailed(back_base)) {
_ = system.write("display: could not allocate the back buffer\n");
const back_base = memory.mmap(size, memory.PROT_READ | memory.PROT_WRITE);
if (memory.mmapFailed(back_base)) {
_ = logging.write("display: could not allocate the back buffer\n");
return null;
}
return .{
+35 -32
View File
@@ -16,15 +16,18 @@
//! (docs/display-v2.md).
const std = @import("std");
const runtime = @import("runtime");
const ipc = @import("ipc");
const input = @import("input");
const Thread = @import("thread").Thread;
const service = @import("service");
const time = @import("time");
const display = @import("display");
const memory = @import("memory");
const logging = @import("logging");
const compositor = @import("compositor.zig");
const backend_mod = @import("backend.zig");
const display_protocol = @import("display-protocol");
const ipc = runtime.ipc;
const system = runtime.system;
const input = runtime.input;
const Thread = runtime.Thread;
const Rect = compositor.Rect;
const Surface = compositor.Surface;
@@ -105,7 +108,7 @@ fn updateFrameClock() void {
const rate: u64 = if (reported == 0) 60 else @min(@max(reported, 30), 120);
frame_interval_milliseconds = @max(1000 / rate, 1);
var line: [96]u8 = undefined;
_ = system.write(std.fmt.bufPrint(&line, "display: frame clock {d} Hz ({s})\n", .{
_ = logging.write(std.fmt.bufPrint(&line, "display: frame clock {d} Hz ({s})\n", .{
1000 / frame_interval_milliseconds,
if (reported == 0) "default" else "panel EDID",
}) catch return);
@@ -116,7 +119,7 @@ fn updateFrameClock() void {
fn schedulePresent() void {
if (frame_timer_armed) return;
frame_timer_armed = true;
_ = system.timerOnce(service_endpoint, frame_interval_milliseconds);
_ = time.timerOnce(service_endpoint, frame_interval_milliseconds);
}
/// A timer landing — the frame clock, or the deferred first native present armed by
@@ -177,8 +180,8 @@ fn createLayer(x: i32, y: i32, w: u32, h: u32, z: u32, visible: bool) ?u32 {
if (w == 0 or h == 0) return null;
const slot = freeLayer() orelse return null;
const len = @as(usize, w) * h * 4;
const base = system.mmap(len, system.PROT_READ | system.PROT_WRITE);
if (system.mmapFailed(base)) return null;
const base = memory.mmap(len, memory.PROT_READ | memory.PROT_WRITE);
if (memory.mmapFailed(base)) return null;
layers[slot] = .{
.used = true,
.x = x,
@@ -222,7 +225,7 @@ fn configureLayer(id: u32, x: i32, y: i32, z: u32, visible: bool) bool {
fn destroyLayer(id: u32) bool {
const l = layerAt(id) orelse return false;
addDamage(layerScreenRect(l));
_ = system.munmap(@intFromPtr(l.surface.pixels), l.surface_len);
_ = memory.munmap(@intFromPtr(l.surface.pixels), l.surface_len);
l.* = .{};
return true;
}
@@ -294,9 +297,9 @@ fn verifyNativePresent() void {
const s = backend.surface();
const sample = s.pixels[@as(usize, s.height / 2) * s.stride + s.width / 2];
if (sample != 0) {
_ = system.write("display: native present verified\n");
_ = logging.write("display: native present verified\n");
} else {
_ = system.write("display: native present FAILED (blank surface)\n");
_ = logging.write("display: native present FAILED (blank surface)\n");
}
}
@@ -307,7 +310,7 @@ fn verifyNativePresent() void {
fn attachScanout(stride: u32, width: u32, height: u32, format: u32, refresh_hz: u32, capability: ?ipc.Handle, reply: []u8) usize {
const cap = capability orelse return fail(reply);
if (width == 0 or height == 0 or stride < width) return fail(reply);
const mapped = runtime.shared_memory.map(cap) orelse return fail(reply);
const mapped = memory.sharedMap(cap) orelse return fail(reply);
const scanout = ipc.lookup(.scanout) orelse return fail(reply);
// A second announce means the driver died and was restarted (V6): re-attach to its fresh
// scanout. (The previous shared mapping leaks — there is no shared_memory_unmap syscall yet — but the
@@ -331,8 +334,8 @@ fn attachScanout(stride: u32, width: u32, height: u32, format: u32, refresh_hz:
addDamage(screenRect()); // the whole new surface must be painted
pending_native_verify = true;
if (!reattach) pending_modeset_check = true; // the mode-set self-check runs once, on first upgrade
_ = system.timerOnce(service_endpoint, 50); // present once the driver is serving .scanout
_ = system.write(if (reattach)
_ = time.timerOnce(service_endpoint, 50); // present once the driver is serving .scanout
_ = logging.write(if (reattach)
"display: scanout re-attached\n"
else
"display: scanout upgraded to virtio-gpu\n");
@@ -349,7 +352,7 @@ fn modesetSelfCheck() void {
var mode_list: [4]backend_mod.Mode = undefined;
const count = backend.modes(&mode_list);
if (count == 0) {
_ = system.write("display: mode-set self-check: no modes reported\n");
_ = logging.write("display: mode-set self-check: no modes reported\n");
return;
}
const current = backend.info();
@@ -361,11 +364,11 @@ fn modesetSelfCheck() void {
}
}
const wanted = target orelse {
_ = system.write("display: mode-set self-check: no alternate mode offered\n");
_ = logging.write("display: mode-set self-check: no alternate mode offered\n");
return;
};
if (!backend.setMode(wanted.width, wanted.height)) {
_ = system.write("display: mode set FAILED\n");
_ = logging.write("display: mode set FAILED\n");
return;
}
addDamage(screenRect()); // repaint the whole screen at the new resolution, then present it
@@ -374,10 +377,10 @@ fn modesetSelfCheck() void {
const now = backend.info();
if (now.width == wanted.width and now.height == wanted.height) {
var line: [80]u8 = undefined;
_ = system.write(std.fmt.bufPrint(&line, "display: mode set to {d}x{d}, verified\n", .{ now.width, now.height }) catch "display: mode set, verified\n");
if (backend.hasFencedPresent()) _ = system.write("display: fenced present ok\n");
_ = logging.write(std.fmt.bufPrint(&line, "display: mode set to {d}x{d}, verified\n", .{ now.width, now.height }) catch "display: mode set, verified\n");
if (backend.hasFencedPresent()) _ = logging.write("display: fenced present ok\n");
} else {
_ = system.write("display: mode set FAILED (geometry unchanged)\n");
_ = logging.write("display: mode set FAILED (geometry unchanged)\n");
}
}
@@ -406,14 +409,14 @@ fn selfCheck() void {
present(); // repaint the self-check region back to the background
if (overlap == green and bottom_only == red) {
_ = system.write("display: compositor self-check ok\n");
_ = logging.write("display: compositor self-check ok\n");
} else {
_ = system.write("display: compositor self-check FAILED\n");
_ = logging.write("display: compositor self-check FAILED\n");
}
}
fn fail_check(_: []const u8) void {
_ = system.write("display: compositor self-check FAILED (setup)\n");
_ = logging.write("display: compositor self-check FAILED (setup)\n");
}
// --- cursor + mouse-input thread --------------------------------------------
@@ -499,7 +502,7 @@ fn clampAxis(value: i32, max: i32) i32 {
/// compositor — so no lock guards the framebuffer.
fn mouseListener(width: u32, height: u32) void {
var mouse = input.subscribeMouse() orelse {
_ = system.write("display: mouse subscribe failed\n");
_ = logging.write("display: mouse subscribe failed\n");
return;
};
// Our own handle to the compositor's endpoint. IPC handles are per-thread, so we
@@ -507,7 +510,7 @@ fn mouseListener(width: u32, height: u32) void {
// handle in this thread's table. A poke posted here wakes the compositor loop parked
// in replyWait (docs/threading.md: handles do not cross threads).
cursor_channel.poke_endpoint = ipc.lookup(.display) orelse {
_ = system.write("display: mouse listener could not reach the compositor endpoint\n");
_ = logging.write("display: mouse listener could not reach the compositor endpoint\n");
return;
};
const max_x: i32 = @as(i32, @intCast(width)) - 1;
@@ -543,7 +546,7 @@ fn renderCursor() void {
@abs(snapshot.y - cursor_origin_y) >= cursor_report_threshold)
{
cursor_tracking_reported = true;
_ = system.write("display: cursor tracking mouse ok\n");
_ = logging.write("display: cursor tracking mouse ok\n");
}
}
@@ -555,7 +558,7 @@ fn startCursorTracking() void {
cursor_origin_x = @divTrunc(@as(i32, @intCast(mode.width)), 2);
cursor_origin_y = @divTrunc(@as(i32, @intCast(mode.height)), 2);
const id = createLayer(cursor_origin_x, cursor_origin_y, cursor_size, cursor_size, cursor_z, true) orelse {
_ = system.write("display: could not create cursor layer\n");
_ = logging.write("display: could not create cursor layer\n");
return;
};
cursor_layer = id;
@@ -563,7 +566,7 @@ fn startCursorTracking() void {
present(); // show the cursor at its start position
_ = Thread.spawn(.{}, mouseListener, .{ mode.width, mode.height }) catch {
_ = system.write("display: could not spawn mouse listener\n");
_ = logging.write("display: could not spawn mouse listener\n");
};
}
@@ -583,11 +586,11 @@ fn initialise(endpoint: ipc.Handle) bool {
present();
var line: [96]u8 = undefined;
_ = system.write(std.fmt.bufPrint(&line, "display: online {d}x{d} pitch {d} format {d}\n", .{
_ = logging.write(std.fmt.bufPrint(&line, "display: online {d}x{d} pitch {d} format {d}\n", .{
mode.width, mode.height, mode.pitch, mode.format,
}) catch "display: online\n");
updateFrameClock();
_ = system.write("display: presented frame 0\n");
_ = logging.write("display: presented frame 0\n");
selfCheck();
@@ -692,7 +695,7 @@ fn onNotification(badge: u64) void {
}
pub fn main() void {
runtime.service.run(display_protocol.message_maximum, .{
service.run(display_protocol.message_maximum, .{
.service = .display,
.init = initialise,
.on_message = onMessage,