xref: /aosp_15_r20/external/crosvm/cros_async/src/sync/spin.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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