use std::panic::Location;
use super::mutex::MutexGuard;
use crate::{
common::time::Instant as RealInstant,
flash::{
Instant,
diag::PrimKind,
flash_ambient,
ids::{Backend, trace_native_from_ambient},
system,
},
native::sync::Condvar as NativeCondvar,
};
pub struct Condvar {
backend: Backend,
native: NativeCondvar,
}
impl Condvar {
#[inline]
pub fn notify_all(&self) {
match self.backend {
Backend::Engine(cvid) => system::signal_condvar(cvid, true),
Backend::Native => {
trace_native_from_ambient("condvar", "notify_all");
self.native.notify_all();
}
}
}
#[inline]
pub fn notify_one(&self) {
match self.backend {
Backend::Engine(cvid) => system::signal_condvar(cvid, false),
Backend::Native => {
trace_native_from_ambient("condvar", "notify_one");
self.native.notify_one();
}
}
}
#[inline]
#[must_use]
pub fn wait<'a, T>(&self, mut guard: MutexGuard<'a, T>) -> MutexGuard<'a, T> {
match self.backend {
Backend::Engine(cvid) => {
let (token, adv, wait) = system::register_condvar_untimed(cvid);
guard.unlocked(move || {
adv.fire();
token.wait();
wait.resume();
});
guard
}
Backend::Native => {
trace_native_from_ambient("condvar", "wait");
if let Some(m) = guard.meta() {
m.released();
}
self.native.wait_ref(guard.native_mut());
if let Some(m) = guard.meta() {
m.acquired(guard.site());
}
guard
}
}
}
#[inline]
#[must_use]
pub fn wait_timeout<'a, T>(
&self,
mut guard: MutexGuard<'a, T>,
deadline: Instant,
) -> MutexGuard<'a, T> {
match self.backend {
Backend::Engine(cvid) => {
let (token, adv, wait) =
system::register_condvar_timed(deadline.as_virtual_nanos(), cvid);
guard.unlocked(move || {
adv.fire();
token.wait();
wait.resume();
});
guard
}
Backend::Native => {
trace_native_from_ambient("condvar", "wait_timeout");
if let Some(m) = guard.meta() {
m.released();
}
let remaining = deadline.saturating_duration_since(Instant::now());
self.native
.wait_timeout_ref(guard.native_mut(), RealInstant::now() + remaining);
if let Some(m) = guard.meta() {
m.acquired(guard.site());
}
guard
}
}
}
}
impl Default for Condvar {
#[track_caller]
fn default() -> Self {
Self {
backend: if flash_ambient() {
let cvid = system::next_condvar_id();
system::describe_cvid(cvid, PrimKind::Condvar, Location::caller());
Backend::Engine(cvid)
} else {
Backend::Native
},
native: NativeCondvar::default(),
}
}
}