tiny_std/
sync.rs

1pub(crate) mod mutex;
2pub(crate) mod rwlock;
3
4use core::marker::PhantomData;
5use core::sync::atomic::AtomicU32;
6use core::sync::atomic::Ordering::Relaxed;
7use rusl::error::Errno;
8use rusl::futex::futex_wait;
9use rusl::platform::FutexFlags;
10pub use {mutex::Mutex, mutex::MutexGuard};
11pub use {rwlock::RwLock, rwlock::RwLockReadGuard, rwlock::RwLockWriteGuard};
12
13pub(crate) struct NotSend(PhantomData<*const ()>);
14
15impl NotSend {
16    #[inline]
17    const fn new() -> Self {
18        Self(PhantomData)
19    }
20}
21
22unsafe impl Sync for NotSend {}
23
24#[inline]
25pub(crate) fn futex_wait_fast(futex: &AtomicU32, expect: u32) {
26    loop {
27        if futex.load(Relaxed) != expect {
28            return;
29        }
30        match futex_wait(futex, expect, FutexFlags::PRIVATE, None) {
31            Ok(()) => {
32                return;
33            }
34            Err(e) => {
35                if let Some(code) = e.code {
36                    if code == Errno::EINTR {
37                    } else {
38                        return;
39                    }
40                }
41            }
42        }
43    }
44}
45
46#[cfg(test)]
47mod tests {
48    use crate::sync::futex_wait_fast;
49    use core::sync::atomic::AtomicU32;
50    use rusl::futex::futex_wake;
51
52    #[test]
53    fn wait_fast_shortcircuit() {
54        let futex = AtomicU32::new(0);
55        // We would expect this to hang forever if it didn't work
56        futex_wait_fast(&futex, 1);
57    }
58
59    #[test]
60    fn wait_fast_cant_short() {
61        let futex = std::sync::Arc::new(AtomicU32::new(0));
62        let f_c = futex.clone();
63        let handle = std::thread::spawn(move || {
64            futex_wait_fast(&f_c, 0);
65        });
66        // Just try wake until we wake the thread
67        while futex_wake(&futex, 1).unwrap() == 0 {}
68        handle.join().unwrap();
69    }
70}