reorg: split the runtime into library/kernel concern modules (C1)

The one giant `runtime` module (with a `system.zig` that was itself a dumping
ground of unrelated syscalls) is split into directly-importable, flat concern
modules under library/kernel/:

  system-call  ipc  memory  process  thread  time  logging  file-system  service  start
  (+ the device/service clients: device, device-manager, block, display, input)

system.zig is dissolved — its functions moved to their concern home (mmap ->
memory, spawn/kill/exit -> process, sleep/clock -> time, write/klog -> logging,
fs* -> file-system). `memory` merges heap+dma+shared-memory behind one flat API
(memory.allocator/dmaAlloc/sharedCreate/mmap), keeping heap's state and malloc
export single. The memory<->thread dependency cycle (heap needs Thread.Mutex,
thread needs mmap) is broken by having thread allocate its own stack via the raw
mmap syscall, so the module graph is a DAG.

This is the atomic step: all 42 internal cross-imports flip from relative to
module imports at once. `runtime.zig` and `system.zig` become thin re-export
SHIMS so the ~38 consumers keep compiling on `runtime.*` untouched; they migrate
to direct imports in C2, after which the shims are deleted (C5).

zig build + zig build test green; 14 QEMU cases pass (smoke, process,
process-kill, thread-spawn/join, logger, vfs, fat-mount, display-native,
usb-storage, virtio-gpu, device-manager, input, power-button).
This commit is contained in:
Daniel Samson
2026-07-22 22:53:13 +01:00
parent 3e69712b97
commit 60f32ee9ff
21 changed files with 636 additions and 467 deletions
+140 -19
View File
@@ -387,31 +387,15 @@ pub fn build(b: *std.Build) void {
// types its `device` helper wraps, and re-exports `vfs-protocol` for the VFS
// server. It never touches `boot-handoff` — user space has no business with the
// loader↔kernel handoff.
const runtime_module = b.addModule("runtime", .{
.root_source_file = b.path("library/kernel/runtime.zig"),
.imports = &.{
.{ .name = "abi", .module = abi_module },
.{ .name = "device-abi", .module = device_abi_module },
.{ .name = "vfs-protocol", .module = vfs_protocol_module },
.{ .name = "input-protocol", .module = input_protocol_module },
},
});
// The device-manager protocol: hello + (M18.2) tree reports, exposed as its
// own module like the other protocol modules. Imported through the runtime.
// Wire-protocol modules the kernel-library client wrappers (device-manager/block/display)
// and the services speak. The `runtime` module itself is defined below, after the
// library/kernel concern modules it shims over.
const device_manager_protocol_module = b.addModule("device-manager-protocol", .{
.root_source_file = b.path("library/protocol/device-manager/device-manager-protocol.zig"),
});
runtime_module.addImport("device-manager-protocol", device_manager_protocol_module);
// The block protocol, so runtime.block (the block-device client) can speak it.
runtime_module.addImport("block-protocol", block_protocol_module);
// The display protocol, so runtime.display (the compositor client) and the display
// service both speak it through the runtime, like the other protocol modules.
const display_protocol_module = b.addModule("display-protocol", .{
.root_source_file = b.path("library/protocol/display/display-protocol.zig"),
});
runtime_module.addImport("display-protocol", display_protocol_module); // runtime.display client speaks it
// The scanout protocol: the compositor's outbound present channel to a native scanout
// driver (virtio-gpu), separate from the client-facing display protocol (docs/display-v2.md).
@@ -433,6 +417,143 @@ pub fn build(b: *std.Build) void {
.root_source_file = b.path("library/device/mmio/mmio.zig"),
});
// --- library/kernel: the userspace private-ABI library (kernel32-style), split by
// concern into directly-importable modules. `system.zig` (the old dumping ground) and
// `runtime.zig` (the old aggregator) are compatibility shims re-exporting these until the
// consumers migrate to direct imports (reorg C1–C5). The graph is a DAG: memory depends on
// thread (heap needs Thread.Mutex), and thread does its own raw mmap so there is no cycle.
const system_call_module = b.addModule("system-call", .{
.root_source_file = b.path("library/kernel/system-call.zig"),
.imports = &.{.{ .name = "abi", .module = abi_module }},
});
const ipc_module = b.addModule("ipc", .{
.root_source_file = b.path("library/kernel/ipc.zig"),
.imports = &.{ .{ .name = "abi", .module = abi_module }, .{ .name = "system-call", .module = system_call_module } },
});
const time_module = b.addModule("time", .{
.root_source_file = b.path("library/kernel/time.zig"),
.imports = &.{.{ .name = "system-call", .module = system_call_module }},
});
const thread_module = b.addModule("thread", .{
.root_source_file = b.path("library/kernel/thread.zig"),
.imports = &.{ .{ .name = "abi", .module = abi_module }, .{ .name = "system-call", .module = system_call_module } },
});
const logging_module = b.addModule("logging", .{
.root_source_file = b.path("library/kernel/logging.zig"),
.imports = &.{ .{ .name = "abi", .module = abi_module }, .{ .name = "system-call", .module = system_call_module } },
});
const process_module = b.addModule("process", .{
.root_source_file = b.path("library/kernel/process.zig"),
.imports = &.{
.{ .name = "abi", .module = abi_module },
.{ .name = "system-call", .module = system_call_module },
.{ .name = "ipc", .module = ipc_module },
.{ .name = "time", .module = time_module },
},
});
const file_system_module = b.addModule("file-system", .{
.root_source_file = b.path("library/kernel/file-system.zig"),
.imports = &.{
.{ .name = "abi", .module = abi_module },
.{ .name = "system-call", .module = system_call_module },
.{ .name = "ipc", .module = ipc_module },
.{ .name = "vfs-protocol", .module = vfs_protocol_module },
},
});
const memory_module = b.addModule("memory", .{
.root_source_file = b.path("library/kernel/memory/memory.zig"),
.imports = &.{
.{ .name = "abi", .module = abi_module },
.{ .name = "system-call", .module = system_call_module },
.{ .name = "ipc", .module = ipc_module },
.{ .name = "thread", .module = thread_module },
},
});
const service_module = b.addModule("service", .{
.root_source_file = b.path("library/kernel/service.zig"),
.imports = &.{
.{ .name = "abi", .module = abi_module },
.{ .name = "ipc", .module = ipc_module },
.{ .name = "process", .module = process_module },
},
});
const start_module = b.addModule("start", .{
.root_source_file = b.path("library/kernel/start.zig"),
.imports = &.{ .{ .name = "process", .module = process_module }, .{ .name = "logging", .module = logging_module } },
});
const device_module = b.addModule("device", .{
.root_source_file = b.path("library/kernel/device.zig"),
.imports = &.{
.{ .name = "abi", .module = abi_module },
.{ .name = "device-abi", .module = device_abi_module },
.{ .name = "system-call", .module = system_call_module },
},
});
const device_manager_client_module = b.addModule("device-manager", .{
.root_source_file = b.path("library/kernel/device-manager.zig"),
.imports = &.{
.{ .name = "ipc", .module = ipc_module },
.{ .name = "time", .module = time_module },
.{ .name = "device-manager-protocol", .module = device_manager_protocol_module },
},
});
const block_client_module = b.addModule("block", .{
.root_source_file = b.path("library/kernel/block.zig"),
.imports = &.{
.{ .name = "ipc", .module = ipc_module },
.{ .name = "time", .module = time_module },
.{ .name = "block-protocol", .module = block_protocol_module },
},
});
const display_client_module = b.addModule("display", .{
.root_source_file = b.path("library/kernel/display.zig"),
.imports = &.{
.{ .name = "ipc", .module = ipc_module },
.{ .name = "time", .module = time_module },
.{ .name = "display-protocol", .module = display_protocol_module },
},
});
const input_client_module = b.addModule("input", .{
.root_source_file = b.path("library/kernel/input.zig"),
.imports = &.{
.{ .name = "ipc", .module = ipc_module },
.{ .name = "time", .module = time_module },
.{ .name = "input-protocol", .module = input_protocol_module },
},
});
// system.zig — compatibility shim for runtime.system.*, re-exporting the concern modules.
const system_module = b.addModule("system", .{
.root_source_file = b.path("library/kernel/system.zig"),
.imports = &.{
.{ .name = "memory", .module = memory_module },
.{ .name = "process", .module = process_module },
.{ .name = "time", .module = time_module },
.{ .name = "logging", .module = logging_module },
.{ .name = "file-system", .module = file_system_module },
},
});
// runtime.zig — compatibility shim re-exporting every concern module under the old runtime.* names.
const runtime_module = b.addModule("runtime", .{
.root_source_file = b.path("library/kernel/runtime.zig"),
.imports = &.{
.{ .name = "system", .module = system_module },
.{ .name = "ipc", .module = ipc_module },
.{ .name = "memory", .module = memory_module },
.{ .name = "process", .module = process_module },
.{ .name = "service", .module = service_module },
.{ .name = "thread", .module = thread_module },
.{ .name = "time", .module = time_module },
.{ .name = "logging", .module = logging_module },
.{ .name = "file-system", .module = file_system_module },
.{ .name = "start", .module = start_module },
.{ .name = "device", .module = device_module },
.{ .name = "device-manager", .module = device_manager_client_module },
.{ .name = "input", .module = input_client_module },
.{ .name = "block", .module = block_client_module },
.{ .name = "display", .module = display_client_module },
},
});
// A device driver's view of its claimed PCI function: config-space header fields, BAR
// decode + map, and the capability walk (library/device/pci/pci.zig). The generic PCI
// mechanics every leaf PCI driver used to re-derive inline. Imports runtime (device