1
//! Authors: Maurice Laveaux, Flip van Spaendonck and Jan Friso Groote
2

            
3
use std::cell::Cell;
4
use std::error::Error;
5
use std::ops::Deref;
6
use std::ops::DerefMut;
7

            
8
use crate::BfSharedMutex;
9
use crate::BfSharedMutexReadGuard;
10
use crate::BfSharedMutexWriteGuard;
11

            
12
/// An extension of the [BfSharedMutex] that allows recursive read locking without deadlocks.
13
///
14
/// The recursion depth and call counters are stored in [`Cell`]s, so a `RecursiveLock` is
15
/// `!Sync` and has no `Clone`. To share the underlying data across threads, give each thread
16
/// its own `RecursiveLock` over a clone of the same mutex via
17
/// [`RecursiveLock::from_mutex`]`(shared.clone())`; the depth tracking is then per thread, as
18
/// the protocol requires. The call counters are likewise per instance, not global.
19
pub struct RecursiveLock<T> {
20
    inner: BfSharedMutex<T>,
21

            
22
    /// The number of times the current thread has read locked the mutex.
23
    recursive_depth: Cell<usize>,
24

            
25
    /// The number of calls to the write() method.
26
    write_calls: Cell<usize>,
27

            
28
    /// The number of calls to the read_recursive() method.
29
    read_recursive_calls: Cell<usize>,
30
}
31

            
32
impl<T> RecursiveLock<T> {
33
    /// Creates a new `RecursiveLock` with the given data.
34
6
    pub fn new(data: T) -> Self {
35
6
        RecursiveLock {
36
6
            inner: BfSharedMutex::new(data),
37
6
            recursive_depth: Cell::new(0),
38
6
            write_calls: Cell::new(0),
39
6
            read_recursive_calls: Cell::new(0),
40
6
        }
41
6
    }
42

            
43
    /// Creates a new `RecursiveLock` from an existing `BfSharedMutex`.
44
1769
    pub fn from_mutex(mutex: BfSharedMutex<T>) -> Self {
45
1769
        RecursiveLock {
46
1769
            inner: mutex,
47
1769
            recursive_depth: Cell::new(0),
48
1769
            write_calls: Cell::new(0),
49
1769
            read_recursive_calls: Cell::new(0),
50
1769
        }
51
1769
    }
52

            
53
    delegate::delegate! {
54
        to self.inner {
55
            #[cfg(not(loom))]
56
            pub fn data_ptr(&self) -> *const T;
57
            #[cfg(loom)]
58
            pub fn data_ptr(&self) -> loom::cell::ConstPtr<T>;
59
1318419
            pub fn is_locked(&self) -> bool;
60
            pub fn is_locked_exclusive(&self) -> bool;
61
        }
62
    }
63

            
64
    /// Acquires a write lock on the mutex.
65
    ///
66
    /// # Panics
67
    ///
68
    /// Panics when called inside a read or write section. In that case the underlying mutex
69
    /// would not wait for this thread's own lock, handing out `&mut T` while a `&T` or another
70
    /// `&mut T` is live.
71
3613
    pub fn write(&self) -> Result<RecursiveLockWriteGuard<'_, T>, Box<dyn Error + '_>> {
72
3613
        assert!(
73
3613
            self.recursive_depth.get() == 0,
74
            "Cannot call write() inside an existing read or write section"
75
        );
76
        // Acquire the underlying lock before touching any bookkeeping, so a
77
        // failed acquisition leaves the recursive state untouched.
78
3613
        let guard = self.inner.write()?;
79
3613
        self.write_calls.set(self.write_calls.get() + 1);
80
3613
        self.recursive_depth.set(1);
81
3613
        Ok(RecursiveLockWriteGuard { mutex: self, guard })
82
3613
    }
83

            
84
    /// Acquires a write lock on the mutex without blocking.
85
    ///
86
    /// # Panics
87
    ///
88
    /// Panics when called inside a read or write section. In that case the underlying mutex
89
    /// would not wait for this thread's own lock, handing out `&mut T` while a `&T` or another
90
    /// `&mut T` is live.
91
558159
    pub fn try_write(&self) -> Result<Option<RecursiveLockWriteGuard<'_, T>>, Box<dyn Error + '_>> {
92
558159
        assert!(
93
558159
            self.recursive_depth.get() == 0,
94
            "Cannot call try_write() inside an existing read or write section"
95
        );
96
        // Acquire the underlying lock before touching any bookkeeping, so a
97
        // failed acquisition leaves the recursive state untouched.
98
558159
        let guard = self.inner.try_write()?;
99

            
100
558159
        self.write_calls.set(self.write_calls.get() + 1);
101

            
102
558159
        if let Some(guard) = guard {
103
558159
            self.recursive_depth.set(1);
104
558159
            Ok(Some(RecursiveLockWriteGuard { mutex: self, guard }))
105
        } else {
106
            Ok(None)
107
        }
108
558159
    }
109

            
110
    /// Acquires a read lock on the mutex.
111
    ///
112
    /// # Panics
113
    ///
114
    /// Panics when called inside a read or write section; the raw read lock is not reentrant.
115
    /// Use [`RecursiveLock::read_recursive`] instead.
116
2
    pub fn read(&self) -> Result<BfSharedMutexReadGuard<'_, T>, Box<dyn Error + '_>> {
117
2
        assert!(
118
2
            self.recursive_depth.get() == 0,
119
            "Cannot call read() inside an existing read or write section"
120
        );
121
2
        self.inner.read()
122
2
    }
123

            
124
    /// Acquires a read lock on the mutex, allowing for recursive read locking.
125
    ///
126
    /// May also be called inside a write section: the returned guard then borrows the write
127
    /// lock instead of acquiring the underlying mutex. While such a guard is alive, mutating
128
    /// through the [`RecursiveLockWriteGuard`] panics.
129
3447320666
    pub fn read_recursive<'a>(&'a self) -> Result<RecursiveLockReadGuard<'a, T>, Box<dyn Error + 'a>> {
130
3447320666
        if self.recursive_depth.get() == 0 {
131
            // Not yet holding a read lock: acquire the shared protocol lock without
132
            // materialising a guard, so the busy flag stays set until our own guard
133
            // releases it (via `create_read_guard_unchecked` on drop). The acquisition
134
            // happens before the bookkeeping is updated, so a failed acquisition leaves
135
            // the recursive state untouched.
136
2257414318
            self.inner.acquire_shared()?;
137
2257414318
            self.recursive_depth.set(1);
138
1189906348
        } else {
139
1189906348
            // Already holding a read lock, so just record the extra level.
140
1189906348
            self.recursive_depth.set(self.recursive_depth.get() + 1);
141
1189906348
        }
142
3447320666
        self.read_recursive_calls.set(self.read_recursive_calls.get() + 1);
143
3447320666
        Ok(RecursiveLockReadGuard {
144
3447320666
            mutex: self,
145
3447320666
            #[cfg(loom)]
146
3447320666
            ptr: self.inner.data_ptr(),
147
3447320666
        })
148
3447320666
    }
