Coverage Report

Created: 2026-02-14 06:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-1.49.0/src/sync/rwlock.rs
Line
Count
Source
1
use crate::sync::batch_semaphore::{Semaphore, TryAcquireError};
2
use crate::sync::mutex::TryLockError;
3
#[cfg(all(tokio_unstable, feature = "tracing"))]
4
use crate::util::trace;
5
use std::cell::UnsafeCell;
6
use std::marker;
7
use std::marker::PhantomData;
8
use std::sync::Arc;
9
10
pub(crate) mod owned_read_guard;
11
pub(crate) mod owned_write_guard;
12
pub(crate) mod owned_write_guard_mapped;
13
pub(crate) mod read_guard;
14
pub(crate) mod write_guard;
15
pub(crate) mod write_guard_mapped;
16
pub(crate) use owned_read_guard::OwnedRwLockReadGuard;
17
pub(crate) use owned_write_guard::OwnedRwLockWriteGuard;
18
pub(crate) use owned_write_guard_mapped::OwnedRwLockMappedWriteGuard;
19
pub(crate) use read_guard::RwLockReadGuard;
20
pub(crate) use write_guard::RwLockWriteGuard;
21
pub(crate) use write_guard_mapped::RwLockMappedWriteGuard;
22
23
#[cfg(not(loom))]
24
const MAX_READS: u32 = u32::MAX >> 3;
25
26
#[cfg(loom)]
27
const 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(flavor = "current_thread")]
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
88
pub 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))]
104
fn 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>.
149
unsafe impl<T> Send for RwLock<T> where T: ?Sized + Send {}
150
unsafe 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`.
154
unsafe impl<T> Send for RwLockReadGuard<'_, T> where T: ?Sized + Sync {}
155
unsafe 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.
158
unsafe impl<T, U> Send for OwnedRwLockReadGuard<T, U>
159
where
160
    T: ?Sized + Send + Sync,
161
    U: ?Sized + Sync,
162
{
163
}
164
unsafe impl<T, U> Sync for OwnedRwLockReadGuard<T, U>
165
where
166
    T: ?Sized + Send + Sync,
167
    U: ?Sized + Send + Sync,
168
{
169
}
170
unsafe impl<T> Sync for RwLockWriteGuard<'_, T> where T: ?Sized + Send + Sync {}
171
unsafe impl<T> Sync for OwnedRwLockWriteGuard<T> where T: ?Sized + Send + Sync {}
172
unsafe impl<T> Sync for RwLockMappedWriteGuard<'_, T> where T: ?Sized + Send + Sync {}
173
unsafe impl<T, U> Sync for OwnedRwLockMappedWriteGuard<T, U>
174
where
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.
183
unsafe impl<T> Send for RwLockWriteGuard<'_, T> where T: ?Sized + Send + Sync {}
184
unsafe impl<T> Send for OwnedRwLockWriteGuard<T> where T: ?Sized + Send + Sync {}
185
unsafe impl<T> Send for RwLockMappedWriteGuard<'_, T> where T: ?Sized + Send + Sync {}
186
unsafe impl<T, U> Send for OwnedRwLockMappedWriteGuard<T, U>
187
where
188
    T: ?Sized + Send + Sync,
189
    U: ?Sized + Send + Sync,
190
{
191
}
192
193
impl<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
0
    pub fn new(value: T) -> RwLock<T>
205
0
    where
206
0
        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
0
        let s = Semaphore::new(MAX_READS as usize);
246
247
0
        RwLock {
248
0
            mr: MAX_READS,
249
0
            c: UnsafeCell::new(value),
250
0
            s,
251
0
            #[cfg(all(tokio_unstable, feature = "tracing"))]
252
0
            resource_span,
253
0
        }
254
0
    }
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
0
    pub fn with_max_readers(value: T, max_reads: u32) -> RwLock<T>
272
0
    where
273
0
        T: Sized,
274
    {
275
0
        assert!(
276
0
            max_reads <= MAX_READS,
277
0
            "a RwLock may not be created with more than {MAX_READS} readers"
278
        );
279
280
        #[cfg(all(tokio_unstable, feature = "tracing"))]
281
        let resource_span = {
282
            let location = std::panic::Location::caller();
283
284
            let resource_span = tracing::trace_span!(
285
                parent: None,
286
                "runtime.resource",
287
                concrete_type = "RwLock",
288
                kind = "Sync",
289
                loc.file = location.file(),
290
                loc.line = location.line(),
291
                loc.col = location.column(),
292
            );
293
294
            resource_span.in_scope(|| {
295
                tracing::trace!(
296
                    target: "runtime::resource::state_update",
297
                    max_readers = max_reads,
298
                );
299
300
                tracing::trace!(
301
                    target: "runtime::resource::state_update",
302
                    write_locked = false,
303
                );
304
305
                tracing::trace!(
306
                    target: "runtime::resource::state_update",
307
                    current_readers = 0,
308
                );
309
            });
310
311
            resource_span
312
        };
313
314
        #[cfg(all(tokio_unstable, feature = "tracing"))]
315
        let s = resource_span.in_scope(|| Semaphore::new(max_reads as usize));
316
317
        #[cfg(any(not(tokio_unstable), not(feature = "tracing")))]
318
0
        let s = Semaphore::new(max_reads as usize);
319
320
0
        RwLock {
321
0
            mr: max_reads,
322
0
            c: UnsafeCell::new(value),
323
0
            s,
324
0
            #[cfg(all(tokio_unstable, feature = "tracing"))]
325
0
            resource_span,
326
0
        }
327
0
    }
328
329
    /// Creates a new instance of an `RwLock<T>` which is unlocked.
330
    ///
331
    /// When using the `tracing` [unstable feature], a `RwLock` created with
332
    /// `const_new` will not be instrumented. As such, it will not be visible
333
    /// in [`tokio-console`]. Instead, [`RwLock::new`] should be used to create
334
    /// an instrumented object if that is needed.
335
    ///
336
    /// # Examples
337
    ///
338
    /// ```
