1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
//! A lock that allows for an unlimited number of concurrent readers, which are never blocked. //! Only one writer can access the resource at a time. //! # Examples //! ``` //! use rculock::{RcuLock, RcuGuard}; //! //! // Create a new RcuLock protecting a piece of data, in this case a number (u32). //! let data: RcuLock<u32> = RcuLock::new(5); //! assert_eq!(5, *data.read()); //! { //! // The data is cloned and handed to the writer //! let mut guard: RcuGuard<u32> = data.write(); //! // RcuGuard implements `Deref` and `DerefMut` for easy access to the data. //! *guard = 4; //! // The writer has changed its copy of the data, but the changes //! // have not yet made it back to the master `RcuLock`. //! assert_eq!(5, *data.read()); //! } //! // After the write guard is dropped, the state of the resource //! // as the writer sees it is atomically stored back into the master RcuLock. //! assert_eq!(4, *data.read()); //! ``` extern crate parking_lot; extern crate crossbeam; use std::sync::Arc; use std::sync::atomic::Ordering::Relaxed; use std::ops::{Deref, DerefMut}; use crossbeam::mem::epoch::{self, Atomic, Owned}; use parking_lot::{Mutex, MutexGuard}; unsafe impl<T: Clone> Sync for RcuLock<T> {} unsafe impl<T: Clone> Send for RcuLock<T> {} #[derive(Debug)] pub struct RcuLock<T: Clone> { /// The resource protected by the lock, behind an `Atomic` for atomic stores, /// and an Arc to hand the resource out to readers without fear of memory leaks. inner: Atomic<Arc<T>>, /// Mutex to ensure at most one writer to prevent a data race, which will occur /// when multiple writers each acquire a copy of the resource protected by the /// `RcuLock`, write to it, and then store their individual changes to the master `RcuLock`. /// Acquired on `write()` and released when `RcuGuard` is dropped. write_lock: Mutex<()>, } impl<T: Clone> RcuLock<T> { /// Create a new RcuLock. pub fn new(target: T) -> RcuLock<T> { let inner = Atomic::null(); let arc = Owned::new(Arc::new(target)); inner.store(Some(arc), Relaxed); RcuLock { inner: inner, write_lock: Mutex::new(()), } } /// Acquire a read handle to the `RcuLock`. This operation never blocks. pub fn read(&self) -> Arc<T> { let epoch = epoch::pin(); let inner = self.inner.load(Relaxed, &epoch); inner.unwrap().deref().deref().clone() } /// Acquire an exclusive write handle to the `RcuLock`, protected by an `RcuGuard`. /// This operation blocks if another `RcuGuard` is currently alive, i.e. /// the `RcuLock` has already handed one out to another writer. /// /// Clones the data protected by the `RcuLock`, which can be expensive. pub fn write(&self) -> RcuGuard<T> { let guard = self.write_lock.lock(); let epoch = epoch::pin(); let data: T = self.inner.load(Relaxed, &epoch).unwrap().deref().deref().deref().clone(); RcuGuard { lock: self, data: data, _guard: guard, } } } pub struct RcuGuard<'a, T: 'a + Clone> { lock: &'a RcuLock<T>, data: T, _guard: MutexGuard<'a, ()>, } impl<'a, T: Clone> DerefMut for RcuGuard<'a, T> { fn deref_mut(&mut self) -> &mut T { &mut self.data } } impl<'a, T: Clone> Deref for RcuGuard<'a, T> { type Target = T; fn deref(&self) -> &T { &self.data } } /// On drop, atomically store the data back into the owning `RcuLock`. impl<'a, T: Clone> Drop for RcuGuard<'a, T> { fn drop(&mut self) { let data = Owned::new(Arc::new(self.data.clone())); self.lock.inner.store(Some(data), Relaxed) } }