lib/time+test: add types, ops, now
Replaces the lib/time placeholder (a monotonic(*timespec) shim that
predated lib/os's syscall surface). Ships Hare's time module first
cut per ref/hare/time/{duration,instant,arithm,+linux/functions}.ha:
- duration (i64 ns); nanosecond / microsecond / millisecond / second
constants.
- instant (sec, nsec) — Hare's layout, NOT POSIX's nsec:u32. Matches
Linux struct timespec on 64-bit, so &instant lands directly in
clock_gettime.
- clock enum: realtime + monotonic only. The rest of Hare's set
(process_cpu / thread_cpu / boot / realtime_alarm / boot_alarm / tai)
graduates when a caller actually needs it (rule 9).
- now(c: clock) instant — aborts on EINVAL/EFAULT (mirrors Hare's
abort-on-impossible-errno). Deliberately NOT (instant | oserror) to
sidestep task #9's 1-word-payload tagged-return trap.
- add / diff / compare on instants per ref/hare/time/arithm.ha
verbatim.
Deferred to follow-up commits when a caller surfaces: sleep, format /
strftime, time.chrono / time.date calendar, timezone, time.error
sum-return shape, time.unix helpers, time.mult, conversion helpers.
Tests at lib/time/timetest.ww (15 rows, table-pattern, semantic per
Class B doctrine). Driver test/wcc/977_time_run.c slotted between
976_stat_run and 978_intdiv_signed in the 9xx _run band.
examples/cmatrix migrates to the new API in the same commit (sole
pre-existing caller — bisect-clean per rule 11).
Class B bug #16 (sign-extend before IDIVQ) was surfaced by the
negative-duration rows during this work; landed 63332fe..4fa4bcf
before this commit. Rows 8-9 (addneg_noborrow / addneg_borrow) are
the load-bearing Class B exercisers; would have stayed silently wrong
pre-#16.
lib/time's own .s output has a cstage/wwstage label-counter skew in
add (cstage emits add_ct_7/_ce_8/_end_6 vs wwstage _6/_7/_5). Filed
as task #15; non-bootstrap-blocking since lib/time is outside the
selfhost toolchain transitive chain.
This commit is contained in:
@@ -1,15 +1,95 @@
|
||||
// time — clocks. We expose monotonic-ns via a syscall trampoline.
|
||||
// Linux clock_gettime is syscall 228; clock id 1 is CLOCK_MONOTONIC.
|
||||
// Until we can pass struct-by-value the user supplies a buffer.
|
||||
// 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 syscall(num: i64, a: i64, b: i64, c: i64) i64;
|
||||
@symbol("rt_syscall") fn syscall2(num: i64, a: i64, b: i64) i64;
|
||||
@symbol("rt_abort") fn abort(msg: str) void;
|
||||
|
||||
def CLOCK_MONOTONIC: i64 = 1;
|
||||
def SYS_CLOCK_GETTIME: i64 = 228;
|
||||
|
||||
// timespec is {sec, nsec} — 16 bytes. Caller passes a pointer.
|
||||
type timespec = struct { sec: i64, nsec: i64 };
|
||||
// ref/hare/time/duration.ha:6. 290y representable range.
|
||||
export type duration = i64;
|
||||
|
||||
export fn monotonic(ts: *timespec) i32 = {
|
||||
return syscall(SYS_CLOCK_GETTIME, CLOCK_MONOTONIC, ts: i64, 0): i32;
|
||||
// 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;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user