339
    /// use tokio::sync::RwLock;
340
    ///
341
    /// static LOCK: RwLock<i32> = RwLock::const_new(5);
342
    /// ```
343
    ///
344
    /// [`tokio-console`]: https://github.com/tokio-rs/console
345
    /// [unstable feature]: crate#unstable-features
346
    #[cfg(not(all(loom, test)))]
347
0
    pub const fn const_new(value: T) -> RwLock<T>
348
0
    where
349
0
        T: Sized,
350
    {
351
0
        RwLock {
352
0
            mr: MAX_READS,
353
0
            c: UnsafeCell::new(value),
354
0
            s: Semaphore::const_new(MAX_READS as usize),
355
0
            #[cfg(all(tokio_unstable, feature = "tracing"))]
356
0
            resource_span: tracing::Span::none(),
357
0
        }
358
0
    }
359
360
    /// Creates a new instance of an `RwLock<T>` which is unlocked
361
    /// and allows a maximum of `max_reads` concurrent readers.
362
    ///
363
    /// # Examples
364
    ///
365
    /// ```
366
    /// use tokio::sync::RwLock;
367
    ///
368
    /// static LOCK: RwLock<i32> = RwLock::const_with_max_readers(5, 1024);
369
    /// ```
370
    #[cfg(not(all(loom, test)))]
371
0
    pub const fn const_with_max_readers(value: T, max_reads: u32) -> RwLock<T>
372
0
    where
373
0
        T: Sized,
374
    {
375
0
        assert!(max_reads <= MAX_READS);
376
377
0
        RwLock {
378
0
            mr: max_reads,
379
0
            c: UnsafeCell::new(value),
380
0
            s: Semaphore::const_new(max_reads as usize),
381
0
            #[cfg(all(tokio_unstable, feature = "tracing"))]
382
0
            resource_span: tracing::Span::none(),
383
0
        }
384
0
    }
385
386
    /// Locks this `RwLock` with shared read access, causing the current task
387
    /// to yield until the lock has been acquired.
388
    ///
389
    /// The calling task will yield until there are no writers which hold the
390
    /// lock. There may be other readers inside the lock when the task resumes.
391
    ///
392
    /// Note that under the priority policy of [`RwLock`], read locks are not
393
    /// granted until prior write locks, to prevent starvation. Therefore
394
    /// deadlock may occur if a read lock is held by the current task, a write
395
    /// lock attempt is made, and then a subsequent read lock attempt is made
396
    /// by the current task.
397
    ///
398
    /// Returns an RAII guard which will drop this read access of the `RwLock`
399
    /// when dropped.
400
    ///
401
    /// # Cancel safety
402
    ///
403
    /// This method uses a queue to fairly distribute locks in the order they
404
    /// were requested. Cancelling a call to `read` makes you lose your place in
405
    /// the queue.
406
    ///
407
    /// # Examples
408
    ///
409
    /// ```
410
    /// use std::sync::Arc;
411
    /// use tokio::sync::RwLock;
412
    ///
413
    /// # #[tokio::main(flavor = "current_thread")]
414
    /// # async fn main() {
415
    /// let lock = Arc::new(RwLock::new(1));
416
    /// let c_lock = lock.clone();
