async_lock/
lib.rs

1//! Async synchronization primitives.
2//!
3//! This crate provides the following primitives:
4//!
5//! * [`Barrier`] - enables tasks to synchronize all together at the same time.
6//! * [`Mutex`] - a mutual exclusion lock.
7//! * [`RwLock`] - a reader-writer lock, allowing any number of readers or a single writer.
8//! * [`Semaphore`] - limits the number of concurrent operations.
9//!
10//! ## Relationship with `std::sync`
11//!
12//! In general, you should consider using [`std::sync`] types over types from this crate.
13//!
14//! There are two primary use cases for types from this crate:
15//!
16//! - You need to use a synchronization primitive in a `no_std` environment.
17//! - You need to hold a lock across an `.await` point.
18//!   (Holding an [`std::sync`] lock guard across an `.await` will make your future non-`Send`,
19//!   and is also highly likely to cause deadlocks.)
20//!
21//! If you already use `libstd` and you aren't holding locks across await points (there is a
22//! Clippy lint called [`await_holding_lock`] that emits warnings for this scenario), you should
23//! consider [`std::sync`] instead of this crate. Those types are optimized for the currently
24//! running operating system, are less complex and are generally much faster.
25//!
26//! In contrast, `async-lock`'s notification system uses `std::sync::Mutex` under the hood if
27//! the `std` feature is enabled, and will fall back to a significantly slower strategy if it is
28//! not. So, there are few cases where `async-lock` is a win for performance over [`std::sync`].
29//!
30//! [`std::sync`]: https://doc.rust-lang.org/std/sync/index.html
31//! [`await_holding_lock`]: https://rust-lang.github.io/rust-clippy/stable/index.html#/await_holding_lock
32
33#![cfg_attr(not(feature = "std"), no_std)]
34#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)]
35#![doc(
36    html_favicon_url = "https://raw.githubusercontent.com/smol-rs/smol/master/assets/images/logo_fullsize_transparent.png"
37)]
38#![doc(
39    html_logo_url = "https://raw.githubusercontent.com/smol-rs/smol/master/assets/images/logo_fullsize_transparent.png"
40)]
41
42extern crate alloc;
43
44/// Make the given function const if the given condition is true.
45macro_rules! const_fn {
46    (
47        const_if: #[cfg($($cfg:tt)+)];
48        $(#[$($attr:tt)*])*
49        $vis:vis const fn $($rest:tt)*
50    ) => {
51        #[cfg($($cfg)+)]
52        $(#[$($attr)*])*
53        $vis const fn $($rest)*
54        #[cfg(not($($cfg)+))]
55        $(#[$($attr)*])*
56        $vis fn $($rest)*
57    };
58}
59
60mod barrier;
61mod mutex;
62mod once_cell;
63mod rwlock;
64mod semaphore;
65
66pub use barrier::{Barrier, BarrierWaitResult};
67pub use mutex::{Mutex, MutexGuard, MutexGuardArc};
68pub use once_cell::OnceCell;
69pub use rwlock::{
70    RwLock, RwLockReadGuard, RwLockReadGuardArc, RwLockUpgradableReadGuard,
71    RwLockUpgradableReadGuardArc, RwLockWriteGuard, RwLockWriteGuardArc,
72};
73pub use semaphore::{Semaphore, SemaphoreGuard, SemaphoreGuardArc};
74
75pub mod futures {
76    //! Named futures for use with `async_lock` primitives.
77
78    pub use crate::barrier::BarrierWait;
79    pub use crate::mutex::{Lock, LockArc};
80    pub use crate::rwlock::futures::{
81        Read, ReadArc, UpgradableRead, UpgradableReadArc, Upgrade, UpgradeArc, Write, WriteArc,
82    };
83    pub use crate::semaphore::{Acquire, AcquireArc};
84}
85
86#[cfg(not(loom))]
87/// Synchronization primitive implementation.
88mod sync {
89    pub(super) use core::sync::atomic;
90
91    pub(super) trait WithMut {
92        type Output;
93
94        fn with_mut<F, R>(&mut self, f: F) -> R
95        where
96            F: FnOnce(&mut Self::Output) -> R;
97    }
98
99    impl WithMut for atomic::AtomicUsize {
100        type Output = usize;
101
102        #[inline]
103        fn with_mut<F, R>(&mut self, f: F) -> R
104        where
105            F: FnOnce(&mut Self::Output) -> R,
106        {
107            f(self.get_mut())
108        }
109    }
110}
111
112#[cfg(loom)]
113/// Synchronization primitive implementation.
114mod sync {
115    pub(super) use loom::sync::atomic;
116}
117
118#[cold]
119fn abort() -> ! {
120    // For no_std targets, panicking while panicking is defined as an abort
121    #[cfg(not(feature = "std"))]
122    {
123        struct Bomb;
124
125        impl Drop for Bomb {
126            fn drop(&mut self) {
127                panic!("Panicking while panicking to abort")
128            }
129        }
130
131        let _bomb = Bomb;
132        panic!("Panicking while panicking to abort")
133    }
134
135    // For libstd targets, abort using std::process::abort
136    #[cfg(feature = "std")]
137    std::process::abort()
138}