std/sys/sync/condvar/
pthread.rs1#![forbid(unsafe_op_in_unsafe_fn)]
2
3use crate::pin::Pin;
4use crate::ptr;
5use crate::sync::atomic::Ordering::Relaxed;
6use crate::sync::atomic::{Atomic, AtomicUsize};
7use crate::sys::pal::sync as pal;
8use crate::sys::sync::{Mutex, OnceBox};
9use crate::time::{Duration, Instant};
10
11pub struct Condvar {
12 cvar: OnceBox<pal::Condvar>,
13 mutex: Atomic<usize>,
14}
15
16impl Condvar {
17 pub const fn new() -> Condvar {
18 Condvar { cvar: OnceBox::new(), mutex: AtomicUsize::new(0) }
19 }
20
21 #[inline]
22 fn get(&self) -> Pin<&pal::Condvar> {
23 self.cvar.get_or_init(|| {
24 let mut cvar = Box::pin(pal::Condvar::new());
25 unsafe { cvar.as_mut().init() };
27 cvar
28 })
29 }
30
31 #[inline]
32 fn verify(&self, mutex: Pin<&pal::Mutex>) {
33 let addr = ptr::from_ref::<pal::Mutex>(&mutex).addr();
34 match self.mutex.compare_exchange(0, addr, Relaxed, Relaxed) {
37 Ok(_) => {} Err(n) if n == addr => {} _ => panic!("attempted to use a condition variable with two mutexes"),
40 }
41 }
42
43 #[inline]
44 pub fn notify_one(&self) {
45 unsafe { self.get().notify_one() }
47 }
48
49 #[inline]
50 pub fn notify_all(&self) {
51 unsafe { self.get().notify_all() }
53 }
54
55 #[inline]
56 pub unsafe fn wait(&self, mutex: &Mutex) {
57 let mutex = unsafe { mutex.pal.get_unchecked() };
60 self.verify(mutex);
61 unsafe { self.get().wait(mutex) }
65 }
66
67 pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
68 let mutex = unsafe { mutex.pal.get_unchecked() };
71 self.verify(mutex);
72
73 if pal::Condvar::PRECISE_TIMEOUT {
74 unsafe { self.get().wait_timeout(mutex, dur) }
78 } else {
79 let now = Instant::now();
81 let woken = unsafe { self.get().wait_timeout(mutex, dur) };
85 woken || now.elapsed() < dur
86 }
87 }
88}