417
    ///
418
    /// let n = lock.read().await;
419
    /// assert_eq!(*n, 1);
420
    ///
421
    /// tokio::spawn(async move {
422
    ///     // While main has an active read lock, we acquire one too.
423
    ///     let r = c_lock.read().await;
424
    ///     assert_eq!(*r, 1);
425
    /// }).await.expect("The spawned task has panicked");
426
    ///
427
    /// // Drop the guard after the spawned task finishes.
428
    /// drop(n);
429
    /// # }
430
    /// ```
431
0
    pub async fn read(&self) -> RwLockReadGuard<'_, T> {
432
0
        let acquire_fut = async {
433
0
            self.s.acquire(1).await.unwrap_or_else(|_| {
434
                // The semaphore was closed. but, we never explicitly close it, and we have a
435
                // handle to it through the Arc, which means that this can never happen.
436
0
                unreachable!()
437
            });
438
439
0
            RwLockReadGuard {
440
0
                s: &self.s,
441
0
                data: self.c.get(),
442
0
                marker: PhantomData,
443
0
                #[cfg(all(tokio_unstable, feature = "tracing"))]
444
0
                resource_span: self.resource_span.clone(),
445
0
            }
446
0
        };
447
448
        #[cfg(all(tokio_unstable, feature = "tracing"))]
449
        let acquire_fut = trace::async_op(
450
            move || acquire_fut,
451
            self.resource_span.clone(),
452
            "RwLock::read",
453
            "poll",
454
            false,
455
        );
456
457
        #[allow(clippy::let_and_return)] // this lint triggers when disabling tracing
458
0
        let guard = acquire_fut.await;
459
460
        #[cfg(all(tokio_unstable, feature = "tracing"))]
461
        self.resource_span.in_scope(|| {
462
            tracing::trace!(
463
            target: "runtime::resource::state_update",
464
            current_readers = 1,
465
            current_readers.op = "add",
466
            )
467
        });
468
469
0
        guard
470
0
    }
471
472
    /// Blockingly locks this `RwLock` with shared read access.
473
    ///
474
    /// This method is intended for use cases where you
475
    /// need to use this rwlock in asynchronous code as well as in synchronous code.
476
    ///
477
    /// Returns an RAII guard which will drop the read access of this `RwLock` when dropped.
478
    ///
479
    /// # Panics
480
    ///
481
    /// This function panics if called within an asynchronous execution context.
482
    ///
483
    ///   - If you find yourself in an asynchronous execution context and needing
484
    ///     to call some (synchronous) function which performs one of these
485
    ///     `blocking_` operations, then consider wrapping that call inside
486
    ///     [`spawn_blocking()`][crate::runtime::Handle::spawn_blocking]
487
    ///     (or [`block_in_place()`][crate::task::block_in_place]).
488
    ///
489
    /// # Examples
490
    ///
491
    /// ```
492
    /// # #[cfg(not(target_family = "wasm"))]
493
    /// # {
494
    /// use std::sync::Arc;
495
    /// use tokio::sync::RwLock;
496
    ///
497
    /// #[tokio::main]
498
    /// async fn main() {
499
    ///     let rwlock = Arc::new(RwLock::new(1));
500
    ///     let mut write_lock = rwlock.write().await;
501
    ///
502
    ///     let blocking_task = tokio::task::spawn_blocking({
503
    ///         let rwlock = Arc::clone(&rwlock);
504
    ///         move || {
505
    ///             // This shall block until the `write_lock` is released.
506
    ///             let read_lock = rwlock.blocking_read();
507
    ///             assert_eq!(*read_lock, 0);
508
    ///         }
509
    ///     });
510
    ///
511
    ///     *write_lock -= 1;
512
    ///     drop(write_lock); // release the lock.
513
    ///
514
    ///     // Await the completion of the blocking task.
515
    ///     blocking_task.await.unwrap();
516
    ///
517
    ///     // Assert uncontended.
518
    ///     assert!(rwlock.try_write().is_ok());
519
    /// }
520
    /// # }
521
    /// ```
522
    #[track_caller]
523
    #[cfg(feature = "sync")]
524
0
    pub fn blocking_read(&self) -> RwLockReadGuard<'_, T> {
525
0
        crate::future::block_on(self.read())
526
0
    }
527
528
    /// Locks this `RwLock` with shared read access, causing the current task
529
    /// to yield until the lock has been acquired.
530
    ///
531
    /// The calling task will yield until there are no writers which hold the
532
    /// lock. There may be other readers inside the lock when the task resumes.
533
    ///
534
    /// This method is identical to [`RwLock::read`], except that the returned
