std/sys/sync/condvar/
futex.rs

1use crate::sync::atomic::Ordering::Relaxed;
2use crate::sys::futex::{Futex, futex_wait, futex_wake, futex_wake_all};
3use crate::sys::sync::Mutex;
4use crate::time::Duration;
5
6pub struct Condvar {
7    // The value of this atomic is simply incremented on every notification.
8    // This is used by `.wait()` to not miss any notifications after
9    // unlocking the mutex and before waiting for notifications.
10    futex: Futex,
11}
12
13impl Condvar {
14    #[inline]
15    pub const fn new() -> Self {
16        Self { futex: Futex::new(0) }
17    }
18
19    // All the memory orderings here are `Relaxed`,
20    // because synchronization is done by unlocking and locking the mutex.
21
22    pub fn notify_one(&self) {
23        self.futex.fetch_add(1, Relaxed);
24        futex_wake(&self.futex);
25    }
26
27    pub fn notify_all(&self) {
28        self.futex.fetch_add(1, Relaxed);
29        futex_wake_all(&self.futex);
30    }
31
32    pub unsafe fn wait(&self, mutex: &Mutex) {
33        self.wait_optional_timeout(mutex, None);
34    }
35
36    pub unsafe fn wait_timeout(&self, mutex: &Mutex, timeout: Duration) -> bool {
37        self.wait_optional_timeout(mutex, Some(timeout))
38    }
39
40    unsafe fn wait_optional_timeout(&self, mutex: &Mutex, timeout: Option<Duration>) -> bool {
41        // Examine the notification counter _before_ we unlock the mutex.
42        let futex_value = self.futex.load(Relaxed);
43
44        // Unlock the mutex before going to sleep.
45        mutex.unlock();
46
47        // Wait, but only if there hasn't been any
48        // notification since we unlocked the mutex.
49        let r = futex_wait(&self.futex, futex_value, timeout);
50
51        // Lock the mutex again.
52        mutex.lock();
53
54        r
55    }
56}