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:
2026-05-17 06:52:16 +09:00
parent 7e9bede6c5
commit bd4ea9f93e
10 changed files with 653 additions and 105 deletions

View File

@@ -2,6 +2,8 @@
// 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;
@@ -504,17 +506,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)
@@ -522,9 +517,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

View File

@@ -74,7 +74,7 @@ fn istype(m: os.mode, t: os.mode) bool = {
// atime/mtime/ctime — kernel-set at create time, all
// post-epoch (>0). Three distinct kstat offsets (72/88/104)
// so a fillfilestat field-copy miscompile or a filestat
// timespec-offset bug surfaces here, not silently.
// time.instant offset bug surfaces here, not silently.
if (fi.atime.sec <= 0i64) { fail(); };
if (fi.mtime.sec <= 0i64) { fail(); };
if (fi.ctime.sec <= 0i64) { fail(); };