535
    /// guard references the `RwLock` with an [`Arc`] rather than by borrowing
536
    /// it. Therefore, the `RwLock` must be wrapped in an `Arc` to call this
537
    /// method, and the guard will live for the `'static` lifetime, as it keeps
538
    /// the `RwLock` alive by holding an `Arc`.
539
    ///
540
    /// Note that under the priority policy of [`RwLock`], read locks are not
541
    /// granted until prior write locks, to prevent starvation. Therefore
542
    /// deadlock may occur if a read lock is held by the current task, a write
543
    /// lock attempt is made, and then a subsequent read lock attempt is made
544
    /// by the current task.
545
    ///
546
    /// Returns an RAII guard which will drop this read access of the `RwLock`
547
    /// when dropped.
548
    ///
549
    /// # Cancel safety
550
    ///
551
    /// This method uses a queue to fairly distribute locks in the order they
552
    /// were requested. Cancelling a call to `read_owned` makes you lose your
553
    /// place in the queue.
554
    ///
555
    /// # Examples
556
    ///
557
    /// ```
558
    /// use std::sync::Arc;
559
    /// use tokio::sync::RwLock;
560
    ///
561
    /// # #[tokio::main(flavor = "current_thread")]
562
    /// # async fn main() {
563
    /// let lock = Arc::new(RwLock::new(1));
564
    /// let c_lock = lock.clone();
565
    ///
566
    /// let n = lock.read_owned().await;
567
    /// assert_eq!(*n, 1);
568
    ///
569
    /// tokio::spawn(async move {
570
    ///     // While main has an active read lock, we acquire one too.
571
    ///     let r = c_lock.read_owned().await;
572
    ///     assert_eq!(*r, 1);
573
    /// }).await.expect("The spawned task has panicked");
574
    ///
575
    /// // Drop the guard after the spawned task finishes.
576
    /// drop(n);
577
    ///}
578
    /// ```
579
0
    pub async fn read_owned(self: Arc<Self>) -> OwnedRwLockReadGuard<T> {
580
        #[cfg(all(tokio_unstable, feature = "tracing"))]
581
        let resource_span = self.resource_span.clone();
582
583
0
        let acquire_fut = async {
584
0
            self.s.acquire(1).await.unwrap_or_else(|_| {
585
                // The semaphore was closed. but, we never explicitly close it, and we have a
586
                // handle to it through the Arc, which means that this can never happen.
587
0
                unreachable!()
588
            });
589
590
0
            OwnedRwLockReadGuard {
591
0
                #[cfg(all(tokio_unstable, feature = "tracing"))]
592
0
                resource_span: self.resource_span.clone(),
593
0
                data: self.c.get(),
594
0
                lock: self,
595
0
                _p: PhantomData,
596
0
            }
597
0
        };
598
599
        #[cfg(all(tokio_unstable, feature = "tracing"))]
600
        let acquire_fut = trace::async_op(
601
            move || acquire_fut,
602
            resource_span,
603
            "RwLock::read_owned",
604
            "poll",
605
            false,
606
        );
607
608
        #[allow(clippy::let_and_return)] // this lint triggers when disabling tracing
609
0
        let guard = acquire_fut.await;
610
611
        #[cfg(all(tokio_unstable, feature = "tracing"))]
612
        guard.resource_span.in_scope(|| {
613
            tracing::trace!(
614
            target: "runtime::resource::state_update",
615
            current_readers = 1,
616
            current_readers.op = "add",
617
            )
618
        });
619
620
0
        guard
621
0
    }
622
623
    /// Attempts to acquire this `RwLock` with shared read access.
624
    ///
625
    /// If the access couldn't be acquired immediately, returns [`TryLockError`].
626
    /// Otherwise, an RAII guard is returned which will release read access
627
    /// when dropped.
628
    ///
629
    /// [`TryLockError`]: TryLockError
630
    ///
631
    /// # Examples
632
    ///
633
    /// ```
634
    /// use std::sync::Arc;
635
    /// use tokio::sync::RwLock;
636
    ///
637
    /// # #[tokio::main(flavor = "current_thread")]
638
    /// # async fn main() {
639
    /// let lock = Arc::new(RwLock::new(1));
640
    /// let c_lock = lock.clone();
641
    ///
642
    /// let v = lock.try_read().unwrap();
643
    /// assert_eq!(*v, 1);
644
    ///
645
    /// tokio::spawn(async move {
646
    ///     // While main has an active read lock, we acquire one too.
647
    ///     let n = c_lock.read().await;
648
    ///     assert_eq!(*n, 1);
649
    /// }).await.expect("The spawned task has panicked");
