1-- Time: a monotonic clock and sleeping on it, and a wall clock, two
2-- concepts beside the others and outside `world`, so a provider without
3-- a clock, and a firmware image that never asks for the time, carries
4-- none of them. Time is counted in nanoseconds in a `u64`: no floating
5-- point, the same arithmetic on every target, and room for 584 years.
6
7duration_value: type = distinct u64
8instant_value: type = distinct u64
9
10--- A span of time, a whole number of nanoseconds from zero to 2^64 - 1,
11--- about 584 years. `u64(span)` is the count and `io.duration(n)` makes
12--- one, as `nanoseconds` does; `milliseconds` and the others make one from
13--- a coarser count and trap when it would not fit. Two spans compare with
14--- `==`, `<>`, `<`, `<=`, `>` and `>=`, as their counts do; the type has
15--- no arithmetic of its own, so an instant is never added to an instant.
16public duration: type = duration_value
17
18--- A reading of a monotonic clock: nanoseconds since a start the provider
19--- fixes, which is the system's boot on Linux. Only the difference
20--- between two readings of one provider means anything, `elapsed`; the
21--- count is `u64(at)`. Two instants compare with `==`, `<>`, `<`, `<=`,
22--- `>` and `>=`, as their counts do.
23public instant: type = instant_value
24
25--- A reading of the wall clock: UTC seconds since 1970-01-01T00:00:00,
26--- negative before it, and the nanoseconds after them, from 0 to
27--- 999,999,999. Leap seconds are not counted, as POSIX counts none.
28--- Calendars, time zones and formatting a date are not this library's.
29public wall_time: type = struct
30 seconds: i64
31 nanoseconds: u32
32end wall_time
33
34--- A monotonic clock and sleeping on it. `now` never goes back: a later
35--- reading of one provider is never less than an earlier one, whatever
36--- the wall clock does. `sleep` returns once at least `span` has passed
37--- on this clock, measured from when it was called; it may return later,
38--- as late as the system schedules it, and never sooner.
39public clock: type = concept (provider: type)
40 --- The clock's reading now.
41 now: (self: provider) -> (at: instant)
42 --- Wait until at least `span` has passed on this clock.
43 sleep: (self: provider, span: duration) -> none
44end clock
45
46--- The wall clock: what time it is in UTC, as the system keeps it. It is
47--- a concept of its own because a firmware image may count time without
48--- knowing the date, and because the system may set this clock, so two
49--- readings may go back; time a task with `clock`, never with this.
50public wall_clock: type = concept (provider: type)
51 --- The wall clock's reading now.
52 wall_now: (self: provider) -> (at: wall_time)
53end wall_clock
54
55--- The reading of a monotonic clock now, through `clock` evidence.
56public now: (provider: type is clock, host: provider) -> (at: instant) =
57 at = provider.now(host)
58end now
59
60--- Wait until at least `span` has passed on the provider's monotonic
61--- clock. A sleep a signal interrupts on a hosted system sleeps on for
62--- what is left; a sleep of zero returns at once.
63public sleep: (provider: type is clock, host: provider, span: duration)
64 -> none =
65 provider.sleep(host, span)
66end sleep
67
68--- The wall clock's reading now, through `wall_clock` evidence.
69public wall_now: (provider: type is wall_clock, host: provider)
70 -> (at: wall_time) =
71 at = provider.wall_now(host)
72end wall_now
73
74--- A span of `count` nanoseconds.
75public nanoseconds: (count: u64) -> (span: duration) =
76 span = duration_value(count)
77end nanoseconds
78
79--- A span of `count` microseconds; it traps beyond 584 years.
80public microseconds: (count: u64) -> (span: duration) =
81 span = duration_value(count * 1000)
82end microseconds
83
84--- A span of `count` milliseconds; it traps beyond 584 years.
85public milliseconds: (count: u64) -> (span: duration) =
86 span = duration_value(count * 1000000)
87end milliseconds
88
89--- A span of `count` seconds; it traps beyond 584 years.
90public seconds: (count: u64) -> (span: duration) =
91 span = duration_value(count * 1000000000)
92end seconds
93
94--- The span from `earlier` to `later`, two readings of one clock taken in
95--- that order. It traps when `later` is the earlier of the two, which
96--- two readings of one monotonic clock taken in order never are.
97public elapsed: (earlier: instant, later: instant) -> (span: duration) =
98 span = duration_value(u64(later) - u64(earlier))
99end elapsed
100
101--- The instant `span` after `at`, a deadline; it traps past the clock's
102--- last instant, 584 years after its start.
103public later: (at: instant, span: duration) -> (result: instant) =
104 result = instant_value(u64(at) + u64(span))
105end later
106
107--- The whole milliseconds in `span`, rounded down.
108public in_milliseconds: (span: duration) -> (count: u64) =
109 count = u64(span) / 1000000
110end in_milliseconds
111
112-- A clock a test sets and advances, beside the memory world.
113
114--- Caller-owned state of a manual clock: what its monotonic clock reads,
115--- in nanoseconds, what its wall clock reads, and how often each was read
116--- and slept on and how long. Declare it `zeroed` and give it to
117--- `clock_over`, which fills it; it must outlive the clock's handle. Its
118--- fields may be read, and the readings set, while the handle is in use:
119--- set `monotonic` only forward, as a monotonic clock never goes back, and
120--- `wall_seconds` either way, as a system's wall clock may be set.
121public clock_space: type = struct
122 monotonic: u64
123 wall_seconds: i64
124 wall_nanoseconds: u32
125 readings: usize
126 sleeps: usize
127 slept: u64
128end clock_space
129
130manual_value: type = struct
131 state: ptr mut clock_space
132end manual_value
133
134--- A clock that moves only when it is told: `advance` moves it, and
135--- `sleep` advances it by exactly the span asked and returns at once, so a
136--- test of code that sleeps or times itself takes no time and gives the
137--- same answer every run. Both of its clocks move together. A provider
138--- of `clock` and `wall_clock`; copies share the state.
139public manual_clock: type = manual_value
140
141--- Fill `state` for a manual clock whose monotonic clock reads `start` and
142--- whose wall clock reads `wall`, and return its handle.
143public clock_over: (inout state: clock_space, start: instant,
144 wall: wall_time) -> (host: manual_clock from state) =
145 state = (monotonic: u64(start), wall_seconds: wall.seconds,
146 wall_nanoseconds: wall.nanoseconds, readings: 0, sleeps: 0,
147 slept: 0)
148 host = (state: addr state)
149end clock_over
150
151--- Move a manual clock's monotonic and wall clocks forward by `span`; it
152--- traps past the monotonic clock's last instant.
153public advance: (host: manual_clock, span: duration) -> none =
154 state: ptr mut clock_space = host.state
155 state.val.monotonic = state.val.monotonic + u64(span)
156 whole: u64 = u64(span) / 1000000000
157 mut part: u32 = state.val.wall_nanoseconds
158 + u32(u64(span) - whole * 1000000000)
159 mut carried: i64 = i64(whole)
160 if part >= 1000000000 then
161 part -= 1000000000
162 inc carried
163 end if
164 state.val.wall_seconds = state.val.wall_seconds + carried
165 state.val.wall_nanoseconds = part
166end advance
167
168manual_now: (self: manual_clock) -> (at: instant) =
169 inc self.state.val.readings
170 at = instant_value(self.state.val.monotonic)
171end manual_now
172
173manual_sleep: (self: manual_clock, span: duration) -> none =
174 inc self.state.val.sleeps
175 self.state.val.slept = self.state.val.slept + u64(span)
176 advance(self, span)
177end manual_sleep
178
179manual_wall_now: (self: manual_clock) -> (at: wall_time) =
180 inc self.state.val.readings
181 at = (seconds: self.state.val.wall_seconds,
182 nanoseconds: self.state.val.wall_nanoseconds)
183end manual_wall_now
184
185manual_clock is clock (now: manual_now, sleep: manual_sleep)
186manual_clock is wall_clock (wall_now: manual_wall_now)