| 1 | use crate::sync::atomic::Ordering::Relaxed; |
| 2 | use crate::sys::futex::{Futex, futex_wait, futex_wake, futex_wake_all}; |
| 3 | use crate::sys::sync::Mutex; |
| 4 | use crate::time::Duration; |
| 5 | |
| 6 | pub 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 | |
| 13 | impl 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 | } |
| 57 | |