650
    ///
651
    /// // Drop the guard when spawned task finishes.
652
    /// drop(v);
653
    /// # }
654
    /// ```
655
0
    pub fn try_read(&self) -> Result<RwLockReadGuard<'_, T>, TryLockError> {
656
0
        match self.s.try_acquire(1) {
657
0
            Ok(permit) => permit,
658
0
            Err(TryAcquireError::NoPermits) => return Err(TryLockError(())),
659
0
            Err(TryAcquireError::Closed) => unreachable!(),
660
        }
661
662
0
        let guard = RwLockReadGuard {
663
0
            s: &self.s,
664
0
            data: self.c.get(),
665
0
            marker: marker::PhantomData,
666
0
            #[cfg(all(tokio_unstable, feature = "tracing"))]
667
0
            resource_span: self.resource_span.clone(),
668
0
        };
669
670
        #[cfg(all(tokio_unstable, feature = "tracing"))]
671
        self.resource_span.in_scope(|| {
672
            tracing::trace!(
673
            target: "runtime::resource::state_update",
674
            current_readers = 1,
675
            current_readers.op = "add",
676
            )
677
        });
678
679
0
        Ok(guard)
680
0
    }
681
682
    /// Attempts to acquire this `RwLock` with shared read access.
683
    ///
684
    /// If the access couldn't be acquired immediately, returns [`TryLockError`].
685
    /// Otherwise, an RAII guard is returned which will release read access
686
    /// when dropped.
687
    ///
688
    /// This method is identical to [`RwLock::try_read`], except that the
689
    /// returned guard references the `RwLock` with an [`Arc`] rather than by
690
    /// borrowing it. Therefore, the `RwLock` must be wrapped in an `Arc` to
691
    /// call this method, and the guard will live for the `'static` lifetime,
692
    /// as it keeps the `RwLock` alive by holding an `Arc`.
693
    ///
694
    /// [`TryLockError`]: TryLockError
695
    ///
696
    /// # Examples
697
    ///
698
    /// ```
699
    /// use std::sync::Arc;
700
    /// use tokio::sync::RwLock;
701
    ///
702
    /// # #[tokio::main(flavor = "current_thread")]
703
    /// # async fn main() {
704
    /// let lock = Arc::new(RwLock::new(1));
705
    /// let c_lock = lock.clone();
706
    ///
707
    /// let v = lock.try_read_owned().unwrap();
708
    /// assert_eq!(*v, 1);
709
    ///
710
    /// tokio::spawn(async move {
711
    ///     // While main has an active read lock, we acquire one too.
712
    ///     let n = c_lock.read_owned().await;
713
    ///     assert_eq!(*n, 1);
714
    /// }).await.expect("The spawned task has panicked");
715
    ///
716
    /// // Drop the guard when spawned task finishes.
717
    /// drop(v);
718
    /// # }
719
    /// ```
720
0
    pub fn try_read_owned(self: Arc<Self>) -> Result<OwnedRwLockReadGuard<T>, TryLockError> {
721
0
        match self.s.try_acquire(1) {
722
0
            Ok(permit) => permit,
723
0
            Err(TryAcquireError::NoPermits) => return Err(TryLockError(())),
724
0
            Err(TryAcquireError::Closed) => unreachable!(),
725
        }
726
727
0
        let guard = OwnedRwLockReadGuard {
728
0
            #[cfg(all(tokio_unstable, feature = "tracing"))]
729
0
            resource_span: self.resource_span.clone(),
730
0
            data: self.c.get(),
731
0
            lock: self,
732
0
            _p: PhantomData,
733
0
        };
734
735
        #[cfg(all(tokio_unstable, feature = "tracing"))]
736
        guard.resource_span.in_scope(|| {
737
            tracing::trace!(
738
            target: "runtime::resource::state_update",
739
            current_readers = 1,
740
            current_readers.op = "add",
741
            )
742
        });
743
744
0
        Ok(guard)
745
0
    }
746
747
    /// Locks this `RwLock` with exclusive write access, causing the current
748
    /// task to yield until the lock has been acquired.
749
    ///
750
    /// The calling task will yield while other writers or readers currently
751
    /// have access to the lock.
752
    ///
753
    /// Returns an RAII guard which will drop the write access of this `RwLock`
754
    /// when dropped.
755
    ///
756
    /// # Cancel safety
757
    ///
758
    /// This method uses a queue to fairly distribute locks in the order they
759
    /// were requested. Cancelling a call to `write` makes you lose your place
760
    /// in the queue.
761
    ///
762
    /// # Examples
763
    ///
764
    /// ```
765
    /// use tokio::sync::RwLock;
