diff --git a/src/libstd/unstable/mutex.rs b/src/libstd/unstable/mutex.rs index 5be9be7bf8a99..ff46824d82359 100644 --- a/src/libstd/unstable/mutex.rs +++ b/src/libstd/unstable/mutex.rs @@ -70,6 +70,15 @@ impl Mutex { } } + /// Creates a new mutex, with the lock/condition variable not initialized. + /// This is the same as initializing from the MUTEX_INIT static. + pub unsafe fn empty() -> Mutex { + Mutex { + lock: atomics::AtomicUint::new(0), + cond: atomics::AtomicUint::new(0), + } + } + /// Creates a new copy of this mutex. This is an unsafe operation because /// there is no reference counting performed on this type. /// @@ -117,8 +126,10 @@ impl Mutex { /// that no other thread is currently holding the lock or waiting on the /// condition variable contained inside. pub unsafe fn destroy(&mut self) { - imp::free_lock(self.lock.swap(0, atomics::Relaxed)); - imp::free_cond(self.cond.swap(0, atomics::Relaxed)); + let lock = self.lock.swap(0, atomics::Relaxed); + let cond = self.cond.swap(0, atomics::Relaxed); + if lock != 0 { imp::free_lock(lock) } + if cond != 0 { imp::free_cond(cond) } } unsafe fn getlock(&mut self) -> *c_void { @@ -333,4 +344,12 @@ mod test { t.join(); } } + + #[test] + fn destroy_immediately() { + unsafe { + let mut m = Mutex::empty(); + m.destroy(); + } + } } diff --git a/src/libstd/unstable/sync.rs b/src/libstd/unstable/sync.rs index f22a707fef6ce..e80b58d01efb2 100644 --- a/src/libstd/unstable/sync.rs +++ b/src/libstd/unstable/sync.rs @@ -319,67 +319,49 @@ pub struct LittleLock { priv l: Mutex, } +pub struct LittleGuard<'a> { + priv l: &'a mut Mutex, +} + impl Drop for LittleLock { fn drop(&mut self) { - unsafe { - self.l.destroy(); - } + unsafe { self.l.destroy(); } + } +} + +#[unsafe_destructor] +impl<'a> Drop for LittleGuard<'a> { + fn drop(&mut self) { + unsafe { self.l.unlock(); } } } impl LittleLock { pub fn new() -> LittleLock { - unsafe { - LittleLock { - l: Mutex::new() - } - } + unsafe { LittleLock { l: Mutex::new() } } } - pub unsafe fn lock(&self, f: || -> T) -> T { - let this = cast::transmute_mut(self); - do atomically { - this.l.lock(); - do (|| { - f() - }).finally { - this.l.unlock(); - } - } + pub unsafe fn lock<'a>(&'a mut self) -> LittleGuard<'a> { + self.l.lock(); + LittleGuard { l: &mut self.l } } - pub unsafe fn try_lock(&self, f: || -> T) -> Option { - let this = cast::transmute_mut(self); - do atomically { - if this.l.trylock() { - Some(do (|| { - f() - }).finally { - this.l.unlock(); - }) - } else { - None - } + pub unsafe fn try_lock<'a>(&'a mut self) -> Option> { + if self.l.trylock() { + Some(LittleGuard { l: &mut self.l }) + } else { + None } } - pub unsafe fn signal(&self) { - let this = cast::transmute_mut(self); - this.l.signal(); + pub unsafe fn signal(&mut self) { + self.l.signal(); } +} - pub unsafe fn lock_and_wait(&self, f: || -> bool) { - let this = cast::transmute_mut(self); - do atomically { - this.l.lock(); - do (|| { - if f() { - this.l.wait(); - } - }).finally { - this.l.unlock(); - } - } +impl<'a> LittleGuard<'a> { + pub unsafe fn wait(&mut self) { + self.l.wait(); } } @@ -431,15 +413,14 @@ impl Exclusive { #[inline] pub unsafe fn with(&self, f: |x: &mut T| -> U) -> U { let rec = self.x.get(); - do (*rec).lock.lock { - if (*rec).failed { - fail!("Poisoned Exclusive::new - another task failed inside!"); - } - (*rec).failed = true; - let result = f(&mut (*rec).data); - (*rec).failed = false; - result + let _l = (*rec).lock.lock(); + if (*rec).failed { + fail!("Poisoned Exclusive::new - another task failed inside!"); } + (*rec).failed = true; + let result = f(&mut (*rec).data); + (*rec).failed = false; + result } #[inline] @@ -452,28 +433,28 @@ impl Exclusive { #[inline] pub unsafe fn hold_and_signal(&self, f: |x: &mut T|) { let rec = self.x.get(); - do (*rec).lock.lock { - if (*rec).failed { - fail!("Poisoned Exclusive::new - another task failed inside!"); - } - (*rec).failed = true; - f(&mut (*rec).data); - (*rec).failed = false; - (*rec).lock.signal(); + let _l = (*rec).lock.lock(); + if (*rec).failed { + fail!("Poisoned Exclusive::new - another task failed inside!"); } + (*rec).failed = true; + f(&mut (*rec).data); + (*rec).failed = false; + (*rec).lock.signal(); } #[inline] pub unsafe fn hold_and_wait(&self, f: |x: &T| -> bool) { let rec = self.x.get(); - do (*rec).lock.lock_and_wait { - if (*rec).failed { - fail!("Poisoned Exclusive::new - another task failed inside!"); - } - (*rec).failed = true; - let result = f(&(*rec).data); - (*rec).failed = false; - result + let mut l = (*rec).lock.lock(); + if (*rec).failed { + fail!("Poisoned Exclusive::new - another task failed inside!"); + } + (*rec).failed = true; + let result = f(&(*rec).data); + (*rec).failed = false; + if result { + l.wait(); } }