spin/
rw_lock.rs

1use core::cell::UnsafeCell;
2use core::default::Default;
3use core::fmt;
4use core::marker::PhantomData;
5use core::mem;
6use core::ops::{Deref, DerefMut};
7use core::ptr::NonNull;
8use core::sync::atomic::{spin_loop_hint as cpu_relax, AtomicUsize, Ordering};
9
10/// A reader-writer lock
11///
12/// This type of lock allows a number of readers or at most one writer at any
13/// point in time. The write portion of this lock typically allows modification
14/// of the underlying data (exclusive access) and the read portion of this lock
15/// typically allows for read-only access (shared access).
16///
17/// The type parameter `T` represents the data that this lock protects. It is
18/// required that `T` satisfies `Send` to be shared across tasks and `Sync` to
19/// allow concurrent access through readers. The RAII guards returned from the
20/// locking methods implement `Deref` (and `DerefMut` for the `write` methods)
21/// to allow access to the contained of the lock.
22///
23/// An [`RwLockUpgradeableGuard`](RwLockUpgradeableGuard) can be upgraded to a
24/// writable guard through the [`RwLockUpgradeableGuard::upgrade`](RwLockUpgradeableGuard::upgrade)
25/// [`RwLockUpgradeableGuard::try_upgrade`](RwLockUpgradeableGuard::try_upgrade) functions.
26/// Writable or upgradeable guards can be downgraded through their respective `downgrade`
27/// functions.
28///
29/// Based on Facebook's
30/// [`folly/RWSpinLock.h`](https://github.com/facebook/folly/blob/a0394d84f2d5c3e50ebfd0566f9d3acb52cfab5a/folly/synchronization/RWSpinLock.h).
31/// This implementation is unfair to writers - if the lock always has readers, then no writers will
32/// ever get a chance. Using an upgradeable lock guard can *somewhat* alleviate this issue as no
33/// new readers are allowed when an upgradeable guard is held, but upgradeable guards can be taken
34/// when there are existing readers. However if the lock is that highly contended and writes are
35/// crucial then this implementation may be a poor choice.
36///
37/// # Examples
38///
39/// ```
40/// use spin;
41///
42/// let lock = spin::RwLock::new(5);
43///
44/// // many reader locks can be held at once
45/// {
46///     let r1 = lock.read();
47///     let r2 = lock.read();
48///     assert_eq!(*r1, 5);
49///     assert_eq!(*r2, 5);
50/// } // read locks are dropped at this point
51///
52/// // only one write lock may be held, however
53/// {
54///     let mut w = lock.write();
55///     *w += 1;
56///     assert_eq!(*w, 6);
57/// } // write lock is dropped here
58/// ```
59pub struct RwLock<T: ?Sized> {
60    lock: AtomicUsize,
61    data: UnsafeCell<T>,
62}
63
64const READER: usize = 1 << 2;
65const UPGRADED: usize = 1 << 1;
66const WRITER: usize = 1;
67
68/// A guard from which the protected data can be read
69///
70/// When the guard falls out of scope it will decrement the read count,
71/// potentially releasing the lock.
72#[derive(Debug)]
73pub struct RwLockReadGuard<'a, T: 'a + ?Sized> {
74    lock: &'a AtomicUsize,
75    data: NonNull<T>,
76}
77
78/// A guard to which the protected data can be written
79///
80/// When the guard falls out of scope it will release the lock.
81#[derive(Debug)]
82pub struct RwLockWriteGuard<'a, T: 'a + ?Sized> {
83    lock: &'a AtomicUsize,
84    data: NonNull<T>,
85    #[doc(hidden)]
86    _invariant: PhantomData<&'a mut T>,
87}
88
89/// A guard from which the protected data can be read, and can be upgraded
90/// to a writable guard if needed
91///
92/// No writers or other upgradeable guards can exist while this is in scope. New reader
93/// creation is prevented (to alleviate writer starvation) but there may be existing readers
94/// when the lock is acquired.
95///
96/// When the guard falls out of scope it will release the lock.
97#[derive(Debug)]
98pub struct RwLockUpgradeableGuard<'a, T: 'a + ?Sized> {
99    lock: &'a AtomicUsize,
100    data: NonNull<T>,
101    #[doc(hidden)]
102    _invariant: PhantomData<&'a mut T>,
103}
104
105// Same unsafe impls as `std::sync::RwLock`
106unsafe impl<T: ?Sized + Send> Send for RwLock<T> {}
107unsafe impl<T: ?Sized + Send + Sync> Sync for RwLock<T> {}
108
109impl<T> RwLock<T> {
110    /// Creates a new spinlock wrapping the supplied data.
111    ///
112    /// May be used statically:
113    ///
114    /// ```
115    /// use spin;
116    ///
117    /// static RW_LOCK: spin::RwLock<()> = spin::RwLock::new(());
118    ///
119    /// fn demo() {
120    ///     let lock = RW_LOCK.read();
121    ///     // do something with lock
122    ///     drop(lock);
123    /// }
124    /// ```
125    #[inline]
126    pub const fn new(user_data: T) -> RwLock<T> {
127        RwLock {
128            lock: AtomicUsize::new(0),
129            data: UnsafeCell::new(user_data),
130        }
131    }
132
133    /// Consumes this `RwLock`, returning the underlying data.
134    #[inline]
135    pub fn into_inner(self) -> T {
136        // We know statically that there are no outstanding references to
137        // `self` so there's no need to lock.
138        let RwLock { data, .. } = self;
139        data.into_inner()
140    }
141}
142
143impl<T: ?Sized> RwLock<T> {
144    /// Locks this rwlock with shared read access, blocking the current thread
145    /// until it can be acquired.
146    ///
147    /// The calling thread will be blocked until there are no more writers which
148    /// hold the lock. There may be other readers currently inside the lock when
149    /// this method returns. This method does not provide any guarantees with
150    /// respect to the ordering of whether contentious readers or writers will
151    /// acquire the lock first.
152    ///
153    /// Returns an RAII guard which will release this thread's shared access
154    /// once it is dropped.
155    ///
156    /// ```
157    /// let mylock = spin::RwLock::new(0);
158    /// {
159    ///     let mut data = mylock.read();
160    ///     // The lock is now locked and the data can be read
161    ///     println!("{}", *data);
162    ///     // The lock is dropped
163    /// }
164    /// ```
165    #[inline]
166    pub fn read(&self) -> RwLockReadGuard<T> {
167        loop {
168            match self.try_read() {
169                Some(guard) => return guard,
170                None => cpu_relax(),
171            }
172        }
173    }
174
175    /// Attempt to acquire this lock with shared read access.
176    ///
177    /// This function will never block and will return immediately if `read`
178    /// would otherwise succeed. Returns `Some` of an RAII guard which will
179    /// release the shared access of this thread when dropped, or `None` if the
180    /// access could not be granted. This method does not provide any
181    /// guarantees with respect to the ordering of whether contentious readers
182    /// or writers will acquire the lock first.
183    ///
184    /// ```
185    /// let mylock = spin::RwLock::new(0);
186    /// {
187    ///     match mylock.try_read() {
188    ///         Some(data) => {
189    ///             // The lock is now locked and the data can be read
190    ///             println!("{}", *data);
191    ///             // The lock is dropped
192    ///         },
193    ///         None => (), // no cigar
194    ///     };
195    /// }
196    /// ```
197    #[inline]
198    pub fn try_read(&self) -> Option<RwLockReadGuard<T>> {
199        let value = self.lock.fetch_add(READER, Ordering::Acquire);
200
201        // We check the UPGRADED bit here so that new readers are prevented when an UPGRADED lock is held.
202        // This helps reduce writer starvation.
203        if value & (WRITER | UPGRADED) != 0 {
204            // Lock is taken, undo.
205            self.lock.fetch_sub(READER, Ordering::Release);
206            None
207        } else {
208            Some(RwLockReadGuard {
209                lock: &self.lock,
210                data: unsafe { NonNull::new_unchecked(self.data.get()) },
211            })
212        }
213    }
214
215    /// Force decrement the reader count.
216    ///
217    /// This is *extremely* unsafe if there are outstanding `RwLockReadGuard`s
218    /// live, or if called more times than `read` has been called, but can be
219    /// useful in FFI contexts where the caller doesn't know how to deal with
220    /// RAII. The underlying atomic operation uses `Ordering::Release`.
221    #[inline]
222    pub unsafe fn force_read_decrement(&self) {
223        debug_assert!(self.lock.load(Ordering::Relaxed) & !WRITER > 0);
224        self.lock.fetch_sub(READER, Ordering::Release);
225    }
226
227    /// Force unlock exclusive write access.
228    ///
229    /// This is *extremely* unsafe if there are outstanding `RwLockWriteGuard`s
230    /// live, or if called when there are current readers, but can be useful in
231    /// FFI contexts where the caller doesn't know how to deal with RAII. The
232    /// underlying atomic operation uses `Ordering::Release`.
233    #[inline]
234    pub unsafe fn force_write_unlock(&self) {
235        debug_assert_eq!(self.lock.load(Ordering::Relaxed) & !(WRITER | UPGRADED), 0);
236        self.lock.fetch_and(!(WRITER | UPGRADED), Ordering::Release);
237    }
238
239    #[inline(always)]
240    fn try_write_internal(&self, strong: bool) -> Option<RwLockWriteGuard<T>> {
241        if compare_exchange(
242            &self.lock,
243            0,
244            WRITER,
245            Ordering::Acquire,
246            Ordering::Relaxed,
247            strong,
248        )
249        .is_ok()
250        {
251            Some(RwLockWriteGuard {
252                lock: &self.lock,
253                data: unsafe { NonNull::new_unchecked(self.data.get()) },
254                _invariant: PhantomData,
255            })
256        } else {
257            None
258        }
259    }
260
261    /// Lock this rwlock with exclusive write access, blocking the current
262    /// thread until it can be acquired.
263    ///
264    /// This function will not return while other writers or other readers
265    /// currently have access to the lock.
266    ///
267    /// Returns an RAII guard which will drop the write access of this rwlock
268    /// when dropped.
269    ///
270    /// ```
271    /// let mylock = spin::RwLock::new(0);
272    /// {
273    ///     let mut data = mylock.write();
274    ///     // The lock is now locked and the data can be written
275    ///     *data += 1;
276    ///     // The lock is dropped
277    /// }
278    /// ```
279    #[inline]
280    pub fn write(&self) -> RwLockWriteGuard<T> {
281        loop {
282            match self.try_write_internal(false) {
283                Some(guard) => return guard,
284                None => cpu_relax(),
285            }
286        }
287    }
288
289    /// Attempt to lock this rwlock with exclusive write access.
290    ///
291    /// This function does not ever block, and it will return `None` if a call
292    /// to `write` would otherwise block. If successful, an RAII guard is
293    /// returned.
294    ///
295    /// ```
296    /// let mylock = spin::RwLock::new(0);
297    /// {
298    ///     match mylock.try_write() {
299    ///         Some(mut data) => {
300    ///             // The lock is now locked and the data can be written
301    ///             *data += 1;
302    ///             // The lock is implicitly dropped
303    ///         },
304    ///         None => (), // no cigar
305    ///     };
306    /// }
307    /// ```
308    #[inline]
309    pub fn try_write(&self) -> Option<RwLockWriteGuard<T>> {
310        self.try_write_internal(true)
311    }
312
313    /// Obtain a readable lock guard that can later be upgraded to a writable lock guard.
314    /// Upgrades can be done through the [`RwLockUpgradeableGuard::upgrade`](RwLockUpgradeableGuard::upgrade) method.
315    #[inline]
316    pub fn upgradeable_read(&self) -> RwLockUpgradeableGuard<T> {
317        loop {
318            match self.try_upgradeable_read() {
319                Some(guard) => return guard,
320                None => cpu_relax(),
321            }
322        }
323    }
324
325    /// Tries to obtain an upgradeable lock guard.
326    #[inline]
327    pub fn try_upgradeable_read(&self) -> Option<RwLockUpgradeableGuard<T>> {
328        if self.lock.fetch_or(UPGRADED, Ordering::Acquire) & (WRITER | UPGRADED) == 0 {
329            Some(RwLockUpgradeableGuard {
330                lock: &self.lock,
331                data: unsafe { NonNull::new_unchecked(self.data.get()) },
332                _invariant: PhantomData,
333            })
334        } else {
335            // We can't unflip the UPGRADED bit back just yet as there is another upgradeable or write lock.
336            // When they unlock, they will clear the bit.
337            None
338        }
339    }
340}
341
342impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLock<T> {
343    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
344        match self.try_read() {
345            Some(guard) => write!(f, "RwLock {{ data: ")
346                .and_then(|()| (&*guard).fmt(f))
347                .and_then(|()| write!(f, "}}")),
348            None => write!(f, "RwLock {{ <locked> }}"),
349        }
350    }
351}
352
353impl<T: ?Sized + Default> Default for RwLock<T> {
354    fn default() -> RwLock<T> {
355        RwLock::new(Default::default())
356    }
357}
358
359impl<'rwlock, T: ?Sized> RwLockUpgradeableGuard<'rwlock, T> {
360    #[inline(always)]
361    fn try_upgrade_internal(self, strong: bool) -> Result<RwLockWriteGuard<'rwlock, T>, Self> {
362        if compare_exchange(
363            &self.lock,
364            UPGRADED,
365            WRITER,
366            Ordering::Acquire,
367            Ordering::Relaxed,
368            strong,
369        )
370        .is_ok()
371        {
372            // Upgrade successful
373            let out = Ok(RwLockWriteGuard {
374                lock: &self.lock,
375                data: self.data,
376                _invariant: PhantomData,
377            });
378
379            // Forget the old guard so its destructor doesn't run
380            mem::forget(self);
381
382            out
383        } else {
384            Err(self)
385        }
386    }
387
388    /// Upgrades an upgradeable lock guard to a writable lock guard.
389    ///
390    /// ```
391    /// let mylock = spin::RwLock::new(0);
392    ///
393    /// let upgradeable = mylock.upgradeable_read(); // Readable, but not yet writable
394    /// let writable = upgradeable.upgrade();
395    /// ```
396    #[inline]
397    pub fn upgrade(mut self) -> RwLockWriteGuard<'rwlock, T> {
398        loop {
399            self = match self.try_upgrade_internal(false) {
400                Ok(guard) => return guard,
401                Err(e) => e,
402            };
403
404            cpu_relax();
405        }
406    }
407
408    /// Tries to upgrade an upgradeable lock guard to a writable lock guard.
409    ///
410    /// ```
411    /// let mylock = spin::RwLock::new(0);
412    /// let upgradeable = mylock.upgradeable_read(); // Readable, but not yet writable
413    ///
414    /// match upgradeable.try_upgrade() {
415    ///     Ok(writable) => /* upgrade successful - use writable lock guard */ (),
416    ///     Err(upgradeable) => /* upgrade unsuccessful */ (),
417    /// };
418    /// ```
419    #[inline]
420    pub fn try_upgrade(self) -> Result<RwLockWriteGuard<'rwlock, T>, Self> {
421        self.try_upgrade_internal(true)
422    }
423
424    #[inline]
425    /// Downgrades the upgradeable lock guard to a readable, shared lock guard. Cannot fail and is guaranteed not to spin.
426    ///
427    /// ```
428    /// let mylock = spin::RwLock::new(1);
429    ///
430    /// let upgradeable = mylock.upgradeable_read();
431    /// assert!(mylock.try_read().is_none());
432    /// assert_eq!(*upgradeable, 1);
433    ///
434    /// let readable = upgradeable.downgrade(); // This is guaranteed not to spin
435    /// assert!(mylock.try_read().is_some());
436    /// assert_eq!(*readable, 1);
437    /// ```
438    pub fn downgrade(self) -> RwLockReadGuard<'rwlock, T> {
439        // Reserve the read guard for ourselves
440        self.lock.fetch_add(READER, Ordering::Acquire);
441
442        RwLockReadGuard {
443            lock: &self.lock,
444            data: self.data,
445        }
446
447        // Dropping self removes the UPGRADED bit
448    }
449}
450
451impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> {
452    /// Downgrades the writable lock guard to a readable, shared lock guard. Cannot fail and is guaranteed not to spin.
453    ///
454    /// ```
455    /// let mylock = spin::RwLock::new(0);
456    ///
457    /// let mut writable = mylock.write();
458    /// *writable = 1;
459    ///
460    /// let readable = writable.downgrade(); // This is guaranteed not to spin
461    /// # let readable_2 = mylock.try_read().unwrap();
462    /// assert_eq!(*readable, 1);
463    /// ```
464    #[inline]
465    pub fn downgrade(self) -> RwLockReadGuard<'rwlock, T> {
466        // Reserve the read guard for ourselves
467        self.lock.fetch_add(READER, Ordering::Acquire);
468
469        RwLockReadGuard {
470            lock: &self.lock,
471            data: self.data,
472        }
473
474        // Dropping self removes the WRITER bit
475    }
476}
477
478impl<'rwlock, T: ?Sized> Deref for RwLockReadGuard<'rwlock, T> {
479    type Target = T;
480
481    fn deref(&self) -> &T {
482        unsafe { self.data.as_ref() }
483    }
484}
485
486impl<'rwlock, T: ?Sized> Deref for RwLockUpgradeableGuard<'rwlock, T> {
487    type Target = T;
488
489    fn deref(&self) -> &T {
490        unsafe { self.data.as_ref() }
491    }
492}
493
494impl<'rwlock, T: ?Sized> Deref for RwLockWriteGuard<'rwlock, T> {
495    type Target = T;
496
497    fn deref(&self) -> &T {
498        unsafe { self.data.as_ref() }
499    }
500}
501
502impl<'rwlock, T: ?Sized> DerefMut for RwLockWriteGuard<'rwlock, T> {
503    fn deref_mut(&mut self) -> &mut T {
504        unsafe { self.data.as_mut() }
505    }
506}
507
508impl<'rwlock, T: ?Sized> Drop for RwLockReadGuard<'rwlock, T> {
509    fn drop(&mut self) {
510        debug_assert!(self.lock.load(Ordering::Relaxed) & !(WRITER | UPGRADED) > 0);
511        self.lock.fetch_sub(READER, Ordering::Release);
512    }
513}
514
515impl<'rwlock, T: ?Sized> Drop for RwLockUpgradeableGuard<'rwlock, T> {
516    fn drop(&mut self) {
517        debug_assert_eq!(
518            self.lock.load(Ordering::Relaxed) & (WRITER | UPGRADED),
519            UPGRADED
520        );
521        self.lock.fetch_sub(UPGRADED, Ordering::AcqRel);
522    }
523}
524
525impl<'rwlock, T: ?Sized> Drop for RwLockWriteGuard<'rwlock, T> {
526    fn drop(&mut self) {
527        debug_assert_eq!(self.lock.load(Ordering::Relaxed) & WRITER, WRITER);
528
529        // Writer is responsible for clearing both WRITER and UPGRADED bits.
530        // The UPGRADED bit may be set if an upgradeable lock attempts an upgrade while this lock is held.
531        self.lock.fetch_and(!(WRITER | UPGRADED), Ordering::Release);
532    }
533}
534
535#[inline(always)]
536fn compare_exchange(
537    atomic: &AtomicUsize,
538    current: usize,
539    new: usize,
540    success: Ordering,
541    failure: Ordering,
542    strong: bool,
543) -> Result<usize, usize> {
544    if strong {
545        atomic.compare_exchange(current, new, success, failure)
546    } else {
547        atomic.compare_exchange_weak(current, new, success, failure)
548    }
549}
550
551#[cfg(test)]
552mod tests {
553    use std::prelude::v1::*;
554
555    use std::sync::atomic::{AtomicUsize, Ordering};
556    use std::sync::mpsc::channel;
557    use std::sync::Arc;
558    use std::thread;
559
560    use super::*;
561
562    #[derive(Eq, PartialEq, Debug)]
563    struct NonCopy(i32);
564
565    #[test]
566    fn smoke() {
567        let l = RwLock::new(());
568        drop(l.read());
569        drop(l.write());
570        drop((l.read(), l.read()));
571        drop(l.write());
572    }
573
574    // TODO: needs RNG
575    //#[test]
576    //fn frob() {
577    //    static R: RwLock = RwLock::new();
578    //    const N: usize = 10;
579    //    const M: usize = 1000;
580    //
581    //    let (tx, rx) = channel::<()>();
582    //    for _ in 0..N {
583    //        let tx = tx.clone();
584    //        thread::spawn(move|| {
585    //            let mut rng = rand::thread_rng();
586    //            for _ in 0..M {
587    //                if rng.gen_weighted_bool(N) {
588    //                    drop(R.write());
589    //                } else {
590    //                    drop(R.read());
591    //                }
592    //            }
593    //            drop(tx);
594    //        });
595    //    }
596    //    drop(tx);
597    //    let _ = rx.recv();
598    //    unsafe { R.destroy(); }
599    //}
600
601    #[test]
602    fn test_rw_arc() {
603        let arc = Arc::new(RwLock::new(0));
604        let arc2 = arc.clone();
605        let (tx, rx) = channel();
606
607        thread::spawn(move || {
608            let mut lock = arc2.write();
609            for _ in 0..10 {
610                let tmp = *lock;
611                *lock = -1;
612                thread::yield_now();
613                *lock = tmp + 1;
614            }
615            tx.send(()).unwrap();
616        });
617
618        // Readers try to catch the writer in the act
619        let mut children = Vec::new();
620        for _ in 0..5 {
621            let arc3 = arc.clone();
622            children.push(thread::spawn(move || {
623                let lock = arc3.read();
624                assert!(*lock >= 0);
625            }));
626        }
627
628        // Wait for children to pass their asserts
629        for r in children {
630            assert!(r.join().is_ok());
631        }
632
633        // Wait for writer to finish
634        rx.recv().unwrap();
635        let lock = arc.read();
636        assert_eq!(*lock, 10);
637    }
638
639    #[test]
640    fn test_rw_access_in_unwind() {
641        let arc = Arc::new(RwLock::new(1));
642        let arc2 = arc.clone();
643        let _ = thread::spawn(move || -> () {
644            struct Unwinder {
645                i: Arc<RwLock<isize>>,
646            }
647            impl Drop for Unwinder {
648                fn drop(&mut self) {
649                    let mut lock = self.i.write();
650                    *lock += 1;
651                }
652            }
653            let _u = Unwinder { i: arc2 };
654            panic!();
655        })
656        .join();
657        let lock = arc.read();
658        assert_eq!(*lock, 2);
659    }
660
661    #[test]
662    fn test_rwlock_unsized() {
663        let rw: &RwLock<[i32]> = &RwLock::new([1, 2, 3]);
664        {
665            let b = &mut *rw.write();
666            b[0] = 4;
667            b[2] = 5;
668        }
669        let comp: &[i32] = &[4, 2, 5];
670        assert_eq!(&*rw.read(), comp);
671    }
672
673    #[test]
674    fn test_rwlock_try_write() {
675        use std::mem::drop;
676
677        let lock = RwLock::new(0isize);
678        let read_guard = lock.read();
679
680        let write_result = lock.try_write();
681        match write_result {
682            None => (),
683            Some(_) => assert!(
684                false,
685                "try_write should not succeed while read_guard is in scope"
686            ),
687        }
688
689        drop(read_guard);
690    }
691
692    #[test]
693    fn test_rw_try_read() {
694        let m = RwLock::new(0);
695        mem::forget(m.write());
696        assert!(m.try_read().is_none());
697    }
698
699    #[test]
700    fn test_into_inner() {
701        let m = RwLock::new(NonCopy(10));
702        assert_eq!(m.into_inner(), NonCopy(10));
703    }
704
705    #[test]
706    fn test_into_inner_drop() {
707        struct Foo(Arc<AtomicUsize>);
708        impl Drop for Foo {
709            fn drop(&mut self) {
710                self.0.fetch_add(1, Ordering::SeqCst);
711            }
712        }
713        let num_drops = Arc::new(AtomicUsize::new(0));
714        let m = RwLock::new(Foo(num_drops.clone()));
715        assert_eq!(num_drops.load(Ordering::SeqCst), 0);
716        {
717            let _inner = m.into_inner();
718            assert_eq!(num_drops.load(Ordering::SeqCst), 0);
719        }
720        assert_eq!(num_drops.load(Ordering::SeqCst), 1);
721    }
722
723    #[test]
724    fn test_force_read_decrement() {
725        let m = RwLock::new(());
726        ::std::mem::forget(m.read());
727        ::std::mem::forget(m.read());
728        ::std::mem::forget(m.read());
729        assert!(m.try_write().is_none());
730        unsafe {
731            m.force_read_decrement();
732            m.force_read_decrement();
733        }
734        assert!(m.try_write().is_none());
735        unsafe {
736            m.force_read_decrement();
737        }
738        assert!(m.try_write().is_some());
739    }
740
741    #[test]
742    fn test_force_write_unlock() {
743        let m = RwLock::new(());
744        ::std::mem::forget(m.write());
745        assert!(m.try_read().is_none());
746        unsafe {
747            m.force_write_unlock();
748        }
749        assert!(m.try_read().is_some());
750    }
751
752    #[test]
753    fn test_upgrade_downgrade() {
754        let m = RwLock::new(());
755        {
756            let _r = m.read();
757            let upg = m.try_upgradeable_read().unwrap();
758            assert!(m.try_read().is_none());
759            assert!(m.try_write().is_none());
760            assert!(upg.try_upgrade().is_err());
761        }
762        {
763            let w = m.write();
764            assert!(m.try_upgradeable_read().is_none());
765            let _r = w.downgrade();
766            assert!(m.try_upgradeable_read().is_some());
767            assert!(m.try_read().is_some());
768            assert!(m.try_write().is_none());
769        }
770        {
771            let _u = m.upgradeable_read();
772            assert!(m.try_upgradeable_read().is_none());
773        }
774
775        assert!(m.try_upgradeable_read().unwrap().try_upgrade().is_ok());
776    }
777}