766
    ///
767
    /// # #[tokio::main(flavor = "current_thread")]
768
    /// # async fn main() {
769
    /// let lock = RwLock::new(1);
770
    ///
771
    /// let mut n = lock.write().await;
772
    /// *n = 2;
773
    /// # }
774
    /// ```
775
0
    pub async fn write(&self) -> RwLockWriteGuard<'_, T> {
776
0
        let acquire_fut = async {
777
0
            self.s.acquire(self.mr as usize).await.unwrap_or_else(|_| {
778
                // The semaphore was closed. but, we never explicitly close it, and we have a
779
                // handle to it through the Arc, which means that this can never happen.
780
0
                unreachable!()
781
            });
782
783
0
            RwLockWriteGuard {
784
0
                permits_acquired: self.mr,
785
0
                s: &self.s,
786
0
                data: self.c.get(),
787
0
                marker: marker::PhantomData,
788
0
                #[cfg(all(tokio_unstable, feature = "tracing"))]
789
0
                resource_span: self.resource_span.clone(),
790
0
            }
791
0
        };
792
793
        #[cfg(all(tokio_unstable, feature = "tracing"))]
794
        let acquire_fut = trace::async_op(
795
            move || acquire_fut,
796
            self.resource_span.clone(),
797
            "RwLock::write",
798
            "poll",
799
            false,
800
        );
801
802
        #[allow(clippy::let_and_return)] // this lint triggers when disabling tracing
803
0
        let guard = acquire_fut.await;
804
805
        #[cfg(all(tokio_unstable, feature = "tracing"))]
806
        self.resource_span.in_scope(|| {
807
            tracing::trace!(
808
            target: "runtime::resource::state_update",
809
            write_locked = true,
810
            write_locked.op = "override",
811
            )
812
        });
813
814
0
        guard
815
0
    }
816
817
    /// Blockingly locks this `RwLock` with exclusive write access.
818
    ///
819
    /// This method is intended for use cases where you
820
    /// need to use this rwlock in asynchronous code as well as in synchronous code.
821
    ///
822
    /// Returns an RAII guard which will drop the write access of this `RwLock` when dropped.
823
    ///
824
    /// # Panics
825
    ///
826
    /// This function panics if called within an asynchronous execution context.
827
    ///
828
    ///   - If you find yourself in an asynchronous execution context and needing
829
    ///     to call some (synchronous) function which performs one of these
830
    ///     `blocking_` operations, then consider wrapping that call inside
831
    ///     [`spawn_blocking()`][crate::runtime::Handle::spawn_blocking]
832
    ///     (or [`block_in_place()`][crate::task::block_in_place]).
833
    ///
834
    /// # Examples
835
    ///
836
    /// ```
837
    /// # #[cfg(not(target_family = "wasm"))]
838
    /// # {
839
    /// use std::sync::Arc;
840
    /// use tokio::{sync::RwLock};
841
    ///
842
    /// #[tokio::main]
843
    /// async fn main() {
844
    ///     let rwlock =  Arc::new(RwLock::new(1));
845
    ///     let read_lock = rwlock.read().await;
846
    ///
847
    ///     let blocking_task = tokio::task::spawn_blocking({
848
    ///         let rwlock = Arc::clone(&rwlock);
849
    ///         move || {
850
    ///             // This shall block until the `read_lock` is released.
851
    ///             let mut write_lock = rwlock.blocking_write();
852
    ///             *write_lock = 2;
853
    ///         }
854
    ///     });
855
    ///
856
    ///     assert_eq!(*read_lock, 1);
857
    ///     // Release the last outstanding read lock.
858
    ///     drop(read_lock);
859
    ///
860
    ///     // Await the completion of the blocking task.
861
    ///     blocking_task.await.unwrap();
862
    ///
863
    ///     // Assert uncontended.
864
    ///     let read_lock = rwlock.try_read().unwrap();
865
    ///     assert_eq!(*read_lock, 2);
866
    /// }
867
    /// # }
868
    /// ```
869
    #[track_caller]
870
    #[cfg(feature = "sync")]
871
0
    pub fn blocking_write(&self) -> RwLockWriteGuard<'_, T> {
872
0
        crate::future::block_on(self.write())
873
0
    }
874
875
    /// Locks this `RwLock` with exclusive write access, causing the current
876
    /// task to yield until the lock has been acquired.
877
    ///
878
    /// The calling task will yield while other writers or readers currently
879
    /// have access to the lock.
880
    ///
881
    /// This method is identical to [`RwLock::write`], except that the returned
882
    /// guard references the `RwLock` with an [`Arc`] rather than by borrowing
