1-- The hosted provider's clocks and entropy, written once over
2-- platform/posix: `time.clock` is the monotonic clock and sleeping on it,
3-- `time.wall_clock` the realtime clock, and `io.entropy` the system's own
4-- random bytes.
5
6import core/time
7import platform/posix
8
9-- A second in nanoseconds.
10second: u64 = 1000000000
11
12-- The longest one request to sleep asks for, about eleven days.
13longest: u64 = 1000000 * second
14
15-- The clock `clock` read now. Every hosted system has both clocks, and
16-- reading one fails only when the process is given a bad address, which
17-- no call here gives, so a failure ends the program.
18read: (clock: posix.clock_kind) -> (sample: posix.time_value) =
19 sample = posix.clock_time(clock) else (problem)
20 _ = problem
21 compiler.unreachable()
22 end
23end read
24
25-- The monotonic clock in nanoseconds since the system started, which no
26-- hosted system counts as negative.
27reading: () -> (at: u64) =
28 sample: posix.time_value = read(posix.monotonic_clock)
29 at = u64(sample.seconds) * second + u64(sample.nanoseconds)
30end reading
31
32system_now: (self: host) -> (at: time.instant) =
33 _ = self.failure
34 at = time.instant(reading())
35end system_now
36
37-- The sleep is measured on the clock `now` reads, whatever clock the
38-- system sleeps on: the deadline is taken first, and the system is asked
39-- again for what is left until the clock has reached it, so a sleep a
40-- signal interrupts, or the system ends early, sleeps on for the rest.
41-- A deadline past the clock's last instant is that instant. A system
42-- that refused every sleep would leave this loop reading the clock until
43-- the deadline, which is still never early; none of them does.
44system_sleep: (self: host, span: time.duration) -> none =
45 _ = self.failure
46 start: u64 = reading()
47 room: u64 = (0 -% 1) - start
48 deadline: u64 = if u64(span) > room then 0 -% 1
49 else start + u64(span) end if
50 loop do
51 now: u64 = reading()
52 return when now >= deadline
53 -- No more than a million seconds at once, within what every
54 -- system's sleep takes; the loop sleeps again for the rest.
55 mut left: u64 = deadline - now
56 if left > longest then left = longest end if
57 whole: u64 = left / second
58 posix.sleep((seconds: i64(whole),
59 nanoseconds: u32(left - whole * second))) else (problem)
60 -- Interrupted, or refused: the clock says what is left.
61 _ = problem
62 end
63 end loop
64end system_sleep
65
66system_wall_now: (self: host) -> (at: time.wall_time) =
67 _ = self.failure
68 sample: posix.time_value = read(posix.realtime_clock)
69 at = (seconds: sample.seconds, nanoseconds: sample.nanoseconds)
70end system_wall_now
71
72host is time.clock (now: system_now, sleep: system_sleep)
73host is time.wall_clock (wall_now: system_wall_now)