shared_mutex/
raw.rs

1use std::sync::{Mutex, Condvar, MutexGuard};
2
3/// A raw lock providing both shared read locks and exclusive write locks.
4///
5/// Used as a raw building block for other synchronization primitives. Most
6/// users should just use `SharedMutex<T>`, which takes care of tieing the lock
7/// to some data.
8pub struct RawSharedMutex {
9    state: Mutex<State>,
10    readers: Condvar,
11    both: Condvar,
12}
13
14impl RawSharedMutex {
15    /// Create a new RawSharedMutex
16    #[inline]
17    pub fn new() -> RawSharedMutex {
18        RawSharedMutex {
19            state: Mutex::new(State::new()),
20            readers: Condvar::new(),
21            both: Condvar::new()
22        }
23    }
24
25    /// Checks if this mutex and the other are the same mutex.
26    ///
27    /// If `is` returns true, the two references point to the same
28    /// mutex, and they may be used interchangeably.
29    #[inline]
30    pub fn is(&self, other: &Self) -> bool {
31        self as *const Self == other as *const Self
32    }
33
34    /// Acquire a shared read lock.
35    ///
36    /// Blocks until a read lock can be acquired. The lock can be released
37    /// by calling `unlock_read`.
38    #[inline]
39    pub fn read(&self) {
40        self.read_from(self.state.lock().unwrap())
41    }
42
43    /// Get a read lock using the given state lock.
44    ///
45    /// WARNING: The lock MUST be from self.state!!
46    fn read_from(&self, mut state_lock: MutexGuard<State>) {
47        // Wait for any writers to finish and for there to be space
48        // for another reader. (There are a max of 2^63 readers at any time)
49        while state_lock.is_writer_active() || state_lock.has_max_readers() {
50            state_lock = self.both.wait(state_lock).unwrap();
51        }
52
53        // At this point there should be no writers and space
54        // for at least one more reader.
55        //
56        // Add ourselves as a reader.
57        state_lock.add_reader();
58    }
59
60    /// Attempt to acquire a shared read lock without blocking.
61    ///
62    /// Returns true if we succeeded and false if acquiring a read lock would
63    /// require blocking.
64    pub fn try_read(&self) -> bool {
65        let mut state_lock = self.state.lock().unwrap();
66
67        // If there isn't a waiting writer and there is space for another reader
68        // we can just take another read lock.
69        if !state_lock.is_writer_active() && !state_lock.has_max_readers() {
70            state_lock.add_reader();
71
72            // Success!
73            true
74        } else {
75            false // We would have to block
76        }
77    }
78
79    /// Acquire an exclusive write lock.
80    ///
81    /// Blocks until the write lock can be acquired. The lock can be released
82    /// by calling `unlock_write`.
83    #[inline]
84    pub fn write(&self) {
85        self.write_from(self.state.lock().unwrap())
86    }
87
88    /// Get a write lock using the given state lock.
89    ///
90    /// WARNING: The lock MUST be from self.state!!
91    fn write_from(&self, mut state_lock: MutexGuard<State>) {
92        // First wait for any other writers to unlock.
93        while state_lock.is_writer_active() {
94            state_lock = self.both.wait(state_lock).unwrap();
95        }
96
97        // At this point there must be no writers, but there may be readers.
98        //
99        // We set the writer-active flag so that readers which try to
100        // acquire the lock from here on out will be queued after us, to
101        // prevent starvation.
102        state_lock.set_writer_active();
103
104        // Now wait for all readers to exit.
105        //
106        // This will happen eventually since new readers are waiting on
107        // us because we set the writer-active flag.
108        while state_lock.readers() != 0 {
109            state_lock = self.readers.wait(state_lock).unwrap();
110        }
111
112        // At this point there should be one writer (us) and no readers.
113        debug_assert!(state_lock.is_writer_active() && state_lock.readers() == 0,
114                      "State not empty on write lock! State = {:?}", *state_lock);
115    }
116
117    /// Attempt to acquire an exclusive write lock without blocking.
118    ///
119    /// Returns true if we succeeded and false if acquiring the write lock would
120    /// require blocking.
121    pub fn try_write(&self) -> bool {
122        let mut state_lock = self.state.lock().unwrap();
123
124        // If there are no readers or writers we can just take the lock.
125        if !state_lock.is_writer_active() && state_lock.readers() == 0 {
126            state_lock.set_writer_active();
127
128            // Success!
129            true
130        } else {
131            false // We would have to block
132        }
133    }
134
135    /// Unlock a previously acquired read lock.
136    ///
137    /// Behavior is unspecified (but not undefined) if `unlock_read` is called
138    /// without a previous accompanying `read`.
139    #[inline]
140    pub fn unlock_read(&self) {
141        let _ = self.unlock_read_to();
142    }
143
144    fn unlock_read_to(&self) -> MutexGuard<State> {
145        let mut state_lock = self.state.lock().unwrap();
146
147        // First decrement the reader count.
148        state_lock.remove_reader();
149
150        // Now check if there is a writer waiting and
151        // we are the last reader.
152        if state_lock.is_writer_active() {
153            if state_lock.readers() == 0 {
154                // Wake up the waiting writer.
155                self.readers.notify_one();
156            }
157        // Check if we where at the max number of readers.
158        } else if state_lock.near_max_readers() {
159            // Wake up a reader to replace us.
160            self.both.notify_one()
161        }
162
163        // Return the lock for potential further use.
164        state_lock
165    }
166
167    /// Unlock a previously acquired write lock.
168    ///
169    /// Behavior is unspecified (but not undefined) if `unlock_write` is called
170    /// without a previous accompanying `write`.
171    #[inline]
172    pub fn unlock_write(&self) {
173        let _ = self.unlock_write_to();
174    }
175
176    #[inline]
177    fn unlock_write_to(&self) -> MutexGuard<State> {
178        let mut state_lock = self.state.lock().unwrap();
179
180        // Writer locks are exclusive so we know we can just
181        // set the state to empty.
182        *state_lock = State::new();
183
184        // Wake any pending readers or writers.
185        self.both.notify_all();
186
187        state_lock
188    }
189
190    /// Wait on the given condition variable, resuming with a write lock.
191    ///
192    /// Behavior is unspecified if there was no previous accompanying `read`.
193    #[inline]
194    pub fn wait_from_read_to_write(&self, cond: &Condvar) {
195        let state_lock = self.unlock_read_to();
196        let state_lock = cond.wait(state_lock).unwrap();
197        self.write_from(state_lock);
198    }
199
200    /// Wait on the given condition variable, resuming with another read lock.
201    ///
202    /// Behavior is unspecified if there was no previous accompanying `read`.
203    #[inline]
204    pub fn wait_from_read_to_read(&self, cond: &Condvar) {
205        let state_lock = self.unlock_read_to();
206        let state_lock = cond.wait(state_lock).unwrap();
207        self.read_from(state_lock);
208    }
209
210    /// Wait on the given condition variable, resuming with a read lock.
211    ///
212    /// Behavior is unspecified if there was no previous accompanying `write`.
213    #[inline]
214    pub fn wait_from_write_to_read(&self, cond: &Condvar) {
215        let state_lock = self.unlock_write_to();
216        let state_lock = cond.wait(state_lock).unwrap();
217        self.read_from(state_lock);
218    }
219
220    /// Wait on the given condition variable, resuming with another write lock.
221    ///
222    /// Behavior is unspecified if there was no previous accompanying `write`.
223    #[inline]
224    pub fn wait_from_write_to_write(&self, cond: &Condvar) {
225        let state_lock = self.unlock_write_to();
226        let state_lock = cond.wait(state_lock).unwrap();
227        self.write_from(state_lock);
228    }
229}
230
231/// Internal State of the SharedMutex.
232///
233/// The high bit indicates if a writer is active.
234///
235/// The lower bits are used to count the number of readers.
236#[derive(Debug)]
237struct State(usize);
238
239#[cfg(target_pointer_width = "64")]
240const USIZE_BITS: u8 = 64;
241
242#[cfg(target_pointer_width = "32")]
243const USIZE_BITS: u8 = 32;
244
245// Only the high bit is set.
246//
247// We can mask the State with this to see if the
248// high bit is set, which would indicate a writer
249// is active.
250const WRITER_ACTIVE: usize = 1 << USIZE_BITS - 1;
251
252// All the low bits are set, the high bit is not set.
253//
254// We can mask the State with this to see how many
255// readers there are.
256//
257// Also the maximum number of readers.
258const READERS_MASK: usize = !WRITER_ACTIVE;
259
260impl State {
261    #[inline]
262    fn new() -> Self { State(0) }
263
264    #[inline]
265    fn is_writer_active(&self) -> bool { self.0 & WRITER_ACTIVE != 0 }
266
267    #[inline]
268    fn set_writer_active(&mut self) { self.0 |= WRITER_ACTIVE }
269
270    #[inline]
271    fn readers(&self) -> usize { self.0 & READERS_MASK }
272
273    #[inline]
274    fn has_max_readers(&self) -> bool { self.readers() == READERS_MASK }
275
276    #[inline]
277    fn near_max_readers(&self) -> bool { self.readers() == READERS_MASK - 1 }
278
279    #[inline]
280    fn add_reader(&mut self) { self.0 += 1 }
281
282    #[inline]
283    fn remove_reader(&mut self) { self.0 -= 1 }
284}
285
286#[cfg(test)]
287mod test {
288    use raw::RawSharedMutex;
289
290    #[test]
291    fn test_raw_is() {
292        let mutex1 = RawSharedMutex::new();
293        let mutex2 = RawSharedMutex::new();
294
295        assert!(mutex1.is(&mutex1));
296        assert!(!mutex1.is(&mutex2));
297    }
298}
299