1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2020 The ChromiumOS Authors 2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be 3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file. 4*bb4ee6a4SAndroid Build Coastguard Worker 5*bb4ee6a4SAndroid Build Coastguard Worker use std::cell::UnsafeCell; 6*bb4ee6a4SAndroid Build Coastguard Worker use std::hint; 7*bb4ee6a4SAndroid Build Coastguard Worker use std::ops::Deref; 8*bb4ee6a4SAndroid Build Coastguard Worker use std::ops::DerefMut; 9*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::atomic::AtomicBool; 10*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::atomic::Ordering; 11*bb4ee6a4SAndroid Build Coastguard Worker 12*bb4ee6a4SAndroid Build Coastguard Worker const UNLOCKED: bool = false; 13*bb4ee6a4SAndroid Build Coastguard Worker const LOCKED: bool = true; 14*bb4ee6a4SAndroid Build Coastguard Worker 15*bb4ee6a4SAndroid Build Coastguard Worker /// A primitive that provides safe, mutable access to a shared resource. 16*bb4ee6a4SAndroid Build Coastguard Worker /// 17*bb4ee6a4SAndroid Build Coastguard Worker /// Unlike `Mutex`, a `SpinLock` will not voluntarily yield its CPU time until the resource is 18*bb4ee6a4SAndroid Build Coastguard Worker /// available and will instead keep spinning until the resource is acquired. For the vast majority 19*bb4ee6a4SAndroid Build Coastguard Worker /// of cases, `Mutex` is a better choice than `SpinLock`. If a `SpinLock` must be used then users 20*bb4ee6a4SAndroid Build Coastguard Worker /// should try to do as little work as possible while holding the `SpinLock` and avoid any sort of 21*bb4ee6a4SAndroid Build Coastguard Worker /// blocking at all costs as it can severely penalize performance. 22*bb4ee6a4SAndroid Build Coastguard Worker /// 23*bb4ee6a4SAndroid Build Coastguard Worker /// # Poisoning 24*bb4ee6a4SAndroid Build Coastguard Worker /// 25*bb4ee6a4SAndroid Build Coastguard Worker /// This `SpinLock` does not implement lock poisoning so it is possible for threads to access 26*bb4ee6a4SAndroid Build Coastguard Worker /// poisoned data if a thread panics while holding the lock. If lock poisoning is needed, it can be 27*bb4ee6a4SAndroid Build Coastguard Worker /// implemented by wrapping the `SpinLock` in a new type that implements poisoning. See the 28*bb4ee6a4SAndroid Build Coastguard Worker /// implementation of `std::sync::Mutex` for an example of how to do this. 29*bb4ee6a4SAndroid Build Coastguard Worker #[repr(align(128))] 30*bb4ee6a4SAndroid Build Coastguard Worker pub struct SpinLock<T: ?Sized> { 31*bb4ee6a4SAndroid Build Coastguard Worker lock: AtomicBool, 32*bb4ee6a4SAndroid Build Coastguard Worker value: UnsafeCell<T>, 33*bb4ee6a4SAndroid Build Coastguard Worker } 34*bb4ee6a4SAndroid Build Coastguard Worker 35*bb4ee6a4SAndroid Build Coastguard Worker impl<T> SpinLock<T> { 36*bb4ee6a4SAndroid Build Coastguard Worker /// Creates a new, unlocked `SpinLock` that's ready for use. new(value: T) -> SpinLock<T>37*bb4ee6a4SAndroid Build Coastguard Worker pub fn new(value: T) -> SpinLock<T> { 38*bb4ee6a4SAndroid Build Coastguard Worker SpinLock { 39*bb4ee6a4SAndroid Build Coastguard Worker lock: AtomicBool::new(UNLOCKED), 40*bb4ee6a4SAndroid Build Coastguard Worker value: UnsafeCell::new(value), 41*bb4ee6a4SAndroid Build Coastguard Worker } 42*bb4ee6a4SAndroid Build Coastguard Worker } 43*bb4ee6a4SAndroid Build Coastguard Worker 44*bb4ee6a4SAndroid Build Coastguard Worker /// Consumes the `SpinLock` and returns the value guarded by it. This method doesn't perform any 45*bb4ee6a4SAndroid Build Coastguard Worker /// locking as the compiler guarantees that there are no references to `self`. into_inner(self) -> T46*bb4ee6a4SAndroid Build Coastguard Worker pub fn into_inner(self) -> T { 47*bb4ee6a4SAndroid Build Coastguard Worker // No need to take the lock because the compiler can statically guarantee 48*bb4ee6a4SAndroid Build Coastguard Worker // that there are no references to the SpinLock. 49*bb4ee6a4SAndroid Build Coastguard Worker self.value.into_inner() 50*bb4ee6a4SAndroid Build Coastguard Worker } 51*bb4ee6a4SAndroid Build Coastguard Worker } 52*bb4ee6a4SAndroid Build Coastguard Worker 53*bb4ee6a4SAndroid Build Coastguard Worker impl<T: ?Sized> SpinLock<T> { 54*bb4ee6a4SAndroid Build Coastguard Worker /// Acquires exclusive, mutable access to the resource protected by the `SpinLock`, blocking the 55*bb4ee6a4SAndroid Build Coastguard Worker /// current thread until it is able to do so. Upon returning, the current thread will be the 56*bb4ee6a4SAndroid Build Coastguard Worker /// only thread with access to the resource. The `SpinLock` will be released when the returned 57*bb4ee6a4SAndroid Build Coastguard Worker /// `SpinLockGuard` is dropped. Attempting to call `lock` while already holding the `SpinLock` 58*bb4ee6a4SAndroid Build Coastguard Worker /// will cause a deadlock. lock(&self) -> SpinLockGuard<T>59*bb4ee6a4SAndroid Build Coastguard Worker pub fn lock(&self) -> SpinLockGuard<T> { 60*bb4ee6a4SAndroid Build Coastguard Worker loop { 61*bb4ee6a4SAndroid Build Coastguard Worker let state = self.lock.load(Ordering::Relaxed); 62*bb4ee6a4SAndroid Build Coastguard Worker if state == UNLOCKED 63*bb4ee6a4SAndroid Build Coastguard Worker && self 64*bb4ee6a4SAndroid Build Coastguard Worker .lock 65*bb4ee6a4SAndroid Build Coastguard Worker .compare_exchange_weak(UNLOCKED, LOCKED, Ordering::Acquire, Ordering::Relaxed) 66*bb4ee6a4SAndroid Build Coastguard Worker .is_ok() 67*bb4ee6a4SAndroid Build Coastguard Worker { 68*bb4ee6a4SAndroid Build Coastguard Worker break; 69*bb4ee6a4SAndroid Build Coastguard Worker } 70*bb4ee6a4SAndroid Build Coastguard Worker hint::spin_loop(); 71*bb4ee6a4SAndroid Build Coastguard Worker } 72*bb4ee6a4SAndroid Build Coastguard Worker 73*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment 74*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)] 75*bb4ee6a4SAndroid Build Coastguard Worker SpinLockGuard { 76*bb4ee6a4SAndroid Build Coastguard Worker lock: self, 77*bb4ee6a4SAndroid Build Coastguard Worker value: unsafe { &mut *self.value.get() }, 78*bb4ee6a4SAndroid Build Coastguard Worker } 79*bb4ee6a4SAndroid Build Coastguard Worker } 80*bb4ee6a4SAndroid Build Coastguard Worker unlock(&self)81*bb4ee6a4SAndroid Build Coastguard Worker fn unlock(&self) { 82*bb4ee6a4SAndroid Build Coastguard Worker // Don't need to compare and swap because we exclusively hold the lock. 83*bb4ee6a4SAndroid Build Coastguard Worker self.lock.store(UNLOCKED, Ordering::Release); 84*bb4ee6a4SAndroid Build Coastguard Worker } 85*bb4ee6a4SAndroid Build Coastguard Worker 86*bb4ee6a4SAndroid Build Coastguard Worker /// Returns a mutable reference to the contained value. This method doesn't perform any locking 87*bb4ee6a4SAndroid Build Coastguard Worker /// as the compiler will statically guarantee that there are no other references to `self`. get_mut(&mut self) -> &mut T88*bb4ee6a4SAndroid Build Coastguard Worker pub fn get_mut(&mut self) -> &mut T { 89*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: 90*bb4ee6a4SAndroid Build Coastguard Worker // Safe because the compiler can statically guarantee that there are no other references to 91*bb4ee6a4SAndroid Build Coastguard Worker // `self`. This is also why we don't need to acquire the lock. 92*bb4ee6a4SAndroid Build Coastguard Worker unsafe { &mut *self.value.get() } 93*bb4ee6a4SAndroid Build Coastguard Worker } 94*bb4ee6a4SAndroid Build Coastguard Worker } 95*bb4ee6a4SAndroid Build Coastguard Worker 96*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment 97*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)] 98*bb4ee6a4SAndroid Build Coastguard Worker unsafe impl<T: ?Sized + Send> Send for SpinLock<T> {} 99*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment 100*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)] 101*bb4ee6a4SAndroid Build Coastguard Worker unsafe impl<T: ?Sized + Send> Sync for SpinLock<T> {} 102*bb4ee6a4SAndroid Build Coastguard Worker 103*bb4ee6a4SAndroid Build Coastguard Worker impl<T: Default> Default for SpinLock<T> { default() -> Self104*bb4ee6a4SAndroid Build Coastguard Worker fn default() -> Self { 105*bb4ee6a4SAndroid Build Coastguard Worker Self::new(Default::default()) 106*bb4ee6a4SAndroid Build Coastguard Worker } 107*bb4ee6a4SAndroid Build Coastguard Worker } 108*bb4ee6a4SAndroid Build Coastguard Worker 109*bb4ee6a4SAndroid Build Coastguard Worker impl<T> From<T> for SpinLock<T> { from(source: T) -> Self110*bb4ee6a4SAndroid Build Coastguard Worker fn from(source: T) -> Self { 111*bb4ee6a4SAndroid Build Coastguard Worker Self::new(source) 112*bb4ee6a4SAndroid Build Coastguard Worker } 113*bb4ee6a4SAndroid Build Coastguard Worker } 114*bb4ee6a4SAndroid Build Coastguard Worker 115*bb4ee6a4SAndroid Build Coastguard Worker /// An RAII implementation of a "scoped lock" for a `SpinLock`. When this structure is dropped, the 116*bb4ee6a4SAndroid Build Coastguard Worker /// lock will be released. The resource protected by the `SpinLock` can be accessed via the `Deref` 117*bb4ee6a4SAndroid Build Coastguard Worker /// and `DerefMut` implementations of this structure. 118*bb4ee6a4SAndroid Build Coastguard Worker pub struct SpinLockGuard<'a, T: 'a + ?Sized> { 119*bb4ee6a4SAndroid Build Coastguard Worker lock: &'a SpinLock<T>, 120*bb4ee6a4SAndroid Build Coastguard Worker value: &'a mut T, 121*bb4ee6a4SAndroid Build Coastguard Worker } 122*bb4ee6a4SAndroid Build Coastguard Worker 123*bb4ee6a4SAndroid Build Coastguard Worker impl<'a, T: ?Sized> Deref for SpinLockGuard<'a, T> { 124*bb4ee6a4SAndroid Build Coastguard Worker type Target = T; deref(&self) -> &T125*bb4ee6a4SAndroid Build Coastguard Worker fn deref(&self) -> &T { 126*bb4ee6a4SAndroid Build Coastguard Worker self.value 127*bb4ee6a4SAndroid Build Coastguard Worker } 128*bb4ee6a4SAndroid Build Coastguard Worker } 129*bb4ee6a4SAndroid Build Coastguard Worker 130*bb4ee6a4SAndroid Build Coastguard Worker impl<'a, T: ?Sized> DerefMut for SpinLockGuard<'a, T> { deref_mut(&mut self) -> &mut T131*bb4ee6a4SAndroid Build Coastguard Worker fn deref_mut(&mut self) -> &mut T { 132*bb4ee6a4SAndroid Build Coastguard Worker self.value 133*bb4ee6a4SAndroid Build Coastguard Worker } 134*bb4ee6a4SAndroid Build Coastguard Worker } 135*bb4ee6a4SAndroid Build Coastguard Worker 136*bb4ee6a4SAndroid Build Coastguard Worker impl<'a, T: ?Sized> Drop for SpinLockGuard<'a, T> { drop(&mut self)137*bb4ee6a4SAndroid Build Coastguard Worker fn drop(&mut self) { 138*bb4ee6a4SAndroid Build Coastguard Worker self.lock.unlock(); 139*bb4ee6a4SAndroid Build Coastguard Worker } 140*bb4ee6a4SAndroid Build Coastguard Worker } 141*bb4ee6a4SAndroid Build Coastguard Worker 142*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)] 143*bb4ee6a4SAndroid Build Coastguard Worker mod test { 144*bb4ee6a4SAndroid Build Coastguard Worker use std::mem; 145*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::atomic::AtomicUsize; 146*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::atomic::Ordering; 147*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::Arc; 148*bb4ee6a4SAndroid Build Coastguard Worker use std::thread; 149*bb4ee6a4SAndroid Build Coastguard Worker 150*bb4ee6a4SAndroid Build Coastguard Worker use super::*; 151*bb4ee6a4SAndroid Build Coastguard Worker 152*bb4ee6a4SAndroid Build Coastguard Worker #[derive(PartialEq, Eq, Debug)] 153*bb4ee6a4SAndroid Build Coastguard Worker struct NonCopy(u32); 154*bb4ee6a4SAndroid Build Coastguard Worker 155*bb4ee6a4SAndroid Build Coastguard Worker #[test] it_works()156*bb4ee6a4SAndroid Build Coastguard Worker fn it_works() { 157*bb4ee6a4SAndroid Build Coastguard Worker let sl = SpinLock::new(NonCopy(13)); 158*bb4ee6a4SAndroid Build Coastguard Worker 159*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(*sl.lock(), NonCopy(13)); 160*bb4ee6a4SAndroid Build Coastguard Worker } 161*bb4ee6a4SAndroid Build Coastguard Worker 162*bb4ee6a4SAndroid Build Coastguard Worker #[test] smoke()163*bb4ee6a4SAndroid Build Coastguard Worker fn smoke() { 164*bb4ee6a4SAndroid Build Coastguard Worker let sl = SpinLock::new(NonCopy(7)); 165*bb4ee6a4SAndroid Build Coastguard Worker 166*bb4ee6a4SAndroid Build Coastguard Worker mem::drop(sl.lock()); 167*bb4ee6a4SAndroid Build Coastguard Worker mem::drop(sl.lock()); 168*bb4ee6a4SAndroid Build Coastguard Worker } 169*bb4ee6a4SAndroid Build Coastguard Worker 170*bb4ee6a4SAndroid Build Coastguard Worker #[test] send()171*bb4ee6a4SAndroid Build Coastguard Worker fn send() { 172*bb4ee6a4SAndroid Build Coastguard Worker let sl = SpinLock::new(NonCopy(19)); 173*bb4ee6a4SAndroid Build Coastguard Worker 174*bb4ee6a4SAndroid Build Coastguard Worker thread::spawn(move || { 175*bb4ee6a4SAndroid Build Coastguard Worker let value = sl.lock(); 176*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(*value, NonCopy(19)); 177*bb4ee6a4SAndroid Build Coastguard Worker }) 178*bb4ee6a4SAndroid Build Coastguard Worker .join() 179*bb4ee6a4SAndroid Build Coastguard Worker .unwrap(); 180*bb4ee6a4SAndroid Build Coastguard Worker } 181*bb4ee6a4SAndroid Build Coastguard Worker 182*bb4ee6a4SAndroid Build Coastguard Worker #[test] high_contention()183*bb4ee6a4SAndroid Build Coastguard Worker fn high_contention() { 184*bb4ee6a4SAndroid Build Coastguard Worker const THREADS: usize = 23; 185*bb4ee6a4SAndroid Build Coastguard Worker const ITERATIONS: usize = 101; 186*bb4ee6a4SAndroid Build Coastguard Worker 187*bb4ee6a4SAndroid Build Coastguard Worker let mut threads = Vec::with_capacity(THREADS); 188*bb4ee6a4SAndroid Build Coastguard Worker 189*bb4ee6a4SAndroid Build Coastguard Worker let sl = Arc::new(SpinLock::new(0usize)); 190*bb4ee6a4SAndroid Build Coastguard Worker for _ in 0..THREADS { 191*bb4ee6a4SAndroid Build Coastguard Worker let sl2 = sl.clone(); 192*bb4ee6a4SAndroid Build Coastguard Worker threads.push(thread::spawn(move || { 193*bb4ee6a4SAndroid Build Coastguard Worker for _ in 0..ITERATIONS { 194*bb4ee6a4SAndroid Build Coastguard Worker *sl2.lock() += 1; 195*bb4ee6a4SAndroid Build Coastguard Worker } 196*bb4ee6a4SAndroid Build Coastguard Worker })); 197*bb4ee6a4SAndroid Build Coastguard Worker } 198*bb4ee6a4SAndroid Build Coastguard Worker 199*bb4ee6a4SAndroid Build Coastguard Worker for t in threads.into_iter() { 200*bb4ee6a4SAndroid Build Coastguard Worker t.join().unwrap(); 201*bb4ee6a4SAndroid Build Coastguard Worker } 202*bb4ee6a4SAndroid Build Coastguard Worker 203*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(*sl.lock(), THREADS * ITERATIONS); 204*bb4ee6a4SAndroid Build Coastguard Worker } 205*bb4ee6a4SAndroid Build Coastguard Worker 206*bb4ee6a4SAndroid Build Coastguard Worker #[test] get_mut()207*bb4ee6a4SAndroid Build Coastguard Worker fn get_mut() { 208*bb4ee6a4SAndroid Build Coastguard Worker let mut sl = SpinLock::new(NonCopy(13)); 209*bb4ee6a4SAndroid Build Coastguard Worker *sl.get_mut() = NonCopy(17); 210*bb4ee6a4SAndroid Build Coastguard Worker 211*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(sl.into_inner(), NonCopy(17)); 212*bb4ee6a4SAndroid Build Coastguard Worker } 213*bb4ee6a4SAndroid Build Coastguard Worker 214*bb4ee6a4SAndroid Build Coastguard Worker #[test] into_inner()215*bb4ee6a4SAndroid Build Coastguard Worker fn into_inner() { 216*bb4ee6a4SAndroid Build Coastguard Worker let sl = SpinLock::new(NonCopy(29)); 217*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(sl.into_inner(), NonCopy(29)); 218*bb4ee6a4SAndroid Build Coastguard Worker } 219*bb4ee6a4SAndroid Build Coastguard Worker 220*bb4ee6a4SAndroid Build Coastguard Worker #[test] into_inner_drop()221*bb4ee6a4SAndroid Build Coastguard Worker fn into_inner_drop() { 222*bb4ee6a4SAndroid Build Coastguard Worker struct NeedsDrop(Arc<AtomicUsize>); 223*bb4ee6a4SAndroid Build Coastguard Worker impl Drop for NeedsDrop { 224*bb4ee6a4SAndroid Build Coastguard Worker fn drop(&mut self) { 225*bb4ee6a4SAndroid Build Coastguard Worker self.0.fetch_add(1, Ordering::AcqRel); 226*bb4ee6a4SAndroid Build Coastguard Worker } 227*bb4ee6a4SAndroid Build Coastguard Worker } 228*bb4ee6a4SAndroid Build Coastguard Worker 229*bb4ee6a4SAndroid Build Coastguard Worker let value = Arc::new(AtomicUsize::new(0)); 230*bb4ee6a4SAndroid Build Coastguard Worker let needs_drop = SpinLock::new(NeedsDrop(value.clone())); 231*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(value.load(Ordering::Acquire), 0); 232*bb4ee6a4SAndroid Build Coastguard Worker 233*bb4ee6a4SAndroid Build Coastguard Worker { 234*bb4ee6a4SAndroid Build Coastguard Worker let inner = needs_drop.into_inner(); 235*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(inner.0.load(Ordering::Acquire), 0); 236*bb4ee6a4SAndroid Build Coastguard Worker } 237*bb4ee6a4SAndroid Build Coastguard Worker 238*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(value.load(Ordering::Acquire), 1); 239*bb4ee6a4SAndroid Build Coastguard Worker } 240*bb4ee6a4SAndroid Build Coastguard Worker 241*bb4ee6a4SAndroid Build Coastguard Worker #[test] arc_nested()242*bb4ee6a4SAndroid Build Coastguard Worker fn arc_nested() { 243*bb4ee6a4SAndroid Build Coastguard Worker // Tests nested sltexes and access to underlying data. 244*bb4ee6a4SAndroid Build Coastguard Worker let sl = SpinLock::new(1); 245*bb4ee6a4SAndroid Build Coastguard Worker let arc = Arc::new(SpinLock::new(sl)); 246*bb4ee6a4SAndroid Build Coastguard Worker thread::spawn(move || { 247*bb4ee6a4SAndroid Build Coastguard Worker let nested = arc.lock(); 248*bb4ee6a4SAndroid Build Coastguard Worker let lock2 = nested.lock(); 249*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(*lock2, 1); 250*bb4ee6a4SAndroid Build Coastguard Worker }) 251*bb4ee6a4SAndroid Build Coastguard Worker .join() 252*bb4ee6a4SAndroid Build Coastguard Worker .unwrap(); 253*bb4ee6a4SAndroid Build Coastguard Worker } 254*bb4ee6a4SAndroid Build Coastguard Worker 255*bb4ee6a4SAndroid Build Coastguard Worker #[test] arc_access_in_unwind()256*bb4ee6a4SAndroid Build Coastguard Worker fn arc_access_in_unwind() { 257*bb4ee6a4SAndroid Build Coastguard Worker let arc = Arc::new(SpinLock::new(1)); 258*bb4ee6a4SAndroid Build Coastguard Worker let arc2 = arc.clone(); 259*bb4ee6a4SAndroid Build Coastguard Worker thread::spawn(move || { 260*bb4ee6a4SAndroid Build Coastguard Worker struct Unwinder { 261*bb4ee6a4SAndroid Build Coastguard Worker i: Arc<SpinLock<i32>>, 262*bb4ee6a4SAndroid Build Coastguard Worker } 263*bb4ee6a4SAndroid Build Coastguard Worker impl Drop for Unwinder { 264*bb4ee6a4SAndroid Build Coastguard Worker fn drop(&mut self) { 265*bb4ee6a4SAndroid Build Coastguard Worker *self.i.lock() += 1; 266*bb4ee6a4SAndroid Build Coastguard Worker } 267*bb4ee6a4SAndroid Build Coastguard Worker } 268*bb4ee6a4SAndroid Build Coastguard Worker let _u = Unwinder { i: arc2 }; 269*bb4ee6a4SAndroid Build Coastguard Worker panic!(); 270*bb4ee6a4SAndroid Build Coastguard Worker }) 271*bb4ee6a4SAndroid Build Coastguard Worker .join() 272*bb4ee6a4SAndroid Build Coastguard Worker .expect_err("thread did not panic"); 273*bb4ee6a4SAndroid Build Coastguard Worker let lock = arc.lock(); 274*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(*lock, 2); 275*bb4ee6a4SAndroid Build Coastguard Worker } 276*bb4ee6a4SAndroid Build Coastguard Worker 277*bb4ee6a4SAndroid Build Coastguard Worker #[test] unsized_value()278*bb4ee6a4SAndroid Build Coastguard Worker fn unsized_value() { 279*bb4ee6a4SAndroid Build Coastguard Worker let sltex: &SpinLock<[i32]> = &SpinLock::new([1, 2, 3]); 280*bb4ee6a4SAndroid Build Coastguard Worker { 281*bb4ee6a4SAndroid Build Coastguard Worker let b = &mut *sltex.lock(); 282*bb4ee6a4SAndroid Build Coastguard Worker b[0] = 4; 283*bb4ee6a4SAndroid Build Coastguard Worker b[2] = 5; 284*bb4ee6a4SAndroid Build Coastguard Worker } 285*bb4ee6a4SAndroid Build Coastguard Worker let expected: &[i32] = &[4, 2, 5]; 286*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(&*sltex.lock(), expected); 287*bb4ee6a4SAndroid Build Coastguard Worker } 288*bb4ee6a4SAndroid Build Coastguard Worker } 289