silk/monotonic_clock
Profiles: aarch64-apple-darwin, aarch64-unknown-linux-gnu, aarch64-unknown-linux-gnu-no-libc, wasm32-unknown-unknown, x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu-no-libc.
Provider-replaceable monotonic marks, resolution, and deadline waits.
When to use
Require MonotonicClock to measure elapsed time or wait for a provider-local deadline. Use
silk.system_clock when a value must correspond to a human date or external Unix timestamp.
Details
A monotonic mark uses Instant with an unspecified origin. Successive reads from one unchanged
provider are non-decreasing, although equal marks are permitted. Marks and absolute deadlines
are meaningful only on the logical provider timeline that produced them.
Gotchas
The shared Instant representation cannot statically prevent mixing system time or marks from
different providers. Native OS waits block the calling host thread and do not park one Fiber;
scheduler-owned tasks receive a lexical replacement whose waits park only that task. Virtual
providers may satisfy a wait by advancing their own timeline without sleeping. An
invalid or unrepresentable provider result traps because this service has no typed failure
channel.
Examples
Advance a virtual clock through lexical provision
import silk.effect {Effect}
import silk.monotonic_clock {MonotonicClock}
import silk.system_clock {SystemClock, Instant}
struct VirtualClock {
mark: Instant
}
impl MonotonicClock for VirtualClock {
effect fn now(self: &mut Self) -> Instant {
return SystemClock.make(SystemClock.seconds(&self.mark), SystemClock.nanoseconds(&self.mark))
}
effect fn getResolution(self: &mut Self) -> u64 {
return 1
}
effect fn waitUntil(self: &mut Self, when: Instant) -> () {
let seconds = SystemClock.seconds(&when)
let currentSeconds = SystemClock.seconds(&self.mark)
if seconds > currentSeconds || (seconds == currentSeconds && SystemClock.nanoseconds(&when) > SystemClock.nanoseconds(
&self.mark,
)) {
self.mark = move when
}
return ()
}
effect fn waitFor(self: &mut Self, howLong: u64) -> () {
self.mark = MonotonicClock.deadlineAfter(&self.mark, howLong)
return ()
}
}
pub fn main() -> i32 {
let mut clock = VirtualClock {mark: SystemClock.make(0, 0)}
run MonotonicClock.waitFor(300ms)
|> Effect.provideMut<MonotonicClock>(&mut clock)
if SystemClock.nanoseconds(&clock.mark) == 300000000 {
return 42
}
return 0
}Import as MonotonicClock with import silk.monotonic_clock { MonotonicClock }.
Public declarations: 1.
MonotonicClock
pub service MonotonicClockAn explicit provider of monotonic marks, nominal resolution, and deadline waits.
Details
Exclusive access permits deterministic providers to advance their timeline and record waits. Every operation belongs to the same logical provider timeline.
Operation now
effect<'static> fn now() -> Instant ? &mut MonotonicClockReads a canonical mark on the active provider's unspecified timeline. Successive reads are non-decreasing but may be equal.
Operation getResolution
effect<'static> fn getResolution() -> u64 ? &mut MonotonicClockReturns the provider-reported positive nominal resolution in whole nanoseconds. The value may be a lower bound on actual observable precision.
Operation waitUntil
effect<'static> fn waitUntil(when: Instant) -> () ? &mut MonotonicClockWaits until the provider's logical mark is at least when.
Gotchas
when must be a canonical mark from the same logical provider. A reached or past deadline
returns immediately. The official native provider blocks its calling host thread.
Operation waitFor
effect<'static> fn waitFor(howLong: u64) -> () ? &mut MonotonicClockWaits for at least howLong nanoseconds on the provider's logical timeline.
Gotchas
A zero duration requires no positive timeline advance. An implementation traps rather than wrapping when the derived absolute deadline cannot be represented.
Associated function MonotonicClock.deadlineAfter
pub fn deadlineAfter<'life0>(start: &'life0 silk/system_clock.Instant, howLong: u64) -> InstantDerives the canonical absolute deadline howLong nanoseconds after start.
Details
The addition is performed in split seconds and nanoseconds so every u64 duration is accepted
whenever the resulting signed-seconds Instant remains representable. Fractional overflow
carries exactly once into seconds.
Gotchas
This operation traps rather than wrapping when the resulting whole seconds exceed the
representable i64 range. start must belong to the provider timeline on which the deadline
will be used.