tokio/sync/
rwlock.rs

1use crate::sync::batch_semaphore::{Semaphore, TryAcquireError};
2use crate::sync::mutex::TryLockError;
3#[cfg(all(tokio_unstable, feature = "tracing"))]
4use crate::util::trace;
5use std::cell::UnsafeCell;
6use std::marker;
7use std::marker::PhantomData;
8use std::sync::Arc;
9
10pub(crate) mod owned_read_guard;
11pub(crate) mod owned_write_guard;
12pub(crate) mod owned_write_guard_mapped;
13pub(crate) mod read_guard;
14pub(crate) mod write_guard;
15pub(crate) mod write_guard_mapped;
16pub(crate) use owned_read_guard::OwnedRwLockReadGuard;
17pub(crate) use owned_write_guard::OwnedRwLockWriteGuard;
18pub(crate) use owned_write_guard_mapped::OwnedRwLockMappedWriteGuard;
19pub(crate) use read_guard::RwLockReadGuard;
20pub(crate) use write_guard::RwLockWriteGuard;
21pub(crate) use write_guard_mapped::RwLockMappedWriteGuard;
22
23#[cfg(not(loom))]
24const MAX_READS: u32 = u32::MAX >> 3;
25
26#[cfg(loom)]
27const MAX_READS: u32 = 10;
28
29/// An asynchronous reader-writer lock.
30///
31/// This type of lock allows a number of readers or at most one writer at any
32/// point in time. The write portion of this lock typically allows modification
33/// of the underlying data (exclusive access) and the read portion of this lock
34/// typically allows for read-only access (shared access).
35///
36/// In comparison, a [`Mutex`] does not distinguish between readers or writers
37/// that acquire the lock, therefore causing any tasks waiting for the lock to
38/// become available to yield. An `RwLock` will allow any number of readers to
39/// acquire the lock as long as a writer is not holding the lock.
40///
41/// The priority policy of Tokio's read-write lock is _fair_ (or
42/// [_write-preferring_]), in order to ensure that readers cannot starve
43/// writers. Fairness is ensured using a first-in, first-out queue for the tasks
44/// awaiting the lock; if a task that wishes to acquire the write lock is at the
45/// head of the queue, read locks will not be given out until the write lock has
46/// been released. This is in contrast to the Rust standard library's
47/// `std::sync::RwLock`, where the priority policy is dependent on the
48/// operating system's implementation.
49///
50/// The type parameter `T` represents the data that this lock protects. It is
51/// required that `T` satisfies [`Send`] to be shared across threads. The RAII guards
52/// returned from the locking methods implement [`Deref`](trait@std::ops::Deref)
53/// (and [`DerefMut`](trait@std::ops::DerefMut)
54/// for the `write` methods) to allow access to the content of the lock.
55///
56/// # Examples
57///
58/// ```
59/// use tokio::sync::RwLock;
60///
61/// #[tokio::main]
62/// async fn main() {
63///     let lock = RwLock::new(5);
64///
65///     // many reader locks can be held at once
66///     {
67///         let r1 = lock.read().await;
68///         let r2 = lock.read().await;
69///         assert_eq!(*r1, 5);
70///         assert_eq!(*r2, 5);
71///     } // read locks are dropped at this point
72///
73///     // only one write lock may be held, however
74///     {
75///         let mut w = lock.write().await;
76///         *w += 1;
77///         assert_eq!(*w, 6);
78///     } // write lock is dropped here
79/// }
80/// ```
81///
82/// [`Mutex`]: struct@super::Mutex
83/// [`RwLock`]: struct@RwLock
84/// [`RwLockReadGuard`]: struct@RwLockReadGuard
85/// [`RwLockWriteGuard`]: struct@RwLockWriteGuard
86/// [`Send`]: trait@std::marker::Send
87/// [_write-preferring_]: https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock#Priority_policies
88pub struct RwLock<T: ?Sized> {
89    #[cfg(all(tokio_unstable, feature = "tracing"))]
90    resource_span: tracing::Span,
91
92    // maximum number of concurrent readers
93    mr: u32,
94
95    //semaphore to coordinate read and write access to T
96    s: Semaphore,
97
98    //inner data T
99    c: UnsafeCell<T>,
100}
101
102#[test]
103#[cfg(not(loom))]
104fn bounds() {
105    fn check_send<T: Send>() {}
106    fn check_sync<T: Sync>() {}
107    fn check_unpin<T: Unpin>() {}
108    // This has to take a value, since the async fn's return type is unnameable.
109    fn check_send_sync_val<T: Send + Sync>(_t: T) {}
110
111    check_send::<RwLock<u32>>();
112    check_sync::<RwLock<u32>>();
113    check_unpin::<RwLock<u32>>();
114
115    check_send::<RwLockReadGuard<'_, u32>>();
116    check_sync::<RwLockReadGuard<'_, u32>>();
117    check_unpin::<RwLockReadGuard<'_, u32>>();
118
119    check_send::<OwnedRwLockReadGuard<u32, i32>>();
120    check_sync::<OwnedRwLockReadGuard<u32, i32>>();
121    check_unpin::<OwnedRwLockReadGuard<u32, i32>>();
122
123    check_send::<RwLockWriteGuard<'_, u32>>();
124    check_sync::<RwLockWriteGuard<'_, u32>>();
125    check_unpin::<RwLockWriteGuard<'_, u32>>();
126
127    check_send::<RwLockMappedWriteGuard<'_, u32>>();
128    check_sync::<RwLockMappedWriteGuard<'_, u32>>();
129    check_unpin::<RwLockMappedWriteGuard<'_, u32>>();
130
131    check_send::<OwnedRwLockWriteGuard<u32>>();
132    check_sync::<OwnedRwLockWriteGuard<u32>>();
133    check_unpin::<OwnedRwLockWriteGuard<u32>>();
134
135    check_send::<OwnedRwLockMappedWriteGuard<u32, i32>>();
136    check_sync::<OwnedRwLockMappedWriteGuard<u32, i32>>();
137    check_unpin::<OwnedRwLockMappedWriteGuard<u32, i32>>();
138
139    let rwlock = Arc::new(RwLock::new(0));
140    check_send_sync_val(rwlock.read());
141    check_send_sync_val(Arc::clone(&rwlock).read_owned());
142    check_send_sync_val(rwlock.write());
143    check_send_sync_val(Arc::clone(&rwlock).write_owned());
144}
145
146// As long as T: Send + Sync, it's fine to send and share RwLock<T> between threads.
147// If T were not Send, sending and sharing a RwLock<T> would be bad, since you can access T through
148// RwLock<T>.
149unsafe impl<T> Send for RwLock<T> where T: ?Sized + Send {}
150unsafe impl<T> Sync for RwLock<T> where T: ?Sized + Send + Sync {}
151// NB: These impls need to be explicit since we're storing a raw pointer.
152// Safety: Stores a raw pointer to `T`, so if `T` is `Sync`, the lock guard over
153// `T` is `Send`.
154unsafe impl<T> Send for RwLockReadGuard<'_, T> where T: ?Sized + Sync {}
155unsafe impl<T> Sync for RwLockReadGuard<'_, T> where T: ?Sized + Send + Sync {}
156// T is required to be `Send` because an OwnedRwLockReadGuard can be used to drop the value held in
157// the RwLock, unlike RwLockReadGuard.
158unsafe impl<T, U> Send for OwnedRwLockReadGuard<T, U>
159where
160    T: ?Sized + Send + Sync,
161    U: ?Sized + Sync,
162{
163}
164unsafe impl<T, U> Sync for OwnedRwLockReadGuard<T, U>
165where
166    T: ?Sized + Send + Sync,
167    U: ?Sized + Send + Sync,
168{
169}
170unsafe impl<T> Sync for RwLockWriteGuard<'_, T> where T: ?Sized + Send + Sync {}
171unsafe impl<T> Sync for OwnedRwLockWriteGuard<T> where T: ?Sized + Send + Sync {}
172unsafe impl<T> Sync for RwLockMappedWriteGuard<'_, T> where T: ?Sized + Send + Sync {}
173unsafe impl<T, U> Sync for OwnedRwLockMappedWriteGuard<T, U>
174where
175    T: ?Sized + Send + Sync,
176    U: ?Sized + Send + Sync,
177{
178}
179// Safety: Stores a raw pointer to `T`, so if `T` is `Sync`, the lock guard over
180// `T` is `Send` - but since this is also provides mutable access, we need to
181// make sure that `T` is `Send` since its value can be sent across thread
182// boundaries.
183unsafe impl<T> Send for RwLockWriteGuard<'_, T> where T: ?Sized + Send + Sync {}
184unsafe impl<T> Send for OwnedRwLockWriteGuard<T> where T: ?Sized + Send + Sync {}
185unsafe impl<T> Send for RwLockMappedWriteGuard<'_, T> where T: ?Sized + Send + Sync {}
186unsafe impl<T, U> Send for OwnedRwLockMappedWriteGuard<T, U>
187where
188    T: ?Sized + Send + Sync,
189    U: ?Sized + Send + Sync,
190{
191}
192
193impl<T: ?Sized> RwLock<T> {
194    /// Creates a new instance of an `RwLock<T>` which is unlocked.
195    ///
196    /// # Examples
197    ///
198    /// ```
199    /// use tokio::sync::RwLock;
200    ///
201    /// let lock = RwLock::new(5);
202    /// ```
203    #[track_caller]
204    pub fn new(value: T) -> RwLock<T>
205    where
206        T: Sized,
207    {
208        #[cfg(all(tokio_unstable, feature = "tracing"))]
209        let resource_span = {
210            let location = std::panic::Location::caller();
211            let resource_span = tracing::trace_span!(
212                parent: None,
213                "runtime.resource",
214                concrete_type = "RwLock",
215                kind = "Sync",
216                loc.file = location.file(),
217                loc.line = location.line(),
218                loc.col = location.column(),
219            );
220
221            resource_span.in_scope(|| {
222                tracing::trace!(
223                    target: "runtime::resource::state_update",
224                    max_readers = MAX_READS,
225                );
226
227                tracing::trace!(
228                    target: "runtime::resource::state_update",
229                    write_locked = false,
230                );
231
232                tracing::trace!(
233                    target: "runtime::resource::state_update",
234                    current_readers = 0,
235                );
236            });
237
238            resource_span
239        };
240
241        #[cfg(all(tokio_unstable, feature = "tracing"))]
242        let s = resource_span.in_scope(|| Semaphore::new(MAX_READS as usize));
243
244        #[cfg(any(not(tokio_unstable), not(feature = "tracing")))]
245        let s = Semaphore::new(MAX_READS as usize);
246
247        RwLock {
248            mr: MAX_READS,
249            c: UnsafeCell::new(value),
250            s,
251            #[cfg(all(tokio_unstable, feature = "tracing"))]
252            resource_span,
253        }
254    }
255
256    /// Creates a new instance of an `RwLock<T>` which is unlocked
257    /// and allows a maximum of `max_reads` concurrent readers.
258    ///
259    /// # Examples
260    ///
261    /// ```
262    /// use tokio::sync::RwLock;
263    ///
264    /// let lock = RwLock::with_max_readers(5, 1024);
265    /// ```
266    ///
267    /// # Panics
268    ///
269    /// Panics if `max_reads` is more than `u32::MAX >> 3`.
270    #[track_caller]
271    pub fn with_max_readers(value: T, max_reads: u32) -> RwLock<T>
272    where
273        T: Sized,
274    {
275        assert!(
276            max_reads <= MAX_READS,
277            "a RwLock may not be created with more than {} readers",
278            MAX_READS
279        );
280
281        #[cfg(all(tokio_unstable, feature = "tracing"))]
282        let resource_span = {
283            let location = std::panic::Location::caller();
284
285            let resource_span = tracing::trace_span!(
286                parent: None,
287                "runtime.resource",
288                concrete_type = "RwLock",
289                kind = "Sync",
290                loc.file = location.file(),
291                loc.line = location.line(),
292                loc.col = location.column(),
293            );
294
295            resource_span.in_scope(|| {
296                tracing::trace!(
297                    target: "runtime::resource::state_update",
298                    max_readers = max_reads,
299                );
300
301                tracing::trace!(
302                    target: "runtime::resource::state_update",
303                    write_locked = false,
304                );
305
306                tracing::trace!(
307                    target: "runtime::resource::state_update",
308                    current_readers = 0,
309                );
310            });
311
312            resource_span
313        };
314
315        #[cfg(all(tokio_unstable, feature = "tracing"))]
316        let s = resource_span.in_scope(|| Semaphore::new(max_reads as usize));
317
318        #[cfg(any(not(tokio_unstable), not(feature = "tracing")))]
319        let s = Semaphore::new(max_reads as usize);
320
321        RwLock {
322            mr: max_reads,
323            c: UnsafeCell::new(value),
324            s,
325            #[cfg(all(tokio_unstable, feature = "tracing"))]
326            resource_span,
327        }
328    }
329
330    /// Creates a new instance of an `RwLock<T>` which is unlocked.
331    ///
332    /// When using the `tracing` [unstable feature], a `RwLock` created with
333    /// `const_new` will not be instrumented. As such, it will not be visible
334    /// in [`tokio-console`]. Instead, [`RwLock::new`] should be used to create
335    /// an instrumented object if that is needed.
336    ///
337    /// # Examples
338    ///
339    /// ```
340    /// use tokio::sync::RwLock;
341    ///
342    /// static LOCK: RwLock<i32> = RwLock::const_new(5);
343    /// ```
344    ///
345    /// [`tokio-console`]: https://github.com/tokio-rs/console
346    /// [unstable feature]: crate#unstable-features
347    #[cfg(not(all(loom, test)))]
348    pub const fn const_new(value: T) -> RwLock<T>
349    where
350        T: Sized,
351    {
352        RwLock {
353            mr: MAX_READS,
354            c: UnsafeCell::new(value),
355            s: Semaphore::const_new(MAX_READS as usize),
356            #[cfg(all(tokio_unstable, feature = "tracing"))]
357            resource_span: tracing::Span::none(),
358        }
359    }
360
361    /// Creates a new instance of an `RwLock<T>` which is unlocked
362    /// and allows a maximum of `max_reads` concurrent readers.
363    ///
364    /// # Examples
365    ///
366    /// ```
367    /// use tokio::sync::RwLock;
368    ///
369    /// static LOCK: RwLock<i32> = RwLock::const_with_max_readers(5, 1024);
370    /// ```
371    #[cfg(not(all(loom, test)))]
372    pub const fn const_with_max_readers(value: T, max_reads: u32) -> RwLock<T>
373    where
374        T: Sized,
375    {
376        assert!(max_reads <= MAX_READS);
377
378        RwLock {
379            mr: max_reads,
380            c: UnsafeCell::new(value),
381            s: Semaphore::const_new(max_reads as usize),
382            #[cfg(all(tokio_unstable, feature = "tracing"))]
383            resource_span: tracing::Span::none(),
384        }
385    }
386
387    /// Locks this `RwLock` with shared read access, causing the current task
388    /// to yield until the lock has been acquired.
389    ///
390    /// The calling task will yield until there are no writers which hold the
391    /// lock. There may be other readers inside the lock when the task resumes.
392    ///
393    /// Note that under the priority policy of [`RwLock`], read locks are not
394    /// granted until prior write locks, to prevent starvation. Therefore
395    /// deadlock may occur if a read lock is held by the current task, a write
396    /// lock attempt is made, and then a subsequent read lock attempt is made
397    /// by the current task.
398    ///
399    /// Returns an RAII guard which will drop this read access of the `RwLock`
400    /// when dropped.
401    ///
402    /// # Cancel safety
403    ///
404    /// This method uses a queue to fairly distribute locks in the order they
405    /// were requested. Cancelling a call to `read` makes you lose your place in
406    /// the queue.
407    ///
408    /// # Examples
409    ///
410    /// ```
411    /// use std::sync::Arc;
412    /// use tokio::sync::RwLock;
413    ///
414    /// #[tokio::main]
415    /// async fn main() {
416    ///     let lock = Arc::new(RwLock::new(1));
417    ///     let c_lock = lock.clone();
418    ///
419    ///     let n = lock.read().await;
420    ///     assert_eq!(*n, 1);
421    ///
422    ///     tokio::spawn(async move {
423    ///         // While main has an active read lock, we acquire one too.
424    ///         let r = c_lock.read().await;
425    ///         assert_eq!(*r, 1);
426    ///     }).await.expect("The spawned task has panicked");
427    ///
428    ///     // Drop the guard after the spawned task finishes.
429    ///     drop(n);
430    /// }
431    /// ```
432    pub async fn read(&self) -> RwLockReadGuard<'_, T> {
433        let acquire_fut = async {
434            self.s.acquire(1).await.unwrap_or_else(|_| {
435                // The semaphore was closed. but, we never explicitly close it, and we have a
436                // handle to it through the Arc, which means that this can never happen.
437                unreachable!()
438            });
439
440            RwLockReadGuard {
441                s: &self.s,
442                data: self.c.get(),
443                marker: PhantomData,
444                #[cfg(all(tokio_unstable, feature = "tracing"))]
445                resource_span: self.resource_span.clone(),
446            }
447        };
448
449        #[cfg(all(tokio_unstable, feature = "tracing"))]
450        let acquire_fut = trace::async_op(
451            move || acquire_fut,
452            self.resource_span.clone(),
453            "RwLock::read",
454            "poll",
455            false,
456        );
457
458        #[allow(clippy::let_and_return)] // this lint triggers when disabling tracing
459        let guard = acquire_fut.await;
460
461        #[cfg(all(tokio_unstable, feature = "tracing"))]
462        self.resource_span.in_scope(|| {
463            tracing::trace!(
464            target: "runtime::resource::state_update",
465            current_readers = 1,
466            current_readers.op = "add",
467            )
468        });
469
470        guard
471    }
472
473    /// Blockingly locks this `RwLock` with shared read access.
474    ///
475    /// This method is intended for use cases where you
476    /// need to use this rwlock in asynchronous code as well as in synchronous code.
477    ///
478    /// Returns an RAII guard which will drop the read access of this `RwLock` when dropped.
479    ///
480    /// # Panics
481    ///
482    /// This function panics if called within an asynchronous execution context.
483    ///
484    ///   - If you find yourself in an asynchronous execution context and needing
485    ///     to call some (synchronous) function which performs one of these
486    ///     `blocking_` operations, then consider wrapping that call inside
487    ///     [`spawn_blocking()`][crate::runtime::Handle::spawn_blocking]
488    ///     (or [`block_in_place()`][crate::task::block_in_place]).
489    ///
490    /// # Examples
491    ///
492    /// ```
493    /// use std::sync::Arc;
494    /// use tokio::sync::RwLock;
495    ///
496    /// #[tokio::main]
497    /// async fn main() {
498    ///     let rwlock = Arc::new(RwLock::new(1));
499    ///     let mut write_lock = rwlock.write().await;
500    ///
501    ///     let blocking_task = tokio::task::spawn_blocking({
502    ///         let rwlock = Arc::clone(&rwlock);
503    ///         move || {
504    ///             // This shall block until the `write_lock` is released.
505    ///             let read_lock = rwlock.blocking_read();
506    ///             assert_eq!(*read_lock, 0);
507    ///         }
508    ///     });
509    ///
510    ///     *write_lock -= 1;
511    ///     drop(write_lock); // release the lock.
512    ///
513    ///     // Await the completion of the blocking task.
514    ///     blocking_task.await.unwrap();
515    ///
516    ///     // Assert uncontended.
517    ///     assert!(rwlock.try_write().is_ok());
518    /// }
519    /// ```
520    #[track_caller]
521    #[cfg(feature = "sync")]
522    pub fn blocking_read(&self) -> RwLockReadGuard<'_, T> {
523        crate::future::block_on(self.read())
524    }
525
526    /// Locks this `RwLock` with shared read access, causing the current task
527    /// to yield until the lock has been acquired.
528    ///
529    /// The calling task will yield until there are no writers which hold the
530    /// lock. There may be other readers inside the lock when the task resumes.
531    ///
532    /// This method is identical to [`RwLock::read`], except that the returned
533    /// guard references the `RwLock` with an [`Arc`] rather than by borrowing
534    /// it. Therefore, the `RwLock` must be wrapped in an `Arc` to call this
535    /// method, and the guard will live for the `'static` lifetime, as it keeps
536    /// the `RwLock` alive by holding an `Arc`.
537    ///
538    /// Note that under the priority policy of [`RwLock`], read locks are not
539    /// granted until prior write locks, to prevent starvation. Therefore
540    /// deadlock may occur if a read lock is held by the current task, a write
541    /// lock attempt is made, and then a subsequent read lock attempt is made
542    /// by the current task.
543    ///
544    /// Returns an RAII guard which will drop this read access of the `RwLock`
545    /// when dropped.
546    ///
547    /// # Cancel safety
548    ///
549    /// This method uses a queue to fairly distribute locks in the order they
550    /// were requested. Cancelling a call to `read_owned` makes you lose your
551    /// place in the queue.
552    ///
553    /// # Examples
554    ///
555    /// ```
556    /// use std::sync::Arc;
557    /// use tokio::sync::RwLock;
558    ///
559    /// #[tokio::main]
560    /// async fn main() {
561    ///     let lock = Arc::new(RwLock::new(1));
562    ///     let c_lock = lock.clone();
563    ///
564    ///     let n = lock.read_owned().await;
565    ///     assert_eq!(*n, 1);
566    ///
567    ///     tokio::spawn(async move {
568    ///         // While main has an active read lock, we acquire one too.
569    ///         let r = c_lock.read_owned().await;
570    ///         assert_eq!(*r, 1);
571    ///     }).await.expect("The spawned task has panicked");
572    ///
573    ///     // Drop the guard after the spawned task finishes.
574    ///     drop(n);
575    ///}
576    /// ```
577    pub async fn read_owned(self: Arc<Self>) -> OwnedRwLockReadGuard<T> {
578        #[cfg(all(tokio_unstable, feature = "tracing"))]
579        let resource_span = self.resource_span.clone();
580
581        let acquire_fut = async {
582            self.s.acquire(1).await.unwrap_or_else(|_| {
583                // The semaphore was closed. but, we never explicitly close it, and we have a
584                // handle to it through the Arc, which means that this can never happen.
585                unreachable!()
586            });
587
588            OwnedRwLockReadGuard {
589                #[cfg(all(tokio_unstable, feature = "tracing"))]
590                resource_span: self.resource_span.clone(),
591                data: self.c.get(),
592                lock: self,
593                _p: PhantomData,
594            }
595        };
596
597        #[cfg(all(tokio_unstable, feature = "tracing"))]
598        let acquire_fut = trace::async_op(
599            move || acquire_fut,
600            resource_span,
601            "RwLock::read_owned",
602            "poll",
603            false,
604        );
605
606        #[allow(clippy::let_and_return)] // this lint triggers when disabling tracing
607        let guard = acquire_fut.await;
608
609        #[cfg(all(tokio_unstable, feature = "tracing"))]
610        guard.resource_span.in_scope(|| {
611            tracing::trace!(
612            target: "runtime::resource::state_update",
613            current_readers = 1,
614            current_readers.op = "add",
615            )
616        });
617
618        guard
619    }
620
621    /// Attempts to acquire this `RwLock` with shared read access.
622    ///
623    /// If the access couldn't be acquired immediately, returns [`TryLockError`].
624    /// Otherwise, an RAII guard is returned which will release read access
625    /// when dropped.
626    ///
627    /// [`TryLockError`]: TryLockError
628    ///
629    /// # Examples
630    ///
631    /// ```
632    /// use std::sync::Arc;
633    /// use tokio::sync::RwLock;
634    ///
635    /// #[tokio::main]
636    /// async fn main() {
637    ///     let lock = Arc::new(RwLock::new(1));
638    ///     let c_lock = lock.clone();
639    ///
640    ///     let v = lock.try_read().unwrap();
641    ///     assert_eq!(*v, 1);
642    ///
643    ///     tokio::spawn(async move {
644    ///         // While main has an active read lock, we acquire one too.
645    ///         let n = c_lock.read().await;
646    ///         assert_eq!(*n, 1);
647    ///     }).await.expect("The spawned task has panicked");
648    ///
649    ///     // Drop the guard when spawned task finishes.
650    ///     drop(v);
651    /// }
652    /// ```
653    pub fn try_read(&self) -> Result<RwLockReadGuard<'_, T>, TryLockError> {
654        match self.s.try_acquire(1) {
655            Ok(permit) => permit,
656            Err(TryAcquireError::NoPermits) => return Err(TryLockError(())),
657            Err(TryAcquireError::Closed) => unreachable!(),
658        }
659
660        let guard = RwLockReadGuard {
661            s: &self.s,
662            data: self.c.get(),
663            marker: marker::PhantomData,
664            #[cfg(all(tokio_unstable, feature = "tracing"))]
665            resource_span: self.resource_span.clone(),
666        };
667
668        #[cfg(all(tokio_unstable, feature = "tracing"))]
669        self.resource_span.in_scope(|| {
670            tracing::trace!(
671            target: "runtime::resource::state_update",
672            current_readers = 1,
673            current_readers.op = "add",
674            )
675        });
676
677        Ok(guard)
678    }
679
680    /// Attempts to acquire this `RwLock` with shared read access.
681    ///
682    /// If the access couldn't be acquired immediately, returns [`TryLockError`].
683    /// Otherwise, an RAII guard is returned which will release read access
684    /// when dropped.
685    ///
686    /// This method is identical to [`RwLock::try_read`], except that the
687    /// returned guard references the `RwLock` with an [`Arc`] rather than by
688    /// borrowing it. Therefore, the `RwLock` must be wrapped in an `Arc` to
689    /// call this method, and the guard will live for the `'static` lifetime,
690    /// as it keeps the `RwLock` alive by holding an `Arc`.
691    ///
692    /// [`TryLockError`]: TryLockError
693    ///
694    /// # Examples
695    ///
696    /// ```
697    /// use std::sync::Arc;
698    /// use tokio::sync::RwLock;
699    ///
700    /// #[tokio::main]
701    /// async fn main() {
702    ///     let lock = Arc::new(RwLock::new(1));
703    ///     let c_lock = lock.clone();
704    ///
705    ///     let v = lock.try_read_owned().unwrap();
706    ///     assert_eq!(*v, 1);
707    ///
708    ///     tokio::spawn(async move {
709    ///         // While main has an active read lock, we acquire one too.
710    ///         let n = c_lock.read_owned().await;
711    ///         assert_eq!(*n, 1);
712    ///     }).await.expect("The spawned task has panicked");
713    ///
714    ///     // Drop the guard when spawned task finishes.
715    ///     drop(v);
716    /// }
717    /// ```
718    pub fn try_read_owned(self: Arc<Self>) -> Result<OwnedRwLockReadGuard<T>, TryLockError> {
719        match self.s.try_acquire(1) {
720            Ok(permit) => permit,
721            Err(TryAcquireError::NoPermits) => return Err(TryLockError(())),
722            Err(TryAcquireError::Closed) => unreachable!(),
723        }
724
725        let guard = OwnedRwLockReadGuard {
726            #[cfg(all(tokio_unstable, feature = "tracing"))]
727            resource_span: self.resource_span.clone(),
728            data: self.c.get(),
729            lock: self,
730            _p: PhantomData,
731        };
732
733        #[cfg(all(tokio_unstable, feature = "tracing"))]
734        guard.resource_span.in_scope(|| {
735            tracing::trace!(
736            target: "runtime::resource::state_update",
737            current_readers = 1,
738            current_readers.op = "add",
739            )
740        });
741
742        Ok(guard)
743    }
744
745    /// Locks this `RwLock` with exclusive write access, causing the current
746    /// task to yield until the lock has been acquired.
747    ///
748    /// The calling task will yield while other writers or readers currently
749    /// have access to the lock.
750    ///
751    /// Returns an RAII guard which will drop the write access of this `RwLock`
752    /// when dropped.
753    ///
754    /// # Cancel safety
755    ///
756    /// This method uses a queue to fairly distribute locks in the order they
757    /// were requested. Cancelling a call to `write` makes you lose your place
758    /// in the queue.
759    ///
760    /// # Examples
761    ///
762    /// ```
763    /// use tokio::sync::RwLock;
764    ///
765    /// #[tokio::main]
766    /// async fn main() {
767    ///   let lock = RwLock::new(1);
768    ///
769    ///   let mut n = lock.write().await;
770    ///   *n = 2;
771    ///}
772    /// ```
773    pub async fn write(&self) -> RwLockWriteGuard<'_, T> {
774        let acquire_fut = async {
775            self.s.acquire(self.mr as usize).await.unwrap_or_else(|_| {
776                // The semaphore was closed. but, we never explicitly close it, and we have a
777                // handle to it through the Arc, which means that this can never happen.
778                unreachable!()
779            });
780
781            RwLockWriteGuard {
782                permits_acquired: self.mr,
783                s: &self.s,
784                data: self.c.get(),
785                marker: marker::PhantomData,
786                #[cfg(all(tokio_unstable, feature = "tracing"))]
787                resource_span: self.resource_span.clone(),
788            }
789        };
790
791        #[cfg(all(tokio_unstable, feature = "tracing"))]
792        let acquire_fut = trace::async_op(
793            move || acquire_fut,
794            self.resource_span.clone(),
795            "RwLock::write",
796            "poll",
797            false,
798        );
799
800        #[allow(clippy::let_and_return)] // this lint triggers when disabling tracing
801        let guard = acquire_fut.await;
802
803        #[cfg(all(tokio_unstable, feature = "tracing"))]
804        self.resource_span.in_scope(|| {
805            tracing::trace!(
806            target: "runtime::resource::state_update",
807            write_locked = true,
808            write_locked.op = "override",
809            )
810        });
811
812        guard
813    }
814
815    /// Blockingly locks this `RwLock` with exclusive write access.
816    ///
817    /// This method is intended for use cases where you
818    /// need to use this rwlock in asynchronous code as well as in synchronous code.
819    ///
820    /// Returns an RAII guard which will drop the write access of this `RwLock` when dropped.
821    ///
822    /// # Panics
823    ///
824    /// This function panics if called within an asynchronous execution context.
825    ///
826    ///   - If you find yourself in an asynchronous execution context and needing
827    ///     to call some (synchronous) function which performs one of these
828    ///     `blocking_` operations, then consider wrapping that call inside
829    ///     [`spawn_blocking()`][crate::runtime::Handle::spawn_blocking]
830    ///     (or [`block_in_place()`][crate::task::block_in_place]).
831    ///
832    /// # Examples
833    ///
834    /// ```
835    /// use std::sync::Arc;
836    /// use tokio::{sync::RwLock};
837    ///
838    /// #[tokio::main]
839    /// async fn main() {
840    ///     let rwlock =  Arc::new(RwLock::new(1));
841    ///     let read_lock = rwlock.read().await;
842    ///
843    ///     let blocking_task = tokio::task::spawn_blocking({
844    ///         let rwlock = Arc::clone(&rwlock);
845    ///         move || {
846    ///             // This shall block until the `read_lock` is released.
847    ///             let mut write_lock = rwlock.blocking_write();
848    ///             *write_lock = 2;
849    ///         }
850    ///     });
851    ///
852    ///     assert_eq!(*read_lock, 1);
853    ///     // Release the last outstanding read lock.
854    ///     drop(read_lock);
855    ///
856    ///     // Await the completion of the blocking task.
857    ///     blocking_task.await.unwrap();
858    ///
859    ///     // Assert uncontended.
860    ///     let read_lock = rwlock.try_read().unwrap();
861    ///     assert_eq!(*read_lock, 2);
862    /// }
863    /// ```
864    #[track_caller]
865    #[cfg(feature = "sync")]
866    pub fn blocking_write(&self) -> RwLockWriteGuard<'_, T> {
867        crate::future::block_on(self.write())
868    }
869
870    /// Locks this `RwLock` with exclusive write access, causing the current
871    /// task to yield until the lock has been acquired.
872    ///
873    /// The calling task will yield while other writers or readers currently
874    /// have access to the lock.
875    ///
876    /// This method is identical to [`RwLock::write`], except that the returned
877    /// guard references the `RwLock` with an [`Arc`] rather than by borrowing
878    /// it. Therefore, the `RwLock` must be wrapped in an `Arc` to call this
879    /// method, and the guard will live for the `'static` lifetime, as it keeps
880    /// the `RwLock` alive by holding an `Arc`.
881    ///
882    /// Returns an RAII guard which will drop the write access of this `RwLock`
883    /// when dropped.
884    ///
885    /// # Cancel safety
886    ///
887    /// This method uses a queue to fairly distribute locks in the order they
888    /// were requested. Cancelling a call to `write_owned` makes you lose your
889    /// place in the queue.
890    ///
891    /// # Examples
892    ///
893    /// ```
894    /// use std::sync::Arc;
895    /// use tokio::sync::RwLock;
896    ///
897    /// #[tokio::main]
898    /// async fn main() {
899    ///   let lock = Arc::new(RwLock::new(1));
900    ///
901    ///   let mut n = lock.write_owned().await;
902    ///   *n = 2;
903    ///}
904    /// ```
905    pub async fn write_owned(self: Arc<Self>) -> OwnedRwLockWriteGuard<T> {
906        #[cfg(all(tokio_unstable, feature = "tracing"))]
907        let resource_span = self.resource_span.clone();
908
909        let acquire_fut = async {
910            self.s.acquire(self.mr as usize).await.unwrap_or_else(|_| {
911                // The semaphore was closed. but, we never explicitly close it, and we have a
912                // handle to it through the Arc, which means that this can never happen.
913                unreachable!()
914            });
915
916            OwnedRwLockWriteGuard {
917                #[cfg(all(tokio_unstable, feature = "tracing"))]
918                resource_span: self.resource_span.clone(),
919                permits_acquired: self.mr,
920                data: self.c.get(),
921                lock: self,
922                _p: PhantomData,
923            }
924        };
925
926        #[cfg(all(tokio_unstable, feature = "tracing"))]
927        let acquire_fut = trace::async_op(
928            move || acquire_fut,
929            resource_span,
930            "RwLock::write_owned",
931            "poll",
932            false,
933        );
934
935        #[allow(clippy::let_and_return)] // this lint triggers when disabling tracing
936        let guard = acquire_fut.await;
937
938        #[cfg(all(tokio_unstable, feature = "tracing"))]
939        guard.resource_span.in_scope(|| {
940            tracing::trace!(
941            target: "runtime::resource::state_update",
942            write_locked = true,
943            write_locked.op = "override",
944            )
945        });
946
947        guard
948    }
949
950    /// Attempts to acquire this `RwLock` with exclusive write access.
951    ///
952    /// If the access couldn't be acquired immediately, returns [`TryLockError`].
953    /// Otherwise, an RAII guard is returned which will release write access
954    /// when dropped.
955    ///
956    /// [`TryLockError`]: TryLockError
957    ///
958    /// # Examples
959    ///
960    /// ```
961    /// use tokio::sync::RwLock;
962    ///
963    /// #[tokio::main]
964    /// async fn main() {
965    ///     let rw = RwLock::new(1);
966    ///
967    ///     let v = rw.read().await;
968    ///     assert_eq!(*v, 1);
969    ///
970    ///     assert!(rw.try_write().is_err());
971    /// }
972    /// ```
973    pub fn try_write(&self) -> Result<RwLockWriteGuard<'_, T>, TryLockError> {
974        match self.s.try_acquire(self.mr as usize) {
975            Ok(permit) => permit,
976            Err(TryAcquireError::NoPermits) => return Err(TryLockError(())),
977            Err(TryAcquireError::Closed) => unreachable!(),
978        }
979
980        let guard = RwLockWriteGuard {
981            permits_acquired: self.mr,
982            s: &self.s,
983            data: self.c.get(),
984            marker: marker::PhantomData,
985            #[cfg(all(tokio_unstable, feature = "tracing"))]
986            resource_span: self.resource_span.clone(),
987        };
988
989        #[cfg(all(tokio_unstable, feature = "tracing"))]
990        self.resource_span.in_scope(|| {
991            tracing::trace!(
992            target: "runtime::resource::state_update",
993            write_locked = true,
994            write_locked.op = "override",
995            )
996        });
997
998        Ok(guard)
999    }
1000
1001    /// Attempts to acquire this `RwLock` with exclusive write access.
1002    ///
1003    /// If the access couldn't be acquired immediately, returns [`TryLockError`].
1004    /// Otherwise, an RAII guard is returned which will release write access
1005    /// when dropped.
1006    ///
1007    /// This method is identical to [`RwLock::try_write`], except that the
1008    /// returned guard references the `RwLock` with an [`Arc`] rather than by
1009    /// borrowing it. Therefore, the `RwLock` must be wrapped in an `Arc` to
1010    /// call this method, and the guard will live for the `'static` lifetime,
1011    /// as it keeps the `RwLock` alive by holding an `Arc`.
1012    ///
1013    /// [`TryLockError`]: TryLockError
1014    ///
1015    /// # Examples
1016    ///
1017    /// ```
1018    /// use std::sync::Arc;
1019    /// use tokio::sync::RwLock;
1020    ///
1021    /// #[tokio::main]
1022    /// async fn main() {
1023    ///     let rw = Arc::new(RwLock::new(1));
1024    ///
1025    ///     let v = Arc::clone(&rw).read_owned().await;
1026    ///     assert_eq!(*v, 1);
1027    ///
1028    ///     assert!(rw.try_write_owned().is_err());
1029    /// }
1030    /// ```
1031    pub fn try_write_owned(self: Arc<Self>) -> Result<OwnedRwLockWriteGuard<T>, TryLockError> {
1032        match self.s.try_acquire(self.mr as usize) {
1033            Ok(permit) => permit,
1034            Err(TryAcquireError::NoPermits) => return Err(TryLockError(())),
1035            Err(TryAcquireError::Closed) => unreachable!(),
1036        }
1037
1038        let guard = OwnedRwLockWriteGuard {
1039            #[cfg(all(tokio_unstable, feature = "tracing"))]
1040            resource_span: self.resource_span.clone(),
1041            permits_acquired: self.mr,
1042            data: self.c.get(),
1043            lock: self,
1044            _p: PhantomData,
1045        };
1046
1047        #[cfg(all(tokio_unstable, feature = "tracing"))]
1048        guard.resource_span.in_scope(|| {
1049            tracing::trace!(
1050            target: "runtime::resource::state_update",
1051            write_locked = true,
1052            write_locked.op = "override",
1053            )
1054        });
1055
1056        Ok(guard)
1057    }
1058
1059    /// Returns a mutable reference to the underlying data.
1060    ///
1061    /// Since this call borrows the `RwLock` mutably, no actual locking needs to
1062    /// take place -- the mutable borrow statically guarantees no locks exist.
1063    ///
1064    /// # Examples
1065    ///
1066    /// ```
1067    /// use tokio::sync::RwLock;
1068    ///
1069    /// fn main() {
1070    ///     let mut lock = RwLock::new(1);
1071    ///
1072    ///     let n = lock.get_mut();
1073    ///     *n = 2;
1074    /// }
1075    /// ```
1076    pub fn get_mut(&mut self) -> &mut T {
1077        unsafe {
1078            // Safety: This is https://github.com/rust-lang/rust/pull/76936
1079            &mut *self.c.get()
1080        }
1081    }
1082
1083    /// Consumes the lock, returning the underlying data.
1084    pub fn into_inner(self) -> T
1085    where
1086        T: Sized,
1087    {
1088        self.c.into_inner()
1089    }
1090}
1091
1092impl<T> From<T> for RwLock<T> {
1093    fn from(s: T) -> Self {
1094        Self::new(s)
1095    }
1096}
1097
1098impl<T: ?Sized> Default for RwLock<T>
1099where
1100    T: Default,
1101{
1102    fn default() -> Self {
1103        Self::new(T::default())
1104    }
1105}
1106
1107impl<T: ?Sized> std::fmt::Debug for RwLock<T>
1108where
1109    T: std::fmt::Debug,
1110{
1111    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1112        let mut d = f.debug_struct("RwLock");
1113        match self.try_read() {
1114            Ok(inner) => d.field("data", &&*inner),
1115            Err(_) => d.field("data", &format_args!("<locked>")),
1116        };
1117        d.finish()
1118    }
1119}