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