lib/os: graduate timespec to time.instant
Removes the local os.timespec (sec, nsec) struct in favour of
time.instant from lib/time. lib/os now `use time;`. filestat's
atime/mtime/ctime change type with byte-identical layout
(i64+i64=16B both sides), so .sec / .nsec accessors at all caller
sites work unchanged.
Rule 12: simple data + mirror Hare. Two same-layout types — one
Hare-canonical, one not — is exactly the structural divergence the
rule forbids. Single-source-of-truth; no transitional alias.
Citations: ref/hare/fs/types.ha:141 (Hare's fs::filestat carries
time::instant), ref/hare/time/instant.ha:9 (canonical layout).
Caller impact (sole reader): lib/os/stattest.ww (.sec / .nsec
unchanged; one comment line refreshed). examples/cmatrix migrated
already in 7e9bede. No selfhost/cmd/* reads mtime/atime/ctime.
Test wiring: lib/os/os.ww removed from 900_stdlib.c's standalone-
w6c-codegen list (cross-module type ref now needs the driver's
module concatenation, same reason lib/bufio and lib/fmt graduated
off earlier). Coverage stays at 976_stat_run via stattest.ww.
Makefile dep edges for the five wwstage targets gain
lib/time/time.ww so changes to it trigger wwstage rebuild.
lib/time is now in the toolchain transitive chain via lib/os. No
selfhost cmd calls time.add/time.diff today; bootstrap is safe.
Latent risk: any future selfhost edit adding time.add/time.diff
would surface task #15 (nested-if label-counter skew in lib/time/
add) as a bootstrap regression. File a fix-#15 before such an edit.
Bootstrap byte-id: ww2 == ww3 == ww4 for all five wwstage tools.
This commit is contained in:
@@ -1,8 +1,107 @@
|
||||
// MODULE: time
|
||||
// time — clocks, instants, durations. Mirrors Hare's lib/time
|
||||
// (ref/hare/time/duration.ha, instant.ha, arithm.ha,
|
||||
// +linux/functions.ha). Calendar / date / strftime / timezone /
|
||||
// sleep live in separate Hare modules and graduate when callers /
|
||||
// supporting stdlib arrive.
|
||||
//
|
||||
// `duration` is a NAMED alias of i64 (lib/math/random precedent
|
||||
// at lib/math/random/random.ww:8); ww treats NAMED as a newtype,
|
||||
// so cross-i64 arithmetic inside this module needs explicit casts.
|
||||
// Hare's structural alias semantics let those casts vanish, but
|
||||
// our type checker is strict.
|
||||
|
||||
@symbol("rt_syscall") fn syscall2(num: i64, a: i64, b: i64) i64;
|
||||
@symbol("rt_abort") fn abort(msg: str) void;
|
||||
|
||||
def SYS_CLOCK_GETTIME: i64 = 228;
|
||||
|
||||
// ref/hare/time/duration.ha:6. 290y representable range.
|
||||
export type duration = i64;
|
||||
|
||||
// ref/hare/time/duration.ha:9-18. Plan-9 naming (lowercase)
|
||||
// diverges from Hare's uppercase per project rule 4.
|
||||
export def nanosecond: duration = 1i64;
|
||||
export def microsecond: duration = 1000i64;
|
||||
export def millisecond: duration = 1000000i64;
|
||||
export def second: duration = 1000000000i64;
|
||||
|
||||
// ref/hare/time/instant.ha:9. (sec, nsec) pair — NOT POSIX struct
|
||||
// timespec (which uses u32 nsec). Layout matches Linux's struct
|
||||
// timespec on 64-bit (i64+i64) so we can pass &instant directly
|
||||
// to clock_gettime.
|
||||
export type instant = struct {
|
||||
sec: i64,
|
||||
nsec: i64,
|
||||
};
|
||||
|
||||
// ref/hare/time/+linux/functions.ha:84. First cut exposes only
|
||||
// realtime and monotonic; Hare's process_cpu / thread_cpu / boot /
|
||||
// realtime_alarm / boot_alarm / tai graduate when a caller needs
|
||||
// them (CLAUDE.md rule 9 — Hare-fidelity, no premature surface).
|
||||
export type clock = enum i32 {
|
||||
realtime = 0,
|
||||
monotonic = 1,
|
||||
};
|
||||
|
||||
// ref/hare/time/+linux/functions.ha:138. Hare's now() also aborts
|
||||
// on impossible errnos. (instant | oserror) is deliberately not
|
||||
// the return shape — EINVAL / EFAULT are programmer errors (bad
|
||||
// clock id, bad ptr), and a 1-word-payload sum return walks into
|
||||
// task #9's cgen-divergence trap.
|
||||
export fn now(c: clock) instant = {
|
||||
let i: instant;
|
||||
let rc = syscall2(SYS_CLOCK_GETTIME, (c as i32): i64, (&i): i64);
|
||||
if (rc != 0i64) { abort("time.now: clock_gettime failed"); };
|
||||
return i;
|
||||
};
|
||||
|
||||
// ref/hare/time/arithm.ha:9. Adds duration to instant. The
|
||||
// negative-duration branch normalises nsec into [0, second).
|
||||
export fn add(i: instant, x: duration) instant = {
|
||||
let r: instant;
|
||||
let xi: i64 = x: i64;
|
||||
let sec: i64 = second: i64;
|
||||
let nsec: i64 = nanosecond: i64;
|
||||
if (xi == 0i64) {
|
||||
r.sec = i.sec;
|
||||
r.nsec = i.nsec;
|
||||
return r;
|
||||
};
|
||||
if (xi > 0i64) {
|
||||
r.sec = i.sec + (i.nsec + xi) / sec;
|
||||
r.nsec = (i.nsec + xi) % sec;
|
||||
return r;
|
||||
};
|
||||
r.sec = i.sec + (i.nsec + xi - sec + nsec) / sec;
|
||||
r.nsec = (i.nsec + (xi % sec) + sec) % sec;
|
||||
return r;
|
||||
};
|
||||
|
||||
// ref/hare/time/arithm.ha:26. Returns duration from a to b.
|
||||
// Sign convention: b - a.
|
||||
export fn diff(a: instant, b: instant) duration = {
|
||||
let sec: i64 = second: i64;
|
||||
let v: i64 = ((b.sec - a.sec) * sec) + (b.nsec - a.nsec);
|
||||
return v: duration;
|
||||
};
|
||||
|
||||
// ref/hare/time/arithm.ha:32. -1 if a < b, 0 if equal, +1 if a > b.
|
||||
export fn compare(a: instant, b: instant) i8 = {
|
||||
if (a.sec < b.sec) { return -1i8; };
|
||||
if (a.sec > b.sec) { return 1i8; };
|
||||
if (a.nsec < b.nsec) { return -1i8; };
|
||||
if (a.nsec > b.nsec) { return 1i8; };
|
||||
return 0i8;
|
||||
};
|
||||
|
||||
// MODULE: os
|
||||
// os — process and filesystem facade. The body of each call lands
|
||||
// either in libwwrt.a (rt_syscall trampoline) or libc bindings,
|
||||
// depending on how the program was linked.
|
||||
|
||||
use time;
|
||||
|
||||
@symbol("rt_syscall") fn syscall0(num: nr) i64;
|
||||
@symbol("rt_syscall") fn syscall1(num: nr, a: i64) i64;
|
||||
@symbol("rt_syscall") fn syscall2(num: nr, a: i64, b: i64) i64;
|
||||
@@ -505,17 +604,10 @@ export type stat_mask = enum u32 {
|
||||
CTIME = 64u32,
|
||||
};
|
||||
|
||||
// timespec — {sec, nsec} pair, matching Hare's time::instant
|
||||
// (ref/hare/time/types.ha). Local to lib/os; graduates to
|
||||
// lib/time.instant when lib/time and lib/fs ship. Same byte layout
|
||||
// (i64+i64 = 16B) so a future migration is field-rename only.
|
||||
export type timespec = struct {
|
||||
sec: i64,
|
||||
nsec: i64,
|
||||
};
|
||||
|
||||
// filestat — Hare's fs::filestat (ref/hare/fs/types.ha:141). 80
|
||||
// bytes. See module-header note re: graduation to lib/fs.
|
||||
// bytes. Times are time.instant (ref/hare/time/instant.ha:9) — the
|
||||
// canonical Hare shape. See module-header note re: graduation to
|
||||
// lib/fs.
|
||||
export type filestat = struct {
|
||||
mask: stat_mask, // 0 (4)
|
||||
mode: mode, // 4 (4)
|
||||
@@ -523,9 +615,9 @@ export type filestat = struct {
|
||||
gid: u32, // 12 (4)
|
||||
sz: u64, // 16 (8)
|
||||
inode: u64, // 24 (8)
|
||||
atime: timespec, // 32 (16)
|
||||
mtime: timespec, // 48 (16)
|
||||
ctime: timespec, // 64 (16) — ends at 80
|
||||
atime: time.instant, // 32 (16)
|
||||
mtime: time.instant, // 48 (16)
|
||||
ctime: time.instant, // 64 (16) — ends at 80
|
||||
};
|
||||
|
||||
// kstat — x86_64 kernel `struct stat` layout. Mirrors
|
||||
|
||||
Reference in New Issue
Block a user