core/time
Shared: available on every enabled target.
Spans and instants of time counted in nanoseconds, the wall clock's time, and the monotonic and wall clock concepts.
Time is two concepts outside world, so an image that never asks the time carries neither. clock is a monotonic clock, now, which never goes back, and sleeping on it, sleep, which returns once at least the span asked has passed on that clock and never sooner; wall_clock is the system's UTC time, wall_now, a wall_time of seconds since 1970 and the nanoseconds after them, which the system may set and so may go back, so a task is timed with clock. A reading is an instant and a span a duration, each a distinct u64 of nanoseconds, which holds 584 years: u64(at) is the count, two of a kind compare with ==, <>, <, <=, > and >= as their counts do, and neither has arithmetic of its own, so elapsed is the span between two readings taken in order, trapping if the second is the earlier, later a deadline, nanoseconds, microseconds, milliseconds and seconds make a span, trapping past 584 years, and in_milliseconds rounds one down. There is no floating point, and the arithmetic is the same on every target. Calendars, time zones and formatting a date are not here. clock_over makes a fake.clock over the caller's clock_space, which moves only when a test says: advance moves both its clocks, a sleep advances them by exactly what it asks and returns at once, the test may set either reading through the state, and the state counts readings, sleeps and the time slept. entropy is a third, fill_random, which fills all of a buffer with unpredictable bytes or fails io_failed; entropy_over makes fake.entropy over the caller's bytes, given in order, a request for more than is left failing, so a program that seeds itself from entropy runs the same in every test. runtime/clock-manual and runtime/random-sequence run both fakes on Cortex-M0.
Items
- clock concept
- wall_clock concept
- duration type
- instant type
- wall_time type
- elapsed function
- in_milliseconds function
- later function
- microseconds function
- milliseconds function
- nanoseconds function
- now function
- seconds function
- sleep function
- wall_now function
Executable example
This complete program is maintained in the repository runtime tests. View source.
-- core/io's manual clock, which a test sets and advances: code that -- times itself and sleeps, written against the `clock` and `wall_clock` -- concepts, runs over it in no time and gives the same answer on every -- target, Cortex-M0 included. A sleep advances the clock by exactly -- what was asked, both of its clocks move together, the wall clock -- carries its nanoseconds into seconds, and spans and instants convert -- as their counts say. Each check that fails returns its own code. import core/io/fake import core/time -- Poll until the clock has moved on by SPAN, sleeping STEP between -- readings, and say how many times it slept: a routine that only knows -- the `clock` concept. waited: (provider: type is time.clock, host: provider, span: time.duration, step: time.duration) -> (sleeps: usize) = start: time.instant = time.now(host) deadline: time.instant = time.later(start, span) sleeps = 0 while time.now(host) < deadline do time.sleep(host, step) inc sleeps end while end waited -- How long WORK took, timed on HOST's clock. timed: (provider: type is time.clock, host: provider, work: time.duration) -> (took: time.duration) = start: time.instant = time.now(host) time.sleep(host, work) took = time.elapsed(start, time.now(host)) end timed public main: () -> (code: i32) = code = 1 return when u64(time.nanoseconds(7)) <> 7 or u64(time.microseconds(3)) <> 3000 or u64(time.milliseconds(250)) <> 250000000 or u64(time.seconds(90)) <> 90000000000 or time.in_milliseconds(time.nanoseconds(1999999)) <> 1 or time.duration(5) <> time.nanoseconds(5) code = 2 mut state: fake.clock_space = zeroed clock := fake.clock_over(state, time.instant(1000), (seconds: 1767225600, nanoseconds: 999999000)) return when u64(time.now(clock)) <> 1000 took: time.duration = timed(clock, time.milliseconds(250)) return when took <> time.milliseconds(250) or state.sleeps <> 1 or state.slept <> 250000000 code = 3 -- The wall clock moved with it, carrying past a whole second. wall: time.wall_time = time.wall_now(clock) return when wall.seconds <> 1767225601 or wall.nanoseconds <> 249999000 code = 4 -- Three sleeps of 400 ms pass a second; the third reaches it. sleeps: usize = waited(clock, time.seconds(1), time.milliseconds(400)) return when sleeps <> 3 or state.monotonic <> 1000 + 1450000000 code = 5 -- A sleep of zero does not move the clock; `advance` moves it as a -- test says, and a test may set the wall clock back. before: time.instant = time.now(clock) time.sleep(clock, time.duration(0)) return when time.now(clock) <> before fake.advance(clock, time.seconds(2)) return when u64(time.elapsed(before, time.now(clock))) <> 2000000000 state.wall_seconds = 0 set_back: time.wall_time = time.wall_now(clock) return when set_back.seconds <> 0 or set_back.nanoseconds <> 449999000 code = 6 return when state.readings < 10 or state.sleeps <> 5 deadline: time.instant = time.later(time.instant(1), time.nanoseconds(2)) return when u64(deadline) <> 3 code = 42 end main
clock concept
public clock: type = concept (provider: type)
--- The clock's reading now.
now: (self: provider) -> (at: instant)
--- Wait until at least `span` has passed on this clock.
sleep: (self: provider, span: duration) -> none
end clockA monotonic clock and sleeping on it. now never goes back: a later reading of one provider is never less than an earlier one, whatever the wall clock does. sleep returns once at least span has passed on this clock, measured from when it was called; it may return later, as late as the system schedules it, and never sooner.
wall_clock concept
public wall_clock: type = concept (provider: type)
--- The wall clock's reading now.
wall_now: (self: provider) -> (at: wall_time)
end wall_clockThe wall clock: what time it is in UTC, as the system keeps it. It is a concept of its own because a firmware image may count time without knowing the date, and because the system may set this clock, so two readings may go back; time a task with clock, never with this.
duration type
public duration: type = duration_valueA span of time, a whole number of nanoseconds from zero to 2^64 - 1, about 584 years. u64(span) is the count and io.duration(n) makes one, as nanoseconds does; milliseconds and the others make one from a coarser count and trap when it would not fit. Two spans compare with ==, <>, <, <=, > and >=, as their counts do; the type has no arithmetic of its own, so an instant is never added to an instant.
instant type
public instant: type = instant_valueA reading of a monotonic clock: nanoseconds since a start the provider fixes, which is the system's boot on Linux. Only the difference between two readings of one provider means anything, elapsed; the count is u64(at). Two instants compare with ==, <>, <, <=, > and >=, as their counts do.
wall_time type
public wall_time: type = struct
seconds: i64
nanoseconds: u32
end wall_timeA reading of the wall clock: UTC seconds since 1970-01-01T00:00:00, negative before it, and the nanoseconds after them, from 0 to 999,999,999. Leap seconds are not counted, as POSIX counts none. Calendars, time zones and formatting a date are not this library's.
elapsed function
public elapsed: (earlier: instant, later: instant) -> (span: duration)The span from earlier to later, two readings of one clock taken in that order. It traps when later is the earlier of the two, which two readings of one monotonic clock taken in order never are.
in_milliseconds function
public in_milliseconds: (span: duration) -> (count: u64)The whole milliseconds in span, rounded down.
later function
public later: (at: instant, span: duration) -> (result: instant)The instant span after at, a deadline; it traps past the clock's last instant, 584 years after its start.
microseconds function
public microseconds: (count: u64) -> (span: duration)A span of count microseconds; it traps beyond 584 years.
milliseconds function
public milliseconds: (count: u64) -> (span: duration)A span of count milliseconds; it traps beyond 584 years.
nanoseconds function
public nanoseconds: (count: u64) -> (span: duration)A span of count nanoseconds.
now function
public now: (provider: type is clock, host: provider) -> (at: instant)The reading of a monotonic clock now, through clock evidence.
seconds function
public seconds: (count: u64) -> (span: duration)A span of count seconds; it traps beyond 584 years.
sleep function
public sleep: (provider: type is clock, host: provider, span: duration)
-> noneWait until at least span has passed on the provider's monotonic clock. A sleep a signal interrupts on a hosted system sleeps on for what is left; a sleep of zero returns at once.
wall_now function
public wall_now: (provider: type is wall_clock, host: provider)
-> (at: wall_time)The wall clock's reading now, through wall_clock evidence.