use crate::common::mutex::*;
use crate::ctx::*;
use crate::ptr::*;
use crate::scheduler::*;
#[derive(Clone)]
pub struct Condvar {
pub(crate) wait_queue: Ptr<std::collections::LinkedList<crate::ptr::Ptr<Context>>>,
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum CvStatus {
NoTimeout = 1,
Timeout,
}
impl Condvar {
pub fn new() -> Self {
Self {
wait_queue: Ptr::new(std::collections::LinkedList::new()),
}
}
pub fn wait_for_mutex(&self, m: &Mutex) {
let active_ctx = RUNTIME.with(|rt| rt.active_ctx);
self.wait_queue.get().push_back(active_ctx);
active_ctx.get().twstatus.store(
self as *const Condvar as *mut i8,
std::sync::atomic::Ordering::Release,
);
m.unlock();
yield_thread();
m.lock();
}
pub fn wait_pred(&self, m: &Mutex, mut pred: impl FnMut() -> bool) {
while !pred() {
self.wait_for_mutex(m);
}
}
pub fn notify_one(&self) {
while let Some(ctx) = self.wait_queue.get().pop_front() {
let expected = self as *const Condvar as *mut i8;
let result = ctx.get().twstatus.compare_exchange(
expected,
-1i8 as *mut i8,
std::sync::atomic::Ordering::Acquire,
std::sync::atomic::Ordering::Relaxed,
);
match result {
Ok(_) => {
yield_thread();
break;
}
Err(x) => {
if x.is_null() {
yield_thread();
}
break;
}
}
}
}
pub fn notify_all(&self) {
while let Some(ctx) = self.wait_queue.get().pop_front() {
let expected = self as *const Condvar as *mut i8;
let result = ctx.get().twstatus.compare_exchange(
expected,
-1i8 as *mut i8,
std::sync::atomic::Ordering::Acquire,
std::sync::atomic::Ordering::Relaxed,
);
match result {
Ok(_) => {
crate::yield_thread();
break;
}
Err(x) => {
if x.is_null() {
crate::yield_thread();
break;
}
}
}
}
}
}
impl Drop for Condvar {
fn drop(&mut self) {
unsafe { std::intrinsics::drop_in_place(self.wait_queue.0) }
}
}