     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48

    use crate::sync::atomic::{AtomicUsize, Ordering};
    use crate::sys::mutex as mutex_imp;
    use crate::sys_common::mutex::MovableMutex;

    pub trait CondvarCheck {
        type Check;
    }

    /// For boxed mutexes, a `Condvar` will check it's only ever used with the same
    /// mutex, based on its (stable) address.
    impl CondvarCheck for Box<mutex_imp::Mutex> {
        type Check = SameMutexCheck;
    }

    pub struct SameMutexCheck {
        addr: AtomicUsize,
    }

    #[allow(dead_code)]
    impl SameMutexCheck {
        pub const fn new() -> Self {
            Self { addr: AtomicUsize::new(0) }
        }
        pub fn verify(&self, mutex: &MovableMutex) {
            let addr = mutex.raw() as *const mutex_imp::Mutex as usize;
            match self.addr.compare_exchange(0, addr, Ordering::SeqCst, Ordering::SeqCst) {
                Ok(_) => {}               // Stored the address
                Err(n) if n == addr => {} // Lost a race to store the same address
                _ => panic!("attempted to use a condition variable with two mutexes"),
            }
        }
    }

    /// Unboxed mutexes may move, so `Condvar` can not require its address to stay
    /// constant.
    impl CondvarCheck for mutex_imp::Mutex {
        type Check = NoCheck;
    }

    pub struct NoCheck;

    #[allow(dead_code)]
    impl NoCheck {
        pub const fn new() -> Self {
            Self
        }
        pub fn verify(&self, _: &MovableMutex) {}
    }