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:
@@ -16,13 +16,17 @@
|
||||
//! restart. Tree reports (`child_added`) land in M18.2.
|
||||
|
||||
const std = @import("std");
|
||||
const runtime = @import("runtime");
|
||||
const device = @import("driver");
|
||||
const ipc = @import("ipc");
|
||||
const process = @import("process");
|
||||
const service = @import("service");
|
||||
const time = @import("time");
|
||||
const memory = @import("memory");
|
||||
const logging = @import("logging");
|
||||
const acpi_ids = @import("acpi-ids");
|
||||
const pci_class = @import("pci-class");
|
||||
const usb_ids = @import("usb-ids");
|
||||
const device_manager_protocol = @import("device-manager-protocol");
|
||||
const device = runtime.device;
|
||||
const system = runtime.system;
|
||||
|
||||
/// The PCI class/subclass/prog-IF triple of an xHCI (USB 3) host controller —
|
||||
/// Serial Bus Controller / USB Controller / XHCI — named from pci-class.zig rather
|
||||
@@ -154,7 +158,7 @@ const Driver = struct {
|
||||
|
||||
const maximum_drivers = 16;
|
||||
var drivers: [maximum_drivers]Driver = .{Driver{}} ** maximum_drivers;
|
||||
var manager_endpoint: runtime.ipc.Handle = 0;
|
||||
var manager_endpoint: ipc.Handle = 0;
|
||||
var test_restart_mode = false;
|
||||
var test_usb_restart_mode = false;
|
||||
var test_usb_killed = false;
|
||||
@@ -169,14 +173,14 @@ var test_kill_due_ns: u64 = 0;
|
||||
/// buffered message. A subscriber whose endpoint stops accepting (it died) is
|
||||
/// dropped on the failed send.
|
||||
const maximum_subscribers = 8;
|
||||
var subscribers: [maximum_subscribers]?runtime.ipc.Handle = .{null} ** maximum_subscribers;
|
||||
var subscribers: [maximum_subscribers]?ipc.Handle = .{null} ** maximum_subscribers;
|
||||
|
||||
/// Publish one event (a ChildAdded or ChildRemoved struct, the same encoding
|
||||
/// the bus drivers send) to every subscriber.
|
||||
fn publishEvent(event: []const u8) void {
|
||||
for (&subscribers) |*slot| {
|
||||
if (slot.*) |handle| {
|
||||
if (!runtime.ipc.send(handle, event)) slot.* = null; // dead subscriber
|
||||
if (!ipc.send(handle, event)) slot.* = null; // dead subscriber
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -284,17 +288,17 @@ fn spawnDriver(driver: *Driver) void {
|
||||
arguments[0] = std.fmt.bufPrint(&id_text, "{d}", .{driver.device_id}) catch return;
|
||||
argument_count = 1;
|
||||
}
|
||||
const child = system.spawnSupervised(driver.name(), arguments[0..argument_count], manager_endpoint) orelse {
|
||||
const child = process.spawnSupervised(driver.name(), arguments[0..argument_count], manager_endpoint) orelse {
|
||||
std.log.info("failed to spawn {s}", .{driver.name()});
|
||||
driver.state = .failed;
|
||||
return;
|
||||
};
|
||||
driver.process_id = child;
|
||||
driver.spawn_ns = system.clock();
|
||||
driver.spawn_ns = time.clock();
|
||||
if (driver.speaks_protocol) {
|
||||
driver.state = .awaiting_hello;
|
||||
driver.hello_deadline_ns = driver.spawn_ns + hello_deadline_ms * 1_000_000;
|
||||
_ = system.timerOnce(manager_endpoint, hello_deadline_ms + 100);
|
||||
_ = time.timerOnce(manager_endpoint, hello_deadline_ms + 100);
|
||||
} else {
|
||||
driver.state = .running;
|
||||
}
|
||||
@@ -310,13 +314,13 @@ fn spawnDriver(driver: *Driver) void {
|
||||
/// restarts with backoff until the crash-loop cap.
|
||||
fn onDriverExit(driver: *Driver) void {
|
||||
pruneChildrenOf(driver.process_id);
|
||||
const reason = runtime.process.exitReason(driver.process_id) orelse .fault;
|
||||
const reason = process.exitReason(driver.process_id) orelse .fault;
|
||||
if (reason == .exited) {
|
||||
driver.state = .stopped;
|
||||
std.log.info("{s} exited cleanly; not restarting", .{driver.name()});
|
||||
return;
|
||||
}
|
||||
const now = system.clock();
|
||||
const now = time.clock();
|
||||
const alive_ns = now - driver.spawn_ns;
|
||||
driver.restarts = if (alive_ns < fast_death_ns) driver.restarts + 1 else 1;
|
||||
if (driver.restarts >= crash_loop_cap) {
|
||||
@@ -328,7 +332,7 @@ fn onDriverExit(driver: *Driver) void {
|
||||
driver.state = .restarting;
|
||||
driver.restart_due_ns = now + delay_ms * 1_000_000;
|
||||
std.log.info("restarting {s} in {d} ms (died: {s})", .{ driver.name(), delay_ms, @tagName(reason) });
|
||||
_ = system.timerOnce(manager_endpoint, delay_ms + 50);
|
||||
_ = time.timerOnce(manager_endpoint, delay_ms + 50);
|
||||
}
|
||||
|
||||
/// A timer landed: sweep every deadline. Overdue hellos are killed (the exit
|
||||
@@ -336,10 +340,10 @@ fn onDriverExit(driver: *Driver) void {
|
||||
/// respawn. Timers carry no id on purpose — the table is the state, and one
|
||||
/// sweep serves every armed deadline.
|
||||
fn sweepDeadlines() void {
|
||||
const now = system.clock();
|
||||
const now = time.clock();
|
||||
if (test_kill_pid != 0 and now >= test_kill_due_ns) {
|
||||
std.log.info("test mode: killing the reporter", .{});
|
||||
_ = system.kill(test_kill_pid);
|
||||
_ = process.kill(test_kill_pid);
|
||||
test_kill_pid = 0;
|
||||
}
|
||||
for (&drivers) |*driver| {
|
||||
@@ -347,7 +351,7 @@ fn sweepDeadlines() void {
|
||||
switch (driver.state) {
|
||||
.awaiting_hello => if (now >= driver.hello_deadline_ns) {
|
||||
std.log.info("{s} missed its hello deadline", .{driver.name()});
|
||||
_ = system.kill(driver.process_id);
|
||||
_ = process.kill(driver.process_id);
|
||||
// The exit notification finishes the job via onDriverExit.
|
||||
},
|
||||
.restarting => if (now >= driver.restart_due_ns) spawnDriver(driver),
|
||||
@@ -358,12 +362,12 @@ fn sweepDeadlines() void {
|
||||
|
||||
// --- the harness callbacks -----------------------------------------------------
|
||||
|
||||
fn initialise(endpoint: runtime.ipc.Handle) bool {
|
||||
fn initialise(endpoint: ipc.Handle) bool {
|
||||
manager_endpoint = endpoint;
|
||||
|
||||
// Enumerate into a heap buffer (too big for the one-page user stack).
|
||||
const buffer = runtime.allocator().alloc(device.DeviceDescriptor, 64) catch {
|
||||
_ = runtime.system.write("/system/services/device-manager: out of memory\n");
|
||||
const buffer = memory.allocator().alloc(device.DeviceDescriptor, 64) catch {
|
||||
_ = logging.write("/system/services/device-manager: out of memory\n");
|
||||
return false;
|
||||
};
|
||||
const total = device.enumerate(buffer);
|
||||
@@ -400,14 +404,14 @@ fn initialise(endpoint: runtime.ipc.Handle) bool {
|
||||
}
|
||||
|
||||
if (matched == 0) {
|
||||
_ = runtime.system.write("/system/services/device-manager: no matchable devices\n");
|
||||
_ = logging.write("/system/services/device-manager: no matchable devices\n");
|
||||
} else {
|
||||
_ = runtime.system.write("/system/services/device-manager: ok\n");
|
||||
_ = logging.write("/system/services/device-manager: ok\n");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
fn onMessage(message: []const u8, reply: []u8, sender: u32, capability: ?runtime.ipc.Handle) usize {
|
||||
fn onMessage(message: []const u8, reply: []u8, sender: u32, capability: ?ipc.Handle) usize {
|
||||
if (message.len < 1) return 0;
|
||||
switch (message[0]) {
|
||||
@intFromEnum(device_manager_protocol.Operation.child_added) => return onChildAdded(message, reply, sender),
|
||||
@@ -432,8 +436,8 @@ fn onMessage(message: []const u8, reply: []u8, sender: u32, capability: ?runtime
|
||||
if (test_scanout_restart_mode and !test_scanout_killed and std.mem.eql(u8, driver.name(), "/system/drivers/virtio-gpu")) {
|
||||
test_scanout_killed = true;
|
||||
test_kill_pid = sender;
|
||||
test_kill_due_ns = system.clock() + 1_500_000_000;
|
||||
_ = system.timerOnce(manager_endpoint, 1600);
|
||||
test_kill_due_ns = time.clock() + 1_500_000_000;
|
||||
_ = time.timerOnce(manager_endpoint, 1600);
|
||||
}
|
||||
} else {
|
||||
status = -1;
|
||||
@@ -489,8 +493,8 @@ fn onChildAdded(message: []const u8, reply: []u8, sender: u32) usize {
|
||||
// (M19.0 idempotence, proven end to end by pci-scan).
|
||||
test_usb_killed = true;
|
||||
test_kill_pid = sender;
|
||||
test_kill_due_ns = system.clock() + 1_000_000_000;
|
||||
_ = system.timerOnce(manager_endpoint, 1100);
|
||||
test_kill_due_ns = time.clock() + 1_000_000_000;
|
||||
_ = time.timerOnce(manager_endpoint, 1100);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -503,8 +507,8 @@ fn onChildAdded(message: []const u8, reply: []u8, sender: u32) usize {
|
||||
// needs a window to enumerate and subscribe before the events.
|
||||
test_usb_killed = true;
|
||||
test_kill_pid = sender;
|
||||
test_kill_due_ns = system.clock() + 2_000_000_000;
|
||||
_ = system.timerOnce(manager_endpoint, 2100);
|
||||
test_kill_due_ns = time.clock() + 2_000_000_000;
|
||||
_ = time.timerOnce(manager_endpoint, 2100);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -547,7 +551,7 @@ fn onEnumerate(reply: []u8) usize {
|
||||
}
|
||||
|
||||
/// An application subscribed: its endpoint arrived as the call's capability.
|
||||
fn onSubscribe(reply: []u8, capability: ?runtime.ipc.Handle) usize {
|
||||
fn onSubscribe(reply: []u8, capability: ?ipc.Handle) usize {
|
||||
var status: i32 = -1;
|
||||
if (capability) |handle| {
|
||||
for (&subscribers) |*slot| {
|
||||
@@ -564,22 +568,22 @@ fn onSubscribe(reply: []u8, capability: ?runtime.ipc.Handle) usize {
|
||||
}
|
||||
|
||||
fn onNotification(badge: u64) void {
|
||||
if (badge & runtime.ipc.notify_exit_bit != 0) {
|
||||
const dead: u32 = @intCast(badge & ~(runtime.ipc.notify_badge_bit | runtime.ipc.notify_exit_bit));
|
||||
if (badge & ipc.notify_exit_bit != 0) {
|
||||
const dead: u32 = @intCast(badge & ~(ipc.notify_badge_bit | ipc.notify_exit_bit));
|
||||
if (driverByProcess(dead)) |driver| onDriverExit(driver);
|
||||
return;
|
||||
}
|
||||
if (badge & runtime.ipc.notify_timer_bit != 0) sweepDeadlines();
|
||||
if (badge & ipc.notify_timer_bit != 0) sweepDeadlines();
|
||||
}
|
||||
|
||||
pub fn main(init: runtime.process.Init) void {
|
||||
pub fn main(init: process.Init) void {
|
||||
if (init.arguments.get(1)) |mode| {
|
||||
test_restart_mode = std.mem.eql(u8, mode, "test-restart");
|
||||
test_usb_restart_mode = std.mem.eql(u8, mode, "test-usb-restart");
|
||||
test_pci_restart_mode = std.mem.eql(u8, mode, "test-pci-restart");
|
||||
test_scanout_restart_mode = std.mem.eql(u8, mode, "test-scanout-restart");
|
||||
}
|
||||
runtime.service.run(device_manager_protocol.message_maximum, .{
|
||||
service.run(device_manager_protocol.message_maximum, .{
|
||||
.service = .device_manager,
|
||||
.init = initialise,
|
||||
.on_message = onMessage,
|
||||
|
||||
Reference in New Issue
Block a user