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:
+35
-17
@@ -11,7 +11,33 @@
|
||||
//! CLOCK_REALTIME) layered on top later.
|
||||
|
||||
const std = @import("std");
|
||||
const system = @import("system.zig");
|
||||
const sc = @import("system-call");
|
||||
|
||||
// --- raw syscall wrappers, formerly in the system.zig dumping ground ---
|
||||
|
||||
/// Monotonic nanoseconds since boot — the raw reading; `now()` wraps it in an `Instant`.
|
||||
/// Never runs backward. Not wall-clock time (see `wallClock`).
|
||||
pub fn clock() u64 {
|
||||
return @intCast(sc.systemCall0(.clock));
|
||||
}
|
||||
|
||||
/// Wall-clock time in Unix epoch seconds (UTC), from the RTC — the real date/time, what a
|
||||
/// filesystem stamps as an mtime. Unlike `clock` (monotonic since boot), this is calendar time.
|
||||
pub fn wallClock() u64 {
|
||||
return @intCast(sc.systemCall0(.wall_clock));
|
||||
}
|
||||
|
||||
/// Block the caller for `ms` milliseconds — the raw, coarse, allocation-free form.
|
||||
pub fn sleepMillis(ms: u64) void {
|
||||
_ = sc.systemCall1(.sleep, ms);
|
||||
}
|
||||
|
||||
/// Arm a one-shot timer: after `ms` the kernel posts a timer notification
|
||||
/// (`ipc.Received.isTimer`) to `endpoint` (a handle from `ipc.createIpcEndpoint`). Unlike
|
||||
/// `sleep`, does not block — a service keeps serving IPC while the deadline is pending.
|
||||
pub fn timerOnce(endpoint: usize, ms: u64) bool {
|
||||
return sc.systemCall2(.timer_bind, endpoint, ms) == 0;
|
||||
}
|
||||
|
||||
const nanos_per_micro: u64 = 1_000;
|
||||
const nanos_per_milli: u64 = 1_000_000;
|
||||
@@ -90,32 +116,27 @@ pub const Instant = struct {
|
||||
|
||||
/// The current monotonic time.
|
||||
pub fn now() Instant {
|
||||
return .{ .ns = system.clock() };
|
||||
return .{ .ns = clock() };
|
||||
}
|
||||
|
||||
/// Monotonic nanoseconds since boot — the raw `clock()` reading, for callers that
|
||||
/// want a plain integer instead of an `Instant`.
|
||||
pub fn monotonicNanos() u64 {
|
||||
return system.clock();
|
||||
return clock();
|
||||
}
|
||||
|
||||
/// Whether the monotonic clock is usable. The kernel returns 0 until the TSC is
|
||||
/// calibrated (`tsc_hz == 0`); a caller that needs real time can treat that as
|
||||
/// "unavailable" instead of assuming the clock advances.
|
||||
pub fn available() bool {
|
||||
return system.clock() != 0;
|
||||
return clock() != 0;
|
||||
}
|
||||
|
||||
/// Block the caller for at least `d`, rounded up to the kernel's millisecond
|
||||
/// granularity. For sub-millisecond precision the scheduler cannot express, use
|
||||
/// `spin`.
|
||||
/// `spin`. (The raw millisecond form is `sleepMillis`.)
|
||||
pub fn sleep(d: Duration) void {
|
||||
system.sleep(d.ceilMillis());
|
||||
}
|
||||
|
||||
/// Block the caller for `ms` milliseconds — the coarse, allocation-free form.
|
||||
pub fn sleepMillis(ms: u64) void {
|
||||
system.sleep(ms);
|
||||
sleepMillis(d.ceilMillis());
|
||||
}
|
||||
|
||||
/// Busy-wait until `d` has elapsed, polling the monotonic clock. This burns the CPU
|
||||
@@ -126,13 +147,10 @@ pub fn spin(d: Duration) void {
|
||||
while (!deadline.reached()) {}
|
||||
}
|
||||
|
||||
/// Arm a one-shot timer against `endpoint` (a handle from `ipc.createIpcEndpoint`):
|
||||
/// after `d` the kernel posts a timer notification (`ipc.Received.isTimer`) there.
|
||||
/// Unlike `sleep`, this does not block — a service can keep serving IPC on the same
|
||||
/// endpoint while the deadline is pending. Rounds `d` up to milliseconds; returns
|
||||
/// false if the timer could not be armed. See `system.timerOnce`.
|
||||
/// The ergonomic `Duration` form of `timerOnce`: arm a one-shot timer against `endpoint`
|
||||
/// for `d` (rounded up to milliseconds). Returns false if the timer could not be armed.
|
||||
pub fn after(endpoint: usize, d: Duration) bool {
|
||||
return system.timerOnce(endpoint, d.ceilMillis());
|
||||
return timerOnce(endpoint, d.ceilMillis());
|
||||
}
|
||||
|
||||
test "Duration unit conversions round toward zero" {
|
||||
|
||||
Reference in New Issue
Block a user