883
    /// it. Therefore, the `RwLock` must be wrapped in an `Arc` to call this
884
    /// method, and the guard will live for the `'static` lifetime, as it keeps
885
    /// the `RwLock` alive by holding an `Arc`.
886
    ///
887
    /// Returns an RAII guard which will drop the write access of this `RwLock`
888
    /// when dropped.
889
    ///
890
    /// # Cancel safety
891
    ///
892
    /// This method uses a queue to fairly distribute locks in the order they
893
    /// were requested. Cancelling a call to `write_owned` makes you lose your
894
    /// place in the queue.
895
    ///
896
    /// # Examples
897
    ///
898
    /// ```
899
    /// use std::sync::Arc;
900
    /// use tokio::sync::RwLock;
901
    ///
902
    /// # #[tokio::main(flavor = "current_thread")]
903
    /// # async fn main() {
904
    /// let lock = Arc::new(RwLock::new(1));
905
    ///
906
    /// let mut n = lock.write_owned().await;
907
    /// *n = 2;
908
    ///}
909
    /// ```
910
0
    pub async fn write_owned(self: Arc<Self>) -> OwnedRwLockWriteGuard<T> {
911
        #[cfg(all(tokio_unstable, feature = "tracing"))]
912
        let resource_span = self.resource_span.clone();
913
914
0
        let acquire_fut = async {
915
0
            self.s.acquire(self.mr as usize).await.unwrap_or_else(|_| {
916
                // The semaphore was closed. but, we never explicitly close it, and we have a
917
                // handle to it through the Arc, which means that this can never happen.
918
0
                unreachable!()
919
            });
920
921
0
            OwnedRwLockWriteGuard {
922
0
                #[cfg(all(tokio_unstable, feature = "tracing"))]
923
0
                resource_span: self.resource_span.clone(),
924
0
                permits_acquired: self.mr,
925
0
                data: self.c.get(),
926
0
                lock: self,
927
0
                _p: PhantomData,
928
0
            }
929
0
        };
930
931
        #[cfg(all(tokio_unstable, feature = "tracing"))]
932
        let acquire_fut = trace::async_op(
933
            move || acquire_fut,
934
            resource_span,
935
            "RwLock::write_owned",
936
            "poll",
937
            false,
938
        );
939
940
        #[allow(clippy::let_and_return)] // this lint triggers when disabling tracing
941
0
        let guard = acquire_fut.await;
942
943
        #[cfg(all(tokio_unstable, feature = "tracing"))]
944
        guard.resource_span.in_scope(|| {
945
            tracing::trace!(
946
            target: "runtime::resource::state_update",
947
            write_locked = true,
948
            write_locked.op = "override",
949
            )
950
        });
951
952
0
        guard
953
0
    }
954
955
    /// Attempts to acquire this `RwLock` with exclusive write access.
956
    ///
957
    /// If the access couldn't be acquired immediately, returns [`TryLockError`].
958
    /// Otherwise, an RAII guard is returned which will release write access
959
    /// when dropped.
960
    ///
961
    /// [`TryLockError`]: TryLockError
962
    ///
963
    /// # Examples
964
    ///
965
    /// ```
966
    /// use tokio::sync::RwLock;
967
    ///
968
    /// # #[tokio::main(flavor = "current_thread")]
969
    /// # async fn main() {
970
    /// let rw = RwLock::new(1);
971
    ///
972
    /// let v = rw.read().await;
973
    /// assert_eq!(*v, 1);
974
    ///
975
    /// assert!(rw.try_write().is_err());
976
    /// # }
977
    /// ```
978
0
    pub fn try_write(&self) -> Result<RwLockWriteGuard<'_, T>, TryLockError> {
979
0
        match self.s.try_acquire(self.mr as usize) {
980
0
            Ok(permit) => permit,
981
0
            Err(TryAcquireError::NoPermits) => return Err(TryLockError(())),
982
0
            Err(TryAcquireError::Closed) => unreachable!(),
983
        }
984
985
0
        let guard = RwLockWriteGuard {
986
0
            permits_acquired: self.mr,
987
0
            s: &self.s,
988
0
            data: self.c.get(),
989
0
            marker: marker::PhantomData,
990
0
            #[cfg(all(tokio_unstable, feature = "tracing"))]
991
0
            resource_span: self.resource_span.clone(),
992
0
        };
993
994
        #[cfg(all(tokio_unstable, feature = "tracing"))]
995
        self.resource_span.in_scope(|| {
996
            tracing::trace!(
997
            target: "runtime::resource::state_update",
998
            write_locked = true,
999
            write_locked.op = "override",
1000
            )
1001
        });