149

            
150
    /// Returns the number of times `write()` has been called.
151
9
    pub fn write_call_count(&self) -> usize {
152
9
        self.write_calls.get()
153
9
    }
154

            
155
    /// Returns the number of times `read_recursive()` has been called.
156
11
    pub fn read_recursive_call_count(&self) -> usize {
157
11
        self.read_recursive_calls.get()
158
11
    }
159
}
160

            
161
#[must_use = "Dropping the guard unlocks the recursive lock immediately"]
162
pub struct RecursiveLockReadGuard<'a, T> {
163
    mutex: &'a RecursiveLock<T>,
164

            
165
    #[cfg(loom)]
166
    ptr: loom::cell::ConstPtr<T>,
167
}
168

            
169
impl<T> RecursiveLockReadGuard<'_, T> {
170
    /// Returns the read depth of the recursive lock.
171
2182036429
    pub fn read_depth(&self) -> usize {
172
2182036429
        self.mutex.recursive_depth.get()
173
2182036429
    }
174
}
175

            
176
/// Allow dereferences the underlying object.
177
impl<T> Deref for RecursiveLockReadGuard<'_, T> {
178
    type Target = T;
179

            
180
131036503
    fn deref(&self) -> &Self::Target {
181
        // SAFETY: This guard keeps the read lock (or the enclosing write lock) held, so only
182
        // shared access is handed out and the data pointer (an `UnsafeCell::get`) is non-null.
183
        #[cfg(not(loom))]
184
        unsafe {
185
131036503
            self.mutex.inner.data_ptr().as_ref().unwrap_unchecked()
186
        }
187

            
188
        #[cfg(loom)]
189
        unsafe {
190
            self.ptr.deref()
191
        }
192
131036503
    }
