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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
use std::cell::UnsafeCell;
use std::ops::{Deref, DerefMut};
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering::*;

/// a primitive for mutual exclusion that spins in a loop
pub struct SpinLock<T> {
    locked: AtomicBool,
    value: UnsafeCell<T>,
}

pub struct Guard<'a, T> {
    lock: &'a SpinLock<T>,
}

impl<T> SpinLock<T> {
    /// Creates a new spinlock.
    ///
    /// # Examples
    ///
    /// ```
    ///   use lib_wc::sync::SpinLock;
    ///
    ///   let spinlock = SpinLock::new(0);
    ///
    ///   {
    ///     let mut guard = spinlock.lock();
    ///     *guard += 1;
    ///   } // The guard is dropped here, unlocking the mutex
    ///
    ///   {
    ///     let mut guard = spinlock.lock();
    ///     *guard += 1;
    ///   } // The guard is dropped here, unlocking the mutex
    ///
    ///   assert_eq!(*spinlock.lock(), 2);
    /// ```
    pub fn new(value: T) -> Self {
        Self {
            locked: AtomicBool::new(false),
            value: UnsafeCell::new(value),
        }
    }

    /// Acquires a lock on the spinlock, spinning the current thread in a loop until it is able to do so.
    ///
    /// This function returns a `Guard` which will release the lock when dropped.
    ///
    /// # Examples
    /// ```
    ///   use lib_wc::sync::SpinLock;
    ///
    ///   let spinlock = SpinLock::new(0);
    ///
    ///   {
    ///     let mut guard = spinlock.lock();
    ///     *guard += 1;
    ///   } // The guard is dropped here, unlocking the mutex
    ///
    ///   {
    ///     let mut guard = spinlock.lock();
    ///     *guard += 1;
    ///   } // The guard is dropped here, unlocking the mutex
    ///
    ///   assert_eq!(*spinlock.lock(), 2);
    /// ```
    pub fn lock(&self) -> Guard<T> {
        while self.locked.swap(true, Acquire) {
            std::hint::spin_loop();
        }
        Guard { lock: self }
    }
}

// T doesn't need to be sync because only one thread will have access to it at a time
unsafe impl<T> Sync for SpinLock<T> where T: Send {}

impl<T> Deref for Guard<'_, T> {
    type Target = T;
    fn deref(&self) -> &Self::Target {
        // Safety: the existence of this guard guarantees
        // that we have exclusively locked the lock
        unsafe { &*self.lock.value.get() }
    }
}

impl<T> DerefMut for Guard<'_, T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        // Safety: the existence of this guard guarantees
        // that we have exclusively locked the lock
        unsafe { &mut *self.lock.value.get() }
    }
}

impl<T> Drop for Guard<'_, T> {
    fn drop(&mut self) {
        self.lock.locked.store(false, Release);
    }
}

#[cfg(test)]
mod tests {
    use crate::concurrent::sync::SpinLock;

    #[test]
    fn test_spinlock() {
        let x = SpinLock::new(Vec::new());

        std::thread::scope(|s| {
            s.spawn(|| x.lock().push(1));
            s.spawn(|| {
                let mut g = x.lock();
                g.push(2);
                g.push(2);
            });
        });
        let g = x.lock();
        assert!(g.as_slice() == [1, 2, 2] || g.as_slice() == [2, 2, 1]);
    }

    #[test]
    fn test_multiple_threads() {
        let x = SpinLock::new(Vec::new());

        std::thread::scope(|s| {
            s.spawn(|| x.lock().push(1));

            for _ in 0..100 {
                s.spawn(|| x.lock().push(1));
            }
        });

        assert_eq!(x.lock().len(), 101);
    }
}