ostd/sync/rwmutex.rs
1// SPDX-License-Identifier: MPL-2.0
2
3use core::{
4 cell::UnsafeCell,
5 fmt,
6 ops::{Deref, DerefMut},
7 sync::atomic::{
8 AtomicUsize,
9 Ordering::{AcqRel, Acquire, Relaxed, Release},
10 },
11};
12
13use super::WaitQueue;
14
15/// A mutex that provides data access to either one writer or many readers.
16///
17/// # Overview
18///
19/// This mutex allows for multiple readers, or at most one writer to access
20/// at any point in time. The writer of this mutex has exclusive access to
21/// modify the underlying data, while the readers are allowed shared and
22/// read-only access.
23///
24/// The writing and reading portions cannot be active simultaneously, when
25/// one portion is in progress, the other portion will sleep. This is
26/// suitable for scenarios where the mutex is expected to be held for a
27/// period of time, which can avoid wasting CPU resources.
28///
29/// This implementation provides the upgradeable read mutex (`upread mutex`).
30/// The `upread mutex` can be upgraded to write mutex atomically, useful in
31/// scenarios where a decision to write is made after reading.
32///
33/// The type parameter `T` represents the data that this mutex is protecting.
34/// It is necessary for `T` to satisfy [`Send`] to be shared across tasks and
35/// [`Sync`] to permit concurrent access via readers. The [`Deref`] method (and
36/// [`DerefMut`] for the writer) is implemented for the RAII guards returned
37/// by the locking methods, which allows for the access to the protected data
38/// while the mutex is held.
39///
40/// # Usage
41///
42/// The mutex can be used in scenarios where data needs to be read frequently
43/// but written to occasionally.
44///
45/// Use `upread mutex` in scenarios where related checking is performed before
46/// modification to effectively avoid deadlocks and improve efficiency.
47///
48/// # Safety
49///
50/// Avoid using `RwMutex` in an interrupt context, as it may result in sleeping
51/// and never being awakened.
52///
53/// # Examples
54///
55/// ```
56/// use ostd::sync::RwMutex;
57///
58/// let mutex = RwMutex::new(5)
59///
60/// // many read mutexes can be held at once
61/// {
62/// let r1 = mutex.read();
63/// let r2 = mutex.read();
64/// assert_eq!(*r1, 5);
65/// assert_eq!(*r2, 5);
66///
67/// // Upgradeable read mutex can share access to data with read mutexes
68/// let r3 = mutex.upread();
69/// assert_eq!(*r3, 5);
70/// drop(r1);
71/// drop(r2);
72/// // read mutexes are dropped at this point
73///
74/// // An upread mutex can only be upgraded successfully after all the
75/// // read mutexes are released, otherwise it will spin-wait.
76/// let mut w1 = r3.upgrade();
77/// *w1 += 1;
78/// assert_eq!(*w1, 6);
79/// } // upread mutex are dropped at this point
80///
81/// {
82/// // Only one write mutex can be held at a time
83/// let mut w2 = mutex.write();
84/// *w2 += 1;
85/// assert_eq!(*w2, 7);
86/// } // write mutex is dropped at this point
87/// ```
88pub struct RwMutex<T: ?Sized> {
89 /// The internal representation of the mutex state is as follows:
90 /// - **Bit 63:** Writer mutex.
91 /// - **Bit 62:** Upgradeable reader mutex.
92 /// - **Bit 61:** Indicates if an upgradeable reader is being upgraded.
93 /// - **Bits 60-0:** Reader mutex count.
94 lock: AtomicUsize,
95 /// Threads that fail to acquire the mutex will sleep on this waitqueue.
96 queue: WaitQueue,
97 val: UnsafeCell<T>,
98}
99
100const READER: usize = 1;
101const WRITER: usize = 1 << (usize::BITS - 1);
102const UPGRADEABLE_READER: usize = 1 << (usize::BITS - 2);
103const BEING_UPGRADED: usize = 1 << (usize::BITS - 3);
104
105/// This bit is reserved as an overflow sentinel.
106/// For more details, see comments on the `MAX_READER` constant
107/// in the [`super::rwlock`] module.
108const MAX_READER: usize = 1 << (usize::BITS - 4);
109
110impl<T> RwMutex<T> {
111 /// Creates a new read-write mutex with an initial value.
112 pub const fn new(val: T) -> Self {
113 Self {
114 lock: AtomicUsize::new(0),
115 queue: WaitQueue::new(),
116 val: UnsafeCell::new(val),
117 }
118 }
119}
120
121impl<T: ?Sized> RwMutex<T> {
122 /// Acquires a read mutex and sleep until it can be acquired.
123 ///
124 /// The calling thread will sleep until there are no writers or upgrading
125 /// upreaders present. The implementation of [`WaitQueue`] guarantees the
126 /// order in which other concurrent readers or writers waiting simultaneously
127 /// will acquire the mutex.
128 #[track_caller]
129 pub fn read(&self) -> RwMutexReadGuard<'_, T> {
130 self.queue.wait_until(|| self.try_read())
131 }
132
133 /// Acquires a write mutex and sleep until it can be acquired.
134 ///
135 /// The calling thread will sleep until there are no writers, upreaders,
136 /// or readers present. The implementation of [`WaitQueue`] guarantees the
137 /// order in which other concurrent readers or writers waiting simultaneously
138 /// will acquire the mutex.
139 #[track_caller]
140 pub fn write(&self) -> RwMutexWriteGuard<'_, T> {
141 self.queue.wait_until(|| self.try_write())
142 }
143
144 /// Acquires a upread mutex and sleep until it can be acquired.
145 ///
146 /// The calling thread will sleep until there are no writers or upreaders present.
147 /// The implementation of [`WaitQueue`] guarantees the order in which other concurrent
148 /// readers or writers waiting simultaneously will acquire the mutex.
149 ///
150 /// Upreader will not block new readers until it tries to upgrade. Upreader
151 /// and reader do not differ before invoking the upgrade method. However,
152 /// only one upreader can exist at any time to avoid deadlock in the
153 /// upgrade method.
154 #[track_caller]
155 pub fn upread(&self) -> RwMutexUpgradeableGuard<'_, T> {
156 self.queue.wait_until(|| self.try_upread())
157 }
158
159 /// Attempts to acquire a read mutex.
160 ///
161 /// This function will never sleep and will return immediately.
162 pub fn try_read(&self) -> Option<RwMutexReadGuard<'_, T>> {
163 let lock = self.lock.fetch_add(READER, Acquire);
164 if lock & (WRITER | BEING_UPGRADED | MAX_READER) == 0 {
165 Some(RwMutexReadGuard { inner: self })
166 } else {
167 self.lock.fetch_sub(READER, Release);
168 None
169 }
170 }
171
172 /// Attempts to acquire a write mutex.
173 ///
174 /// This function will never sleep and will return immediately.
175 pub fn try_write(&self) -> Option<RwMutexWriteGuard<'_, T>> {
176 if self
177 .lock
178 .compare_exchange(0, WRITER, Acquire, Relaxed)
179 .is_ok()
180 {
181 Some(RwMutexWriteGuard { inner: self })
182 } else {
183 None
184 }
185 }
186
187 /// Attempts to acquire a upread mutex.
188 ///
189 /// This function will never sleep and will return immediately.
190 pub fn try_upread(&self) -> Option<RwMutexUpgradeableGuard<'_, T>> {
191 let lock = self.lock.fetch_or(UPGRADEABLE_READER, Acquire) & (WRITER | UPGRADEABLE_READER);
192 if lock == 0 {
193 return Some(RwMutexUpgradeableGuard { inner: self });
194 } else if lock == WRITER {
195 self.lock.fetch_sub(UPGRADEABLE_READER, Release);
196 }
197 None
198 }
199
200 /// Returns a mutable reference to the underlying data.
201 ///
202 /// This method is zero-cost: By holding a mutable reference to the lock, the compiler has
203 /// already statically guaranteed that access to the data is exclusive.
204 pub fn get_mut(&mut self) -> &mut T {
205 self.val.get_mut()
206 }
207}
208
209impl<T: ?Sized + fmt::Debug> fmt::Debug for RwMutex<T> {
210 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
211 fmt::Debug::fmt(&self.val, f)
212 }
213}
214
215// There can be more than one readers to get the `T`'s immutable reference,
216// so `T` must be `Sync` to guarantee the sharing safety.
217unsafe impl<T: ?Sized + Send> Send for RwMutex<T> {}
218unsafe impl<T: ?Sized + Send + Sync> Sync for RwMutex<T> {}
219
220impl<T: ?Sized> !Send for RwMutexWriteGuard<'_, T> {}
221unsafe impl<T: ?Sized + Sync> Sync for RwMutexWriteGuard<'_, T> {}
222
223impl<T: ?Sized> !Send for RwMutexReadGuard<'_, T> {}
224unsafe impl<T: ?Sized + Sync> Sync for RwMutexReadGuard<'_, T> {}
225
226impl<T: ?Sized> !Send for RwMutexUpgradeableGuard<'_, T> {}
227unsafe impl<T: ?Sized + Sync> Sync for RwMutexUpgradeableGuard<'_, T> {}
228
229/// A guard that provides immutable data access.
230pub struct RwMutexReadGuard<'a, T: ?Sized> {
231 inner: &'a RwMutex<T>,
232}
233
234impl<T: ?Sized> Deref for RwMutexReadGuard<'_, T> {
235 type Target = T;
236
237 fn deref(&self) -> &T {
238 // SAFETY: The mutex is locked by a reader, which provides shared access to the data.
239 unsafe { &*self.inner.val.get() }
240 }
241}
242
243impl<T: ?Sized> Drop for RwMutexReadGuard<'_, T> {
244 fn drop(&mut self) {
245 // When there are no readers, wake up a waiting writer.
246 if self.inner.lock.fetch_sub(READER, Release) == READER {
247 self.inner.queue.wake_one();
248 }
249 }
250}
251
252impl<T: ?Sized + fmt::Debug> fmt::Debug for RwMutexReadGuard<'_, T> {
253 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
254 fmt::Debug::fmt(&**self, f)
255 }
256}
257
258/// A guard that provides mutable data access.
259#[clippy::has_significant_drop]
260#[must_use]
261pub struct RwMutexWriteGuard<'a, T: ?Sized> {
262 inner: &'a RwMutex<T>,
263}
264
265impl<'a, T: ?Sized> RwMutexWriteGuard<'a, T> {
266 /// Atomically downgrades a write guard to an upgradeable reader guard.
267 ///
268 /// This method always succeeds because the lock is exclusively held by the writer.
269 pub fn downgrade(mut self) -> RwMutexUpgradeableGuard<'a, T> {
270 loop {
271 self = match self.try_downgrade() {
272 Ok(guard) => return guard,
273 Err(e) => e,
274 };
275 }
276 }
277
278 /// This is not exposed as a public method to prevent intermediate lock states from affecting the
279 /// downgrade process.
280 fn try_downgrade(self) -> Result<RwMutexUpgradeableGuard<'a, T>, Self> {
281 let inner = self.inner;
282 let res = self
283 .inner
284 .lock
285 .compare_exchange(WRITER, UPGRADEABLE_READER, AcqRel, Relaxed);
286 if res.is_ok() {
287 drop(self);
288 Ok(RwMutexUpgradeableGuard { inner })
289 } else {
290 Err(self)
291 }
292 }
293}
294
295impl<T: ?Sized> Deref for RwMutexWriteGuard<'_, T> {
296 type Target = T;
297
298 fn deref(&self) -> &T {
299 // SAFETY: The mutex is locked by a writer, which provides exclusive access to the data.
300 unsafe { &*self.inner.val.get() }
301 }
302}
303
304impl<T: ?Sized> DerefMut for RwMutexWriteGuard<'_, T> {
305 fn deref_mut(&mut self) -> &mut Self::Target {
306 // SAFETY: The mutex is locked by a writer, which provides exclusive access to the data.
307 unsafe { &mut *self.inner.val.get() }
308 }
309}
310
311impl<T: ?Sized> Drop for RwMutexWriteGuard<'_, T> {
312 fn drop(&mut self) {
313 self.inner.lock.fetch_and(!WRITER, Release);
314
315 // When the current writer releases, wake up all the sleeping threads.
316 // All awakened threads may include readers and writers.
317 // Thanks to the `wait_until` method, either all readers
318 // continue to execute or one writer continues to execute.
319 self.inner.queue.wake_all();
320 }
321}
322
323impl<T: ?Sized + fmt::Debug> fmt::Debug for RwMutexWriteGuard<'_, T> {
324 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
325 fmt::Debug::fmt(&**self, f)
326 }
327}
328
329/// A guard that provides immutable data access but can be atomically
330/// upgraded to [`RwMutexWriteGuard`].
331pub struct RwMutexUpgradeableGuard<'a, T: ?Sized> {
332 inner: &'a RwMutex<T>,
333}
334
335impl<'a, T: ?Sized> RwMutexUpgradeableGuard<'a, T> {
336 /// Upgrades this upread guard to a write guard atomically.
337 ///
338 /// After calling this method, subsequent readers will be blocked
339 /// while previous readers remain unaffected.
340 ///
341 /// The calling thread will not sleep, but spin to wait for the existing
342 /// reader to be released. There are two main reasons.
343 /// - First, it needs to sleep in an extra waiting queue and needs extra
344 /// wake-up logic and overhead.
345 /// - Second, upgrading method usually requires a high response time
346 /// (because the mutex is being used now).
347 pub fn upgrade(mut self) -> RwMutexWriteGuard<'a, T> {
348 self.inner.lock.fetch_or(BEING_UPGRADED, Acquire);
349 loop {
350 self = match self.try_upgrade() {
351 Ok(guard) => return guard,
352 Err(e) => e,
353 };
354 }
355 }
356
357 /// Attempts to upgrade this upread guard to a write guard atomically.
358 ///
359 /// This function will return immediately.
360 ///
361 /// This function is not exposed publicly because the `BEING_UPGRADED` bit
362 /// is set only in [`Self::upgrade`].
363 fn try_upgrade(self) -> Result<RwMutexWriteGuard<'a, T>, Self> {
364 let res = self.inner.lock.compare_exchange(
365 UPGRADEABLE_READER | BEING_UPGRADED,
366 WRITER | UPGRADEABLE_READER,
367 AcqRel,
368 Relaxed,
369 );
370 if res.is_ok() {
371 let inner = self.inner;
372 drop(self);
373 Ok(RwMutexWriteGuard { inner })
374 } else {
375 Err(self)
376 }
377 }
378}
379
380impl<T: ?Sized> Deref for RwMutexUpgradeableGuard<'_, T> {
381 type Target = T;
382
383 fn deref(&self) -> &T {
384 // SAFETY: The mutex is locked by a reader, which provides shared access to the data.
385 unsafe { &*self.inner.val.get() }
386 }
387}
388
389impl<T: ?Sized> Drop for RwMutexUpgradeableGuard<'_, T> {
390 fn drop(&mut self) {
391 let res = self.inner.lock.fetch_sub(UPGRADEABLE_READER, Release);
392 if res == UPGRADEABLE_READER {
393 self.inner.queue.wake_all();
394 }
395 }
396}
397
398impl<T: ?Sized + fmt::Debug> fmt::Debug for RwMutexUpgradeableGuard<'_, T> {
399 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
400 fmt::Debug::fmt(&**self, f)
401 }
402}