diff options
| author | Vivian Lim <[email protected]> | 2021-02-06 22:11:59 -0800 |
|---|---|---|
| committer | Vivian Lim <[email protected]> | 2021-02-06 22:11:59 -0800 |
| commit | 64423f0e34cc4a7d78c15b345b3b8f58243d8286 (patch) | |
| tree | cc20e2e7f0fc35abf470e20e61d3d48f0d954f3b /ctr-std/src/sync/mutex.rs | |
| parent | Support libctru 2.0 (diff) | |
| download | ctru-rs-64423f0e34cc4a7d78c15b345b3b8f58243d8286.tar.xz ctru-rs-64423f0e34cc4a7d78c15b345b3b8f58243d8286.zip | |
Delete ctr-std to use my fork of the rust repo instead
Diffstat (limited to 'ctr-std/src/sync/mutex.rs')
| -rw-r--r-- | ctr-std/src/sync/mutex.rs | 716 |
1 files changed, 0 insertions, 716 deletions
diff --git a/ctr-std/src/sync/mutex.rs b/ctr-std/src/sync/mutex.rs deleted file mode 100644 index e5a4106..0000000 --- a/ctr-std/src/sync/mutex.rs +++ /dev/null @@ -1,716 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use cell::UnsafeCell; -use fmt; -use mem; -use ops::{Deref, DerefMut}; -use ptr; -use sys_common::mutex as sys; -use sys_common::poison::{self, TryLockError, TryLockResult, LockResult}; - -/// A mutual exclusion primitive useful for protecting shared data -/// -/// This mutex will block threads waiting for the lock to become available. The -/// mutex can also be statically initialized or created via a [`new`] -/// constructor. Each mutex has a type parameter which represents the data that -/// it is protecting. The data can only be accessed through the RAII guards -/// returned from [`lock`] and [`try_lock`], which guarantees that the data is only -/// ever accessed when the mutex is locked. -/// -/// # Poisoning -/// -/// The mutexes in this module implement a strategy called "poisoning" where a -/// mutex is considered poisoned whenever a thread panics while holding the -/// mutex. Once a mutex is poisoned, all other threads are unable to access the -/// data by default as it is likely tainted (some invariant is not being -/// upheld). -/// -/// For a mutex, this means that the [`lock`] and [`try_lock`] methods return a -/// [`Result`] which indicates whether a mutex has been poisoned or not. Most -/// usage of a mutex will simply [`unwrap()`] these results, propagating panics -/// among threads to ensure that a possibly invalid invariant is not witnessed. -/// -/// A poisoned mutex, however, does not prevent all access to the underlying -/// data. The [`PoisonError`] type has an [`into_inner`] method which will return -/// the guard that would have otherwise been returned on a successful lock. This -/// allows access to the data, despite the lock being poisoned. -/// -/// [`new`]: #method.new -/// [`lock`]: #method.lock -/// [`try_lock`]: #method.try_lock -/// [`Result`]: ../../std/result/enum.Result.html -/// [`unwrap()`]: ../../std/result/enum.Result.html#method.unwrap -/// [`PoisonError`]: ../../std/sync/struct.PoisonError.html -/// [`into_inner`]: ../../std/sync/struct.PoisonError.html#method.into_inner -/// -/// # Examples -/// -/// ``` -/// use std::sync::{Arc, Mutex}; -/// use std::thread; -/// use std::sync::mpsc::channel; -/// -/// const N: usize = 10; -/// -/// // Spawn a few threads to increment a shared variable (non-atomically), and -/// // let the main thread know once all increments are done. -/// // -/// // Here we're using an Arc to share memory among threads, and the data inside -/// // the Arc is protected with a mutex. -/// let data = Arc::new(Mutex::new(0)); -/// -/// let (tx, rx) = channel(); -/// for _ in 0..N { -/// let (data, tx) = (data.clone(), tx.clone()); -/// thread::spawn(move || { -/// // The shared state can only be accessed once the lock is held. -/// // Our non-atomic increment is safe because we're the only thread -/// // which can access the shared state when the lock is held. -/// // -/// // We unwrap() the return value to assert that we are not expecting -/// // threads to ever fail while holding the lock. -/// let mut data = data.lock().unwrap(); -/// *data += 1; -/// if *data == N { -/// tx.send(()).unwrap(); -/// } -/// // the lock is unlocked here when `data` goes out of scope. -/// }); -/// } -/// -/// rx.recv().unwrap(); -/// ``` -/// -/// To recover from a poisoned mutex: -/// -/// ``` -/// use std::sync::{Arc, Mutex}; -/// use std::thread; -/// -/// let lock = Arc::new(Mutex::new(0_u32)); -/// let lock2 = lock.clone(); -/// -/// let _ = thread::spawn(move || -> () { -/// // This thread will acquire the mutex first, unwrapping the result of -/// // `lock` because the lock has not been poisoned. -/// let _guard = lock2.lock().unwrap(); -/// -/// // This panic while holding the lock (`_guard` is in scope) will poison -/// // the mutex. -/// panic!(); -/// }).join(); -/// -/// // The lock is poisoned by this point, but the returned result can be -/// // pattern matched on to return the underlying guard on both branches. -/// let mut guard = match lock.lock() { -/// Ok(guard) => guard, -/// Err(poisoned) => poisoned.into_inner(), -/// }; -/// -/// *guard += 1; -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Mutex<T: ?Sized> { - // Note that this mutex is in a *box*, not inlined into the struct itself. - // Once a native mutex has been used once, its address can never change (it - // can't be moved). This mutex type can be safely moved at any time, so to - // ensure that the native mutex is used correctly we box the inner mutex to - // give it a constant address. - inner: Box<sys::Mutex>, - poison: poison::Flag, - data: UnsafeCell<T>, -} - -// these are the only places where `T: Send` matters; all other -// functionality works fine on a single thread. -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<T: ?Sized + Send> Send for Mutex<T> { } -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<T: ?Sized + Send> Sync for Mutex<T> { } - -/// An RAII implementation of a "scoped lock" of a mutex. When this structure is -/// dropped (falls out of scope), the lock will be unlocked. -/// -/// The data protected by the mutex can be accessed through this guard via its -/// [`Deref`] and [`DerefMut`] implementations. -/// -/// This structure is created by the [`lock`] and [`try_lock`] methods on -/// [`Mutex`]. -/// -/// [`Deref`]: ../../std/ops/trait.Deref.html -/// [`DerefMut`]: ../../std/ops/trait.DerefMut.html -/// [`lock`]: struct.Mutex.html#method.lock -/// [`try_lock`]: struct.Mutex.html#method.try_lock -/// [`Mutex`]: struct.Mutex.html -#[must_use = "if unused the Mutex will immediately unlock"] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct MutexGuard<'a, T: ?Sized + 'a> { - // funny underscores due to how Deref/DerefMut currently work (they - // disregard field privacy). - __lock: &'a Mutex<T>, - __poison: poison::Guard, -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: ?Sized> !Send for MutexGuard<'a, T> { } -#[stable(feature = "mutexguard", since = "1.19.0")] -unsafe impl<'a, T: ?Sized + Sync> Sync for MutexGuard<'a, T> { } - -impl<T> Mutex<T> { - /// Creates a new mutex in an unlocked state ready for use. - /// - /// # Examples - /// - /// ``` - /// use std::sync::Mutex; - /// - /// let mutex = Mutex::new(0); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn new(t: T) -> Mutex<T> { - let mut m = Mutex { - inner: box sys::Mutex::new(), - poison: poison::Flag::new(), - data: UnsafeCell::new(t), - }; - unsafe { - m.inner.init(); - } - m - } -} - -impl<T: ?Sized> Mutex<T> { - /// Acquires a mutex, blocking the current thread until it is able to do so. - /// - /// This function will block the local thread until it is available to acquire - /// the mutex. Upon returning, the thread is the only thread with the lock - /// held. An RAII guard is returned to allow scoped unlock of the lock. When - /// the guard goes out of scope, the mutex will be unlocked. - /// - /// The exact behavior on locking a mutex in the thread which already holds - /// the lock is left unspecified. However, this function will not return on - /// the second call (it might panic or deadlock, for example). - /// - /// # Errors - /// - /// If another user of this mutex panicked while holding the mutex, then - /// this call will return an error once the mutex is acquired. - /// - /// # Panics - /// - /// This function might panic when called if the lock is already held by - /// the current thread. - /// - /// # Examples - /// - /// ``` - /// use std::sync::{Arc, Mutex}; - /// use std::thread; - /// - /// let mutex = Arc::new(Mutex::new(0)); - /// let c_mutex = mutex.clone(); - /// - /// thread::spawn(move || { - /// *c_mutex.lock().unwrap() = 10; - /// }).join().expect("thread::spawn failed"); - /// assert_eq!(*mutex.lock().unwrap(), 10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn lock(&self) -> LockResult<MutexGuard<T>> { - unsafe { - self.inner.raw_lock(); - MutexGuard::new(self) - } - } - - /// Attempts to acquire this lock. - /// - /// If the lock could not be acquired at this time, then [`Err`] is returned. - /// Otherwise, an RAII guard is returned. The lock will be unlocked when the - /// guard is dropped. - /// - /// This function does not block. - /// - /// # Errors - /// - /// If another user of this mutex panicked while holding the mutex, then - /// this call will return failure if the mutex would otherwise be - /// acquired. - /// - /// [`Err`]: ../../std/result/enum.Result.html#variant.Err - /// - /// # Examples - /// - /// ``` - /// use std::sync::{Arc, Mutex}; - /// use std::thread; - /// - /// let mutex = Arc::new(Mutex::new(0)); - /// let c_mutex = mutex.clone(); - /// - /// thread::spawn(move || { - /// let mut lock = c_mutex.try_lock(); - /// if let Ok(ref mut mutex) = lock { - /// **mutex = 10; - /// } else { - /// println!("try_lock failed"); - /// } - /// }).join().expect("thread::spawn failed"); - /// assert_eq!(*mutex.lock().unwrap(), 10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn try_lock(&self) -> TryLockResult<MutexGuard<T>> { - unsafe { - if self.inner.try_lock() { - Ok(MutexGuard::new(self)?) - } else { - Err(TryLockError::WouldBlock) - } - } - } - - /// Determines whether the mutex is poisoned. - /// - /// If another thread is active, the mutex can still become poisoned at any - /// time. You should not trust a `false` value for program correctness - /// without additional synchronization. - /// - /// # Examples - /// - /// ``` - /// use std::sync::{Arc, Mutex}; - /// use std::thread; - /// - /// let mutex = Arc::new(Mutex::new(0)); - /// let c_mutex = mutex.clone(); - /// - /// let _ = thread::spawn(move || { - /// let _lock = c_mutex.lock().unwrap(); - /// panic!(); // the mutex gets poisoned - /// }).join(); - /// assert_eq!(mutex.is_poisoned(), true); - /// ``` - #[inline] - #[stable(feature = "sync_poison", since = "1.2.0")] - pub fn is_poisoned(&self) -> bool { - self.poison.get() - } - - /// Consumes this mutex, returning the underlying data. - /// - /// # Errors - /// - /// If another user of this mutex panicked while holding the mutex, then - /// this call will return an error instead. - /// - /// # Examples - /// - /// ``` - /// use std::sync::Mutex; - /// - /// let mutex = Mutex::new(0); - /// assert_eq!(mutex.into_inner().unwrap(), 0); - /// ``` - #[stable(feature = "mutex_into_inner", since = "1.6.0")] - pub fn into_inner(self) -> LockResult<T> where T: Sized { - // We know statically that there are no outstanding references to - // `self` so there's no need to lock the inner mutex. - // - // To get the inner value, we'd like to call `data.into_inner()`, - // but because `Mutex` impl-s `Drop`, we can't move out of it, so - // we'll have to destructure it manually instead. - unsafe { - // Like `let Mutex { inner, poison, data } = self`. - let (inner, poison, data) = { - let Mutex { ref inner, ref poison, ref data } = self; - (ptr::read(inner), ptr::read(poison), ptr::read(data)) - }; - mem::forget(self); - inner.destroy(); // Keep in sync with the `Drop` impl. - drop(inner); - - poison::map_result(poison.borrow(), |_| data.into_inner()) - } - } - - /// Returns a mutable reference to the underlying data. - /// - /// Since this call borrows the `Mutex` mutably, no actual locking needs to - /// take place---the mutable borrow statically guarantees no locks exist. - /// - /// # Errors - /// - /// If another user of this mutex panicked while holding the mutex, then - /// this call will return an error instead. - /// - /// # Examples - /// - /// ``` - /// use std::sync::Mutex; - /// - /// let mut mutex = Mutex::new(0); - /// *mutex.get_mut().unwrap() = 10; - /// assert_eq!(*mutex.lock().unwrap(), 10); - /// ``` - #[stable(feature = "mutex_get_mut", since = "1.6.0")] - pub fn get_mut(&mut self) -> LockResult<&mut T> { - // We know statically that there are no other references to `self`, so - // there's no need to lock the inner mutex. - let data = unsafe { &mut *self.data.get() }; - poison::map_result(self.poison.borrow(), |_| data ) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<#[may_dangle] T: ?Sized> Drop for Mutex<T> { - fn drop(&mut self) { - // This is actually safe b/c we know that there is no further usage of - // this mutex (it's up to the user to arrange for a mutex to get - // dropped, that's not our job) - // - // IMPORTANT: This code must be kept in sync with `Mutex::into_inner`. - unsafe { self.inner.destroy() } - } -} - -#[stable(feature = "mutex_from", since = "1.24.0")] -impl<T> From<T> for Mutex<T> { - /// Creates a new mutex in an unlocked state ready for use. - /// This is equivalent to [`Mutex::new`]. - /// - /// [`Mutex::new`]: #method.new - fn from(t: T) -> Self { - Mutex::new(t) - } -} - -#[stable(feature = "mutex_default", since = "1.10.0")] -impl<T: ?Sized + Default> Default for Mutex<T> { - /// Creates a `Mutex<T>`, with the `Default` value for T. - fn default() -> Mutex<T> { - Mutex::new(Default::default()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<T: ?Sized + fmt::Debug> fmt::Debug for Mutex<T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self.try_lock() { - Ok(guard) => f.debug_struct("Mutex").field("data", &&*guard).finish(), - Err(TryLockError::Poisoned(err)) => { - f.debug_struct("Mutex").field("data", &&**err.get_ref()).finish() - }, - Err(TryLockError::WouldBlock) => { - struct LockedPlaceholder; - impl fmt::Debug for LockedPlaceholder { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("<locked>") } - } - - f.debug_struct("Mutex").field("data", &LockedPlaceholder).finish() - } - } - } -} - -impl<'mutex, T: ?Sized> MutexGuard<'mutex, T> { - unsafe fn new(lock: &'mutex Mutex<T>) -> LockResult<MutexGuard<'mutex, T>> { - poison::map_result(lock.poison.borrow(), |guard| { - MutexGuard { - __lock: lock, - __poison: guard, - } - }) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'mutex, T: ?Sized> Deref for MutexGuard<'mutex, T> { - type Target = T; - - fn deref(&self) -> &T { - unsafe { &*self.__lock.data.get() } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'mutex, T: ?Sized> DerefMut for MutexGuard<'mutex, T> { - fn deref_mut(&mut self) -> &mut T { - unsafe { &mut *self.__lock.data.get() } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> { - #[inline] - fn drop(&mut self) { - unsafe { - self.__lock.poison.done(&self.__poison); - self.__lock.inner.raw_unlock(); - } - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl<'a, T: ?Sized + fmt::Debug> fmt::Debug for MutexGuard<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("MutexGuard") - .field("lock", &self.__lock) - .finish() - } -} - -#[stable(feature = "std_guard_impls", since = "1.20.0")] -impl<'a, T: ?Sized + fmt::Display> fmt::Display for MutexGuard<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - (**self).fmt(f) - } -} - -pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex { - &guard.__lock.inner -} - -pub fn guard_poison<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a poison::Flag { - &guard.__lock.poison -} - -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests { - use sync::mpsc::channel; - use sync::{Arc, Mutex, Condvar}; - use sync::atomic::{AtomicUsize, Ordering}; - use thread; - - struct Packet<T>(Arc<(Mutex<T>, Condvar)>); - - #[derive(Eq, PartialEq, Debug)] - struct NonCopy(i32); - - #[test] - fn smoke() { - let m = Mutex::new(()); - drop(m.lock().unwrap()); - drop(m.lock().unwrap()); - } - - #[test] - fn lots_and_lots() { - const J: u32 = 1000; - const K: u32 = 3; - - let m = Arc::new(Mutex::new(0)); - - fn inc(m: &Mutex<u32>) { - for _ in 0..J { - *m.lock().unwrap() += 1; - } - } - - let (tx, rx) = channel(); - for _ in 0..K { - let tx2 = tx.clone(); - let m2 = m.clone(); - thread::spawn(move|| { inc(&m2); tx2.send(()).unwrap(); }); - let tx2 = tx.clone(); - let m2 = m.clone(); - thread::spawn(move|| { inc(&m2); tx2.send(()).unwrap(); }); - } - - drop(tx); - for _ in 0..2 * K { - rx.recv().unwrap(); - } - assert_eq!(*m.lock().unwrap(), J * K * 2); - } - - #[test] - fn try_lock() { - let m = Mutex::new(()); - *m.try_lock().unwrap() = (); - } - - #[test] - fn test_into_inner() { - let m = Mutex::new(NonCopy(10)); - assert_eq!(m.into_inner().unwrap(), NonCopy(10)); - } - - #[test] - fn test_into_inner_drop() { - struct Foo(Arc<AtomicUsize>); - impl Drop for Foo { - fn drop(&mut self) { - self.0.fetch_add(1, Ordering::SeqCst); - } - } - let num_drops = Arc::new(AtomicUsize::new(0)); - let m = Mutex::new(Foo(num_drops.clone())); - assert_eq!(num_drops.load(Ordering::SeqCst), 0); - { - let _inner = m.into_inner().unwrap(); - assert_eq!(num_drops.load(Ordering::SeqCst), 0); - } - assert_eq!(num_drops.load(Ordering::SeqCst), 1); - } - - #[test] - fn test_into_inner_poison() { - let m = Arc::new(Mutex::new(NonCopy(10))); - let m2 = m.clone(); - let _ = thread::spawn(move || { - let _lock = m2.lock().unwrap(); - panic!("test panic in inner thread to poison mutex"); - }).join(); - - assert!(m.is_poisoned()); - match Arc::try_unwrap(m).unwrap().into_inner() { - Err(e) => assert_eq!(e.into_inner(), NonCopy(10)), - Ok(x) => panic!("into_inner of poisoned Mutex is Ok: {:?}", x), - } - } - - #[test] - fn test_get_mut() { - let mut m = Mutex::new(NonCopy(10)); - *m.get_mut().unwrap() = NonCopy(20); - assert_eq!(m.into_inner().unwrap(), NonCopy(20)); - } - - #[test] - fn test_get_mut_poison() { - let m = Arc::new(Mutex::new(NonCopy(10))); - let m2 = m.clone(); - let _ = thread::spawn(move || { - let _lock = m2.lock().unwrap(); - panic!("test panic in inner thread to poison mutex"); - }).join(); - - assert!(m.is_poisoned()); - match Arc::try_unwrap(m).unwrap().get_mut() { - Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)), - Ok(x) => panic!("get_mut of poisoned Mutex is Ok: {:?}", x), - } - } - - #[test] - fn test_mutex_arc_condvar() { - let packet = Packet(Arc::new((Mutex::new(false), Condvar::new()))); - let packet2 = Packet(packet.0.clone()); - let (tx, rx) = channel(); - let _t = thread::spawn(move|| { - // wait until parent gets in - rx.recv().unwrap(); - let &(ref lock, ref cvar) = &*packet2.0; - let mut lock = lock.lock().unwrap(); - *lock = true; - cvar.notify_one(); - }); - - let &(ref lock, ref cvar) = &*packet.0; - let mut lock = lock.lock().unwrap(); - tx.send(()).unwrap(); - assert!(!*lock); - while !*lock { - lock = cvar.wait(lock).unwrap(); - } - } - - #[test] - fn test_arc_condvar_poison() { - let packet = Packet(Arc::new((Mutex::new(1), Condvar::new()))); - let packet2 = Packet(packet.0.clone()); - let (tx, rx) = channel(); - - let _t = thread::spawn(move || -> () { - rx.recv().unwrap(); - let &(ref lock, ref cvar) = &*packet2.0; - let _g = lock.lock().unwrap(); - cvar.notify_one(); - // Parent should fail when it wakes up. - panic!(); - }); - - let &(ref lock, ref cvar) = &*packet.0; - let mut lock = lock.lock().unwrap(); - tx.send(()).unwrap(); - while *lock == 1 { - match cvar.wait(lock) { - Ok(l) => { - lock = l; - assert_eq!(*lock, 1); - } - Err(..) => break, - } - } - } - - #[test] - fn test_mutex_arc_poison() { - let arc = Arc::new(Mutex::new(1)); - assert!(!arc.is_poisoned()); - let arc2 = arc.clone(); - let _ = thread::spawn(move|| { - let lock = arc2.lock().unwrap(); - assert_eq!(*lock, 2); - }).join(); - assert!(arc.lock().is_err()); - assert!(arc.is_poisoned()); - } - - #[test] - fn test_mutex_arc_nested() { - // Tests nested mutexes and access - // to underlying data. - let arc = Arc::new(Mutex::new(1)); - let arc2 = Arc::new(Mutex::new(arc)); - let (tx, rx) = channel(); - let _t = thread::spawn(move|| { - let lock = arc2.lock().unwrap(); - let lock2 = lock.lock().unwrap(); - assert_eq!(*lock2, 1); - tx.send(()).unwrap(); - }); - rx.recv().unwrap(); - } - - #[test] - fn test_mutex_arc_access_in_unwind() { - let arc = Arc::new(Mutex::new(1)); - let arc2 = arc.clone(); - let _ = thread::spawn(move|| -> () { - struct Unwinder { - i: Arc<Mutex<i32>>, - } - impl Drop for Unwinder { - fn drop(&mut self) { - *self.i.lock().unwrap() += 1; - } - } - let _u = Unwinder { i: arc2 }; - panic!(); - }).join(); - let lock = arc.lock().unwrap(); - assert_eq!(*lock, 2); - } - - #[test] - fn test_mutex_unsized() { - let mutex: &Mutex<[i32]> = &Mutex::new([1, 2, 3]); - { - let b = &mut *mutex.lock().unwrap(); - b[0] = 4; - b[2] = 5; - } - let comp: &[i32] = &[4, 2, 5]; - assert_eq!(&*mutex.lock().unwrap(), comp); - } -} |