1002
1003
0
        Ok(guard)
1004
0
    }
1005
1006
    /// Attempts to acquire this `RwLock` with exclusive write access.
1007
    ///
1008
    /// If the access couldn't be acquired immediately, returns [`TryLockError`].
1009
    /// Otherwise, an RAII guard is returned which will release write access
1010
    /// when dropped.
1011
    ///
1012
    /// This method is identical to [`RwLock::try_write`], except that the
1013
    /// returned guard references the `RwLock` with an [`Arc`] rather than by
1014
    /// borrowing it. Therefore, the `RwLock` must be wrapped in an `Arc` to
1015
    /// call this method, and the guard will live for the `'static` lifetime,
1016
    /// as it keeps the `RwLock` alive by holding an `Arc`.
1017
    ///
1018
    /// [`TryLockError`]: TryLockError
1019
    ///
1020
    /// # Examples
1021
    ///
1022
    /// ```
1023
    /// use std::sync::Arc;
1024
    /// use tokio::sync::RwLock;
1025
    ///
1026
    /// # #[tokio::main(flavor = "current_thread")]
1027
    /// # async fn main() {
1028
    /// let rw = Arc::new(RwLock::new(1));
1029
    ///
1030
    /// let v = Arc::clone(&rw).read_owned().await;
1031
    /// assert_eq!(*v, 1);
1032
    ///
1033
    /// assert!(rw.try_write_owned().is_err());
1034
    /// # }
1035
    /// ```
1036
0
    pub fn try_write_owned(self: Arc<Self>) -> Result<OwnedRwLockWriteGuard<T>, TryLockError> {
1037
0
        match self.s.try_acquire(self.mr as usize) {
1038
0
            Ok(permit) => permit,
1039
0
            Err(TryAcquireError::NoPermits) => return Err(TryLockError(())),
1040
0
            Err(TryAcquireError::Closed) => unreachable!(),
1041
        }
1042
1043
0
        let guard = OwnedRwLockWriteGuard {
1044
0
            #[cfg(all(tokio_unstable, feature = "tracing"))]
1045
0
            resource_span: self.resource_span.clone(),
1046
0
            permits_acquired: self.mr,
1047
0
            data: self.c.get(),
1048
0
            lock: self,
1049
0
            _p: PhantomData,
1050
0
        };
1051
1052
        #[cfg(all(tokio_unstable, feature = "tracing"))]
1053
        guard.resource_span.in_scope(|| {
1054
            tracing::trace!(
1055
            target: "runtime::resource::state_update",
1056
            write_locked = true,
1057
            write_locked.op = "override",
1058
            )
1059
        });
1060
1061
0
        Ok(guard)
1062
0
    }
1063
1064
    /// Returns a mutable reference to the underlying data.
1065
    ///
1066
    /// Since this call borrows the `RwLock` mutably, no actual locking needs to
1067
    /// take place -- the mutable borrow statically guarantees no locks exist.
1068
    ///
1069
    /// # Examples
1070
    ///
1071
    /// ```
1072
    /// use tokio::sync::RwLock;
1073
    ///
1074
    /// fn main() {
1075
    ///     let mut lock = RwLock::new(1);
1076
    ///
1077
    ///     let n = lock.get_mut();
1078
    ///     *n = 2;
1079
    /// }
1080
    /// ```
1081
0
    pub fn get_mut(&mut self) -> &mut T {
1082
0
        self.c.get_mut()
1083
0
    }
1084
1085
    /// Consumes the lock, returning the underlying data.
1086
0
    pub fn into_inner(self) -> T
1087
0
    where
1088
0
        T: Sized,
1089
    {
1090
0
        self.c.into_inner()
1091
0
    }
1092
}
1093
1094
impl<T> From<T> for RwLock<T> {
1095
0
    fn from(s: T) -> Self {
1096
0
        Self::new(s)
1097
0
    }
1098
}
1099
1100
impl<T> Default for RwLock<T>
1101
where
1102
    T: Default,
1103
{
1104
0
    fn default() -> Self {
1105
0
        Self::new(T::default())
1106
0
    }
1107
}
1108
1109
impl<T: ?Sized> std::fmt::Debug for RwLock<T>
1110
where
1111
    T: std::fmt::Debug,
1112
{
1113
0
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1114
0
        let mut d = f.debug_struct("RwLock");
1115
0
        match self.try_read() {
1116
0
            Ok(inner) => d.field("data", &&*inner),
1117
0
            Err(_) => d.field("data", &format_args!("<locked>")),
1118
        };
1119
0
        d.finish()
1120
0
    }
1121
}