spawned_rt/time.rs
1//! Clock and entropy seam for library code.
2//!
3//! In normal builds [`Instant`] is `std::time::Instant` and [`entropy`] reads
4//! the wall clock, so behaviour is identical to calling them directly. Under
5//! `--cfg spawned_sim` both come from the running simulation: `Instant` reads
6//! virtual time and `entropy` is a stream derived from the simulation seed, so
7//! restart windows, shutdown deadlines, backoff jitter and metrics timings are
8//! deterministic per seed and advance in virtual time.
9
10#[cfg(not(all(spawned_sim, feature = "async")))]
11pub use std::time::Instant;
12
13#[cfg(all(spawned_sim, feature = "async"))]
14pub use crate::tasks::sim::Instant;
15
16/// Seed material for jitter and similar randomization: wall-clock nanoseconds
17/// mixed with a process-wide counter (distinct per call), or, under
18/// simulation, the next value of the simulation's entropy stream.
19pub fn entropy() -> u64 {
20 #[cfg(all(spawned_sim, feature = "async"))]
21 {
22 crate::tasks::sim::entropy()
23 }
24 #[cfg(not(all(spawned_sim, feature = "async")))]
25 {
26 static NEXT: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(1);
27 std::time::SystemTime::now()
28 .duration_since(std::time::UNIX_EPOCH)
29 .unwrap_or_default()
30 .as_nanos() as u64
31 ^ NEXT.fetch_add(1, std::sync::atomic::Ordering::Relaxed)
32 }
33}