193
}
194

            
195
impl<T> Drop for RecursiveLockReadGuard<'_, T> {
196
3447320666
    fn drop(&mut self) {
197
3447320666
        self.mutex.recursive_depth.set(self.mutex.recursive_depth.get() - 1);
198
3447320666
        if self.mutex.recursive_depth.get() == 0 {
199
            // SAFETY: The depth reached zero, so the outermost `read_recursive` forgot a real read
200
            // guard that still holds this thread's `busy` flag. Reconstructing and immediately
201
            // dropping a guard releases that flag exactly once, matching the forgotten guard.
202
2257414318
            unsafe {
203
2257414318
                let _ = self.mutex.inner.create_read_guard_unchecked();
204
2257414318
            }
205
1189906348
        }
206
3447320666
    }
207
}
208

            
209
#[must_use = "Dropping the guard unlocks the recursive lock immediately"]
210
pub struct RecursiveLockWriteGuard<'a, T> {
211
    mutex: &'a RecursiveLock<T>,
212

            
213
    guard: BfSharedMutexWriteGuard<'a, T>,
214
}
215

            
216
/// Allow dereferences the underlying object.
217
impl<T> Deref for RecursiveLockWriteGuard<'_, T> {
218
    type Target = T;
219

            
220
5306
    fn deref(&self) -> &Self::Target {
221
        // We hold the write guard, so immutable access is safe; defer to it rather than taking a
222
        // second loom borrow of the cell, which would conflict with the guard's mutable borrow.
223
5306
        self.guard.deref()
224
5306
    }
225
}
226

            
227
/// Allow dereferences the underlying object.
228
impl<T> DerefMut for RecursiveLockWriteGuard<'_, T> {
229
    /// # Panics
230
    ///
231
    /// Panics while a recursive read guard taken inside this write section is alive. Such a
232
    /// guard hands out `&T` derived from the data pointer, invisible to the borrow checker,
233
    /// so a `&mut T` would alias it.
234
561767
    fn deref_mut(&mut self) -> &mut Self::Target {
235
561767
        assert!(
236
561767
            self.mutex.recursive_depth.get() == 1,
237
            "Cannot mutate through RecursiveLockWriteGuard while recursive read guards from its write section are alive"
238
        );
239
        // We hold the write guard exclusively and no recursive read guards exist, so mutable
240
        // access is safe.
241
561767
        self.guard.deref_mut()
242
561767
    }
243
}
244

            
245
impl<T> Drop for RecursiveLockWriteGuard<'_, T> {
246
561771
    fn drop(&mut self) {
247
        // Read guards taken with `read_recursive()` inside this write section borrow the write
248
        // lock: once this guard drops, the underlying mutex is released and their `&T` would be
249
        // unprotected. Panic instead of silently allowing that use-after-unlock.
250
561771
        assert!(
251
561771
            self.mutex.recursive_depth.get() == 1,
252
            "RecursiveLockWriteGuard dropped while recursive read guards from its write section are still alive"
253
        );
254
561771
        self.mutex.recursive_depth.set(0);
255
561771
    }
