use std::{
sync::{Arc, Condvar},
task::Waker,
};
use crate::shared::mutex::StdMutex;
use super::waker::waker_helper;
pub(crate) fn pair() -> (Arc<Suspender>, Waker) {
let suspender = Arc::new(Suspender::new());
let resumer = suspender.clone();
(suspender, waker_helper(resumer))
}
pub(crate) struct Suspender {
lock: StdMutex<State>,
cvar: Condvar,
}
impl Suspender {
pub(crate) fn new() -> Suspender {
Suspender {
lock: StdMutex::new(State::Initial),
cvar: Condvar::new(),
}
}
pub(crate) fn suspend(&self) {
let mut lock = self.lock.lock();
match *lock {
State::Initial => {
*lock = State::Suspended;
while *lock == State::Suspended {
lock = self.cvar.wait(lock).unwrap();
}
}
State::Notified => {
*lock = State::Initial;
}
State::Suspended => {
panic!("cannot suspend a thread that is already in a suspended state")
}
}
}
pub(crate) fn resume(&self) {
let mut lock = self.lock.lock();
if *lock == State::Initial {
*lock = State::Notified;
} else if *lock == State::Suspended {
*lock = State::Notified;
self.cvar.notify_one();
}
}
}
#[derive(PartialEq)]
enum State {
Initial,
Notified,
Suspended,
}