use std::{
collections::{BTreeMap, BTreeSet},
panic::Location,
sync::{
Arc, LazyLock, OnceLock, Weak,
atomic::{AtomicU64, Ordering},
},
};
use super::{pace::Pacer, sched::Entry, wake::Wake};
use crate::{
common::time::Instant as RealInstant,
flash::{diag::PrimKind, ids::ThreadKey},
native::sync::Mutex,
};
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub(in crate::flash) struct CvId(pub(super) u64);
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub(in crate::flash) struct WaiterId(pub(super) u64);
pub(in crate::flash) struct Clock {
nanos: AtomicU64,
real_epoch: OnceLock<web_time::Instant>,
}
impl Clock {
const fn new() -> Self {
Self {
nanos: AtomicU64::new(crate::flash::Instant::BASE_NANOS),
real_epoch: OnceLock::new(),
}
}
#[cfg(test)]
pub(in crate::flash) fn advance(&self, delta_nanos: u64) {
self.nanos.fetch_add(delta_nanos, Ordering::Release);
}
pub(in crate::flash) fn now_nanos(&self) -> u64 {
self.nanos.load(Ordering::Acquire)
}
pub(in crate::flash) fn real_now_nanos(&self) -> u64 {
let epoch = self.real_epoch.get_or_init(web_time::Instant::now);
let elapsed = u64::try_from(epoch.elapsed().as_nanos()).unwrap_or(u64::MAX);
crate::flash::Instant::BASE_NANOS.saturating_add(elapsed)
}
fn reset(&self) {
self.nanos
.store(crate::flash::Instant::BASE_NANOS, Ordering::Release);
}
pub(super) fn store(&self, nanos: u64) {
self.nanos.store(nanos, Ordering::Release);
}
}
pub(in crate::flash) struct Registry {
pub(super) active_async_holders: BTreeMap<u64, &'static Location<'static>>,
pub(super) active_sync_holders: BTreeMap<ThreadKey, SyncHolder>,
pub(super) next_cv: u64,
pub(super) cv_desc: BTreeMap<u64, CvDesc>,
pub(super) next_id: u64,
pub(super) next_task_id: u64,
pub(super) active: usize,
pub(super) active_async: usize,
}
pub(in crate::flash) struct SyncHolder {
pub(super) name: Option<String>,
}
pub(in crate::flash) struct CvDesc {
pub(super) kind: PrimKind,
pub(super) created_at: &'static Location<'static>,
pub(super) created_on: Option<String>,
}
pub(in crate::flash) struct Scheduler {
pub(super) timed: BTreeMap<(u64, WaiterId), Entry>,
pub(super) indef: BTreeMap<WaiterId, Entry>,
pub(super) yielders: BTreeMap<WaiterId, Wake>,
pub(super) unpark_pending: BTreeSet<ThreadKey>,
pub(super) notify_permits: BTreeSet<CvId>,
pub(super) real_io: usize,
pub(super) pace_anchor: Option<(RealInstant, u64)>,
#[cfg(test)]
pub(super) advance_log: Vec<u64>,
}
pub(in crate::flash) struct Core {
pub(super) registry: Registry,
pub(super) sched: Scheduler,
}
impl Core {
const fn new() -> Self {
Self {
registry: Registry {
active: 0,
active_async: 0,
next_id: 0,
next_cv: 0,
next_task_id: 0,
cv_desc: BTreeMap::new(),
active_async_holders: BTreeMap::new(),
active_sync_holders: BTreeMap::new(),
},
sched: Scheduler {
timed: BTreeMap::new(),
indef: BTreeMap::new(),
yielders: BTreeMap::new(),
unpark_pending: BTreeSet::new(),
notify_permits: BTreeSet::new(),
real_io: 0,
pace_anchor: None,
#[cfg(test)]
advance_log: Vec::new(),
},
}
}
}
pub(in crate::flash) struct FlashInner {
pub(super) core: Mutex<Core>,
pub(super) pacer: Pacer,
pub(in crate::flash) clock: Clock,
}
impl FlashInner {
fn new() -> Arc<Self> {
Arc::new_cyclic(|weak| Self {
clock: Clock::new(),
core: Mutex::new(Core::new()),
pacer: Pacer::new(Weak::clone(weak)),
})
}
#[cfg(test)]
pub(in crate::flash) fn new_arc() -> Arc<Self> {
Self::new()
}
pub(in crate::flash) fn reset(&self) {
self.clock.reset();
*self.core.lock() = Core::new();
}
}
pub(in crate::flash) static FLASH: LazyLock<Arc<FlashInner>> = LazyLock::new(FlashInner::new);