256
}
257

            
258
#[cfg(test)]
259
mod tests {
260
    use crate::BfSharedMutex;
261
    use crate::RecursiveLock;
262

            
263
    #[test]
264
1
    fn test_from_mutex() {
265
1
        let mutex = BfSharedMutex::new(100);
266
1
        let lock = RecursiveLock::from_mutex(mutex);
267
1
        assert_eq!(*lock.read().unwrap(), 100);
268
1
    }
269

            
270
    #[test]
271
1
    fn test_single_recursive_read() {
272
1
        let lock = RecursiveLock::new(42);
273
1
        let guard = lock.read_recursive().unwrap();
274
1
        assert_eq!(*guard, 42);
275
1
        assert_eq!(lock.recursive_depth.get(), 1);
276
1
    }
277

            
278
    #[test]
279
1
    fn test_nested_recursive_reads() {
280
1
        let lock = RecursiveLock::new(42);
281

            
282
1
        let guard1 = lock.read_recursive().unwrap();
283
1
        assert_eq!(*guard1, 42);
284
1
        assert_eq!(lock.recursive_depth.get(), 1);
285

            
286
1
        let guard2 = lock.read_recursive().unwrap();
287
1
        assert_eq!(*guard2, 42);
288
1
        assert_eq!(lock.recursive_depth.get(), 2);
289

            
290
1
        let guard3 = lock.read_recursive().unwrap();
291
1
        assert_eq!(*guard3, 42);
292
1
        assert_eq!(lock.recursive_depth.get(), 3);
293

            
294
1
        drop(guard3);
295
1
        assert_eq!(lock.recursive_depth.get(), 2);
296

            
297
1
        drop(guard2);
298
1
        assert_eq!(lock.recursive_depth.get(), 1);
299

            
300
1
        drop(guard1);
301
1
        assert_eq!(lock.recursive_depth.get(), 0);
302
1
    }
303

            
304
    #[test]
305
1
    fn test_read_recursive_inside_write() {
306
1
        let lock = RecursiveLock::new(42);
307
1
        let mut write = lock.write().unwrap();
308
1
        *write += 1;
309

            
310
        // Piggybacks on the write lock instead of acquiring the underlying mutex.
311
1
        let read = lock.read_recursive().unwrap();
312
1
        assert_eq!(*read, 43);
313
1
        assert_eq!(read.read_depth(), 2);
314
1
        drop(read);
315

            
316
        // Mutation is allowed again once the read guard is gone.
317
1
        *write += 1;
318
1
        assert_eq!(*write, 44);
319
1
        drop(write);
320

            
321
1
        assert_eq!(*lock.read().unwrap(), 44);
322
1
    }
323

            
324
    #[test]
325
1
    fn test_write_call_counter() {
326
1
        let lock = RecursiveLock::new(42);
327

            
328
        // Initially, the counter should be 0
329
1
        assert_eq!(lock.write_call_count(), 0);
330

            
331
        // After one write call, counter should be 1
332
        {
333
1
            let _guard = lock.write().unwrap();
334
1
            assert_eq!(lock.write_call_count(), 1);
335
        }
336

            
337
        // After another write call, counter should be 2
338
        {
339
1
            let _guard = lock.write().unwrap();
340
1
            assert_eq!(lock.write_call_count(), 2);
341
        }
342

            
343
        // Counter should remain 2
344
1
        assert_eq!(lock.write_call_count(), 2);
345
1
    }
346

            
347
    #[test]
348
1
    fn test_read_recursive_call_counter() {
349
1
        let lock = RecursiveLock::new(42);
350

            
351
        // Initially, the counter should be 0
352
1
        assert_eq!(lock.read_recursive_call_count(), 0);
353

            
354
        // After one read_recursive call, counter should be 1
355
        {
356
1
            let _guard = lock.read_recursive().unwrap();
357
1
            assert_eq!(lock.read_recursive_call_count(), 1);
358
        }
359

            
360
        // After another read_recursive call, counter should be 2
361
        {
362
1
            let _guard = lock.read_recursive().unwrap();
363
1
            assert_eq!(lock.read_recursive_call_count(), 2);
364
        }
365

            
366
        // Test nested recursive reads increment the counter
367
        {
368
1
            let _guard1 = lock.read_recursive().unwrap();
369
1
            assert_eq!(lock.read_recursive_call_count(), 3);
370

            
371
1
            let _guard2 = lock.read_recursive().unwrap();
372
1
            assert_eq!(lock.read_recursive_call_count(), 4);
373
        }
374

            
375
        // Counter should remain 4
376
1
        assert_eq!(lock.read_recursive_call_count(), 4);
377
1
    }
378

            
379
    #[test]
380
    #[cfg(loom)]
381
    fn test_loom_recursive_lock() {
382
        let mut builder = loom::model::Builder::new();
383
        // Mirrors the bound used for the underlying busy-forbidden mutex.
384
        builder.preemption_bound = Some(2);
385

            
386
        builder.check(|| {
387
            let mutex = BfSharedMutex::new(0usize);
388

            
389
            let threads: Vec<_> = (0..2)
390
                .map(|_| {
391
                    let mutex = mutex.clone();
392
                    loom::thread::spawn(move || {
393
                        // `RecursiveLock` is !Sync, so each thread wraps its own clone of the
394
                        // shared mutex; the recursion depth is then tracked per thread.
395
                        let lock = RecursiveLock::from_mutex(mutex);
396

            
397
                        // Nested recursive reads must observe a single consistent value and
398
                        // release the underlying read lock exactly once when the outermost
399
                        // guard drops.
400
                        {
401
                            let outer = lock.read_recursive().unwrap();
402
                            let inner = lock.read_recursive().unwrap();
403
                            assert_eq!(*outer, *inner);
404
                            assert_eq!(inner.read_depth(), 2);
405
                        }
406

            
407
                        // Exclusive access through the recursive write path.
408
                        *lock.write().unwrap() += 1;
409
                    })
410
                })
411
                .collect();
412

            
413
            for th in threads {
414
                th.join().unwrap();
415
            }
416
        });
417
    }
418

            
419
    #[test]
420
1
    fn test_both_counters() {
421
1
        let lock = RecursiveLock::new(42);
422

            
423
        // Initially, both counters should be 0
424
1
        assert_eq!(lock.write_call_count(), 0);
425
1
        assert_eq!(lock.read_recursive_call_count(), 0);
426

            
427
        // Call write and check counters
428
        {
429
1
            let _guard = lock.write().unwrap();
430
1
            assert_eq!(lock.write_call_count(), 1);
431
1
            assert_eq!(lock.read_recursive_call_count(), 0);
432
        }
433

            
434
        // Call read_recursive and check counters
435
        {
436
1
            let _guard = lock.read_recursive().unwrap();
437
1
            assert_eq!(lock.write_call_count(), 1);
438
1
            assert_eq!(lock.read_recursive_call_count(), 1);
439
        }
440

            
441
        // Call write again
442
        {
443
1
            let _guard = lock.write().unwrap();
444
1
            assert_eq!(lock.write_call_count(), 2);
445
1
            assert_eq!(lock.read_recursive_call_count(), 1);
446
        }
447

            
448
        // Call read_recursive multiple times
449
        {
450
1
            let _guard1 = lock.read_recursive().unwrap();
451
1
            let _guard2 = lock.read_recursive().unwrap();
452
1
            assert_eq!(lock.write_call_count(), 2);
453
1
            assert_eq!(lock.read_recursive_call_count(), 3);
454
        }
455
1
    }
456
}