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:
10
Makefile
10
Makefile
@@ -113,7 +113,7 @@ $(BIN)/wwdump_ww: selfhost/cmd/wwdump/main.ww \
|
||||
selfhost/cmd/wcc/cgen.ww selfhost/cmd/wcc/cgenexpr.ww \
|
||||
selfhost/cmd/wcc/cgenstmt.ww selfhost/cmd/wcc/cgenutil.ww \
|
||||
selfhost/cmd/wcc/cgendecl.ww \
|
||||
lib/os/os.ww lib/strconv/strconv.ww lib/strings/strings.ww lib/ascii/ascii.ww lib/io/io.ww lib/memio/memio.ww lib/fmt/fmt.ww \
|
||||
lib/os/os.ww lib/time/time.ww lib/strconv/strconv.ww lib/strings/strings.ww lib/ascii/ascii.ww lib/io/io.ww lib/memio/memio.ww lib/fmt/fmt.ww \
|
||||
$(BIN)/ww $(BIN)/w6c $(BIN)/w6a $(BIN)/w6l \
|
||||
$(LIB)/libwwrt.a | $(BIN)
|
||||
cd $(BIN) && ./ww build \
|
||||
@@ -134,7 +134,7 @@ $(BIN)/w6c_ww: selfhost/cmd/w6c/main.ww \
|
||||
selfhost/cmd/wcc/cgen.ww selfhost/cmd/wcc/cgenexpr.ww \
|
||||
selfhost/cmd/wcc/cgenstmt.ww selfhost/cmd/wcc/cgenutil.ww \
|
||||
selfhost/cmd/wcc/cgendecl.ww \
|
||||
lib/os/os.ww lib/strconv/strconv.ww lib/strings/strings.ww lib/ascii/ascii.ww lib/io/io.ww lib/memio/memio.ww lib/fmt/fmt.ww \
|
||||
lib/os/os.ww lib/time/time.ww lib/strconv/strconv.ww lib/strings/strings.ww lib/ascii/ascii.ww lib/io/io.ww lib/memio/memio.ww lib/fmt/fmt.ww \
|
||||
$(BIN)/ww $(BIN)/w6c $(BIN)/w6a $(BIN)/w6l \
|
||||
$(LIB)/libwwrt.a | $(BIN)
|
||||
cd $(BIN) && ./ww build \
|
||||
@@ -152,7 +152,7 @@ $(BIN)/w6a_ww: selfhost/cmd/w6a/main.ww selfhost/cmd/w6a/types.ww \
|
||||
selfhost/cmd/w6a/lex.ww selfhost/cmd/w6a/parse.ww \
|
||||
selfhost/cmd/w6a/asm.ww selfhost/cmd/w6a/obj.ww \
|
||||
selfhost/cmd/wcc/mem.ww \
|
||||
lib/os/os.ww \
|
||||
lib/os/os.ww lib/time/time.ww \
|
||||
$(BIN)/ww $(BIN)/w6c $(BIN)/w6a $(BIN)/w6l \
|
||||
$(LIB)/libwwrt.a | $(BIN)
|
||||
cd $(BIN) && ./ww build \
|
||||
@@ -168,7 +168,7 @@ $(BIN)/w6l_ww: selfhost/cmd/w6l/main.ww selfhost/cmd/w6l/sym.ww \
|
||||
selfhost/cmd/w6l/obj.ww selfhost/cmd/w6l/dyn.ww \
|
||||
selfhost/cmd/w6l/pass.ww selfhost/cmd/w6l/dynout.ww \
|
||||
selfhost/cmd/w6l/out.ww selfhost/cmd/wcc/mem.ww \
|
||||
lib/os/os.ww \
|
||||
lib/os/os.ww lib/time/time.ww \
|
||||
$(BIN)/ww $(BIN)/w6c $(BIN)/w6a $(BIN)/w6l \
|
||||
$(LIB)/libwwrt.a | $(BIN)
|
||||
cd $(BIN) && ./ww build \
|
||||
@@ -181,7 +181,7 @@ $(BIN)/w6l_ww: selfhost/cmd/w6l/main.ww selfhost/cmd/w6l/sym.ww \
|
||||
# The driver pulls in lib/os (default search path) and selfhost/cmd/wcc
|
||||
# (for the bump arena). It then orchestrates w6c/w6a/w6l like the C driver.
|
||||
$(BIN)/ww_ww: selfhost/cmd/ww/main.ww selfhost/cmd/wcc/mem.ww lib/os/os.ww \
|
||||
lib/strconv/strconv.ww \
|
||||
lib/time/time.ww lib/strconv/strconv.ww \
|
||||
$(BIN)/ww $(BIN)/w6c $(BIN)/w6a $(BIN)/w6l \
|
||||
$(LIB)/libwwrt.a | $(BIN)
|
||||
cd $(BIN) && ./ww build \
|
||||
|
||||
21
lib/os/os.ww
21
lib/os/os.ww
@@ -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
|
||||
|
||||
@@ -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(); };
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -16,7 +16,6 @@ static const char *modules[] = {
|
||||
"lib/strings/strings.ww",
|
||||
"lib/io/io.ww",
|
||||
"lib/errors/errors.ww",
|
||||
"lib/os/os.ww",
|
||||
"lib/strconv/strconv.ww",
|
||||
"lib/sort/sort.ww",
|
||||
"lib/path/path.ww",
|
||||
@@ -33,13 +32,15 @@ static const char *modules[] = {
|
||||
"lib/math/random/random.ww",
|
||||
"lib/time/time.ww",
|
||||
"lib/c/libc/libc.ww",
|
||||
/* lib/bufio/bufio.ww and lib/fmt/fmt.ww moved off this list:
|
||||
* both graduated to io.stream-based sinks, which carry cross-
|
||||
* module type refs (*io.stream, io.closed, io.eof) that only
|
||||
* resolve once the driver concatenates `use`d modules. Coverage
|
||||
* lives at lib/bufio/bufiotest.ww + lib/fmt/fmttest.ww (wired
|
||||
* at 998_bufio_run.c and 970_fmt_run.c), plus the bufio.scanline
|
||||
* and fmt.println e2e rows in test/wcc/700_e2e.c. */
|
||||
/* lib/bufio/bufio.ww, lib/fmt/fmt.ww, and lib/os/os.ww moved
|
||||
* off this list: each has cross-module type refs that only
|
||||
* resolve once the driver concatenates `use`d modules. bufio /
|
||||
* fmt graduated to io.stream-based sinks (*io.stream, io.closed,
|
||||
* io.eof); lib/os carries time.instant in filestat post-Commit B.
|
||||
* Coverage lives at lib/bufio/bufiotest.ww + lib/fmt/fmttest.ww +
|
||||
* lib/os/stattest.ww (wired at 998_bufio_run.c, 970_fmt_run.c,
|
||||
* 976_stat_run.c), plus the bufio.scanline / fmt.println e2e rows
|
||||
* in test/wcc/700_e2e.c. */
|
||||
"lib/net/net.ww",
|
||||
NULL
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user