use std::sync::Mutex;
use std::time::Instant;
use thread_aware::affinity::Affinity;
use thread_aware::{PerCore, ThreadAware};
use crate::timers::Timers;
#[derive(Debug, Clone)]
pub(crate) enum ClockState {
System(SynchronizedTimers),
#[cfg(any(feature = "test-util", test))]
ClockControl(crate::ClockControl),
}
impl ThreadAware for ClockState {
fn relocate(&mut self, source: Option<Affinity>, destination: Affinity) {
match self {
Self::System(synchronized_timers) => synchronized_timers.relocate(source, destination),
#[cfg(any(feature = "test-util", test))]
Self::ClockControl(clock_control) => clock_control.relocate(source, destination),
}
}
}
impl ClockState {
pub(crate) fn new_system() -> Self {
Self::System(SynchronizedTimers::new_isolated())
}
#[cfg(any(feature = "rt-shared", test))]
pub(crate) fn new_system_shared() -> Self {
Self::System(SynchronizedTimers::new_shared())
}
}
impl ClockState {
pub(crate) fn timers_len(&self) -> usize {
match self {
#[cfg(any(feature = "test-util", test))]
Self::ClockControl(control) => control.timers_len(),
Self::System(timers) => timers.with_timers(|t| t.len()),
}
}
pub(crate) fn alive(&self) -> bool {
match self {
#[cfg(any(feature = "test-util", test))]
Self::ClockControl(_) => true,
Self::System(timers) => timers.with_timers(|t| t.alive()),
}
}
#[cfg_attr(test, mutants::skip)] pub(crate) fn is_unique(&self) -> bool {
match self {
Self::System(timers) => timers.is_unique(),
#[cfg(any(feature = "test-util", test))]
Self::ClockControl(control) => control.is_unique(),
}
}
}
#[derive(Debug, Clone)]
pub(crate) enum SynchronizedTimers {
#[cfg(any(feature = "rt-shared", test))]
Shared(std::sync::Arc<Mutex<Timers>>),
Isolated(thread_aware::Arc<Mutex<Timers>, PerCore>),
}
impl ThreadAware for SynchronizedTimers {
fn relocate(&mut self, source: Option<Affinity>, destination: Affinity) {
match self {
#[cfg(any(feature = "rt-shared", test))]
Self::Shared(_) => {}
Self::Isolated(timers) => timers.relocate(source, destination),
}
}
}
impl SynchronizedTimers {
pub(crate) fn new_isolated() -> Self {
Self::Isolated(thread_aware::Arc::new(|| Mutex::new(Timers::default())))
}
#[cfg(any(feature = "rt-shared", test))]
pub(crate) fn new_shared() -> Self {
Self::Shared(std::sync::Arc::new(Mutex::new(Timers::default())))
}
pub(super) fn with_timers<F, R>(&self, f: F) -> R
where
F: FnOnce(&mut Timers) -> R,
{
let mut timers = match self {
#[cfg(any(feature = "rt-shared", test))]
Self::Shared(timers) => timers.lock().expect("timers lock poisoned"),
Self::Isolated(timers) => timers.lock().expect("timers lock poisoned"),
};
f(&mut timers)
}
#[cfg_attr(test, mutants::skip)] pub(crate) fn try_advance_timers(&self, now: Instant) -> Option<Instant> {
self.with_timers(|timers| timers.advance_timers(now))
}
#[cfg_attr(test, mutants::skip)] pub(crate) fn is_unique(&self) -> bool {
match self {
#[cfg(any(feature = "rt-shared", test))]
Self::Shared(timers) => std::sync::Arc::strong_count(timers) == 1,
Self::Isolated(timers) => thread_aware::Arc::strong_count(timers) == 1,
}
}
}
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn clock_state_send_and_sync() {
static_assertions::assert_impl_all!(ClockState: Send, Sync);
}
}