Skip to content

Commit 4fe1296

Browse files
committed
auto merge of #10660 : alexcrichton/rust/little-scope, r=pcwalton
This moves the locking/waiting methods to returning an RAII struct instead of relying on closures. Additionally, this changes the methods to all take '&mut self' to discourage recursive locking. The new method to block is to call `wait` on the returned RAII structure instead of calling it on the lock itself (this enforces that the lock is held). At the same time, this improves the Mutex interface a bit by allowing destruction of non-initialized members and by allowing construction of an empty mutex (nothing initialized inside).
2 parents 21990cd + ac59888 commit 4fe1296

File tree

2 files changed

+71
-71
lines changed

2 files changed

+71
-71
lines changed

src/libstd/unstable/mutex.rs

+21-2
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,15 @@ impl Mutex {
7070
}
7171
}
7272

73+
/// Creates a new mutex, with the lock/condition variable not initialized.
74+
/// This is the same as initializing from the MUTEX_INIT static.
75+
pub unsafe fn empty() -> Mutex {
76+
Mutex {
77+
lock: atomics::AtomicUint::new(0),
78+
cond: atomics::AtomicUint::new(0),
79+
}
80+
}
81+
7382
/// Creates a new copy of this mutex. This is an unsafe operation because
7483
/// there is no reference counting performed on this type.
7584
///
@@ -117,8 +126,10 @@ impl Mutex {
117126
/// that no other thread is currently holding the lock or waiting on the
118127
/// condition variable contained inside.
119128
pub unsafe fn destroy(&mut self) {
120-
imp::free_lock(self.lock.swap(0, atomics::Relaxed));
121-
imp::free_cond(self.cond.swap(0, atomics::Relaxed));
129+
let lock = self.lock.swap(0, atomics::Relaxed);
130+
let cond = self.cond.swap(0, atomics::Relaxed);
131+
if lock != 0 { imp::free_lock(lock) }
132+
if cond != 0 { imp::free_cond(cond) }
122133
}
123134

124135
unsafe fn getlock(&mut self) -> *c_void {
@@ -333,4 +344,12 @@ mod test {
333344
t.join();
334345
}
335346
}
347+
348+
#[test]
349+
fn destroy_immediately() {
350+
unsafe {
351+
let mut m = Mutex::empty();
352+
m.destroy();
353+
}
354+
}
336355
}

src/libstd/unstable/sync.rs

+50-69
Original file line numberDiff line numberDiff line change
@@ -319,67 +319,49 @@ pub struct LittleLock {
319319
priv l: Mutex,
320320
}
321321

322+
pub struct LittleGuard<'a> {
323+
priv l: &'a mut Mutex,
324+
}
325+
322326
impl Drop for LittleLock {
323327
fn drop(&mut self) {
324-
unsafe {
325-
self.l.destroy();
326-
}
328+
unsafe { self.l.destroy(); }
329+
}
330+
}
331+
332+
#[unsafe_destructor]
333+
impl<'a> Drop for LittleGuard<'a> {
334+
fn drop(&mut self) {
335+
unsafe { self.l.unlock(); }
327336
}
328337
}
329338

330339
impl LittleLock {
331340
pub fn new() -> LittleLock {
332-
unsafe {
333-
LittleLock {
334-
l: Mutex::new()
335-
}
336-
}
341+
unsafe { LittleLock { l: Mutex::new() } }
337342
}
338343

339-
pub unsafe fn lock<T>(&self, f: || -> T) -> T {
340-
let this = cast::transmute_mut(self);
341-
do atomically {
342-
this.l.lock();
343-
do (|| {
344-
f()
345-
}).finally {
346-
this.l.unlock();
347-
}
348-
}
344+
pub unsafe fn lock<'a>(&'a mut self) -> LittleGuard<'a> {
345+
self.l.lock();
346+
LittleGuard { l: &mut self.l }
349347
}
350348

351-
pub unsafe fn try_lock<T>(&self, f: || -> T) -> Option<T> {
352-
let this = cast::transmute_mut(self);
353-
do atomically {
354-
if this.l.trylock() {
355-
Some(do (|| {
356-
f()
357-
}).finally {
358-
this.l.unlock();
359-
})
360-
} else {
361-
None
362-
}
349+
pub unsafe fn try_lock<'a>(&'a mut self) -> Option<LittleGuard<'a>> {
350+
if self.l.trylock() {
351+
Some(LittleGuard { l: &mut self.l })
352+
} else {
353+
None
363354
}
364355
}
365356

366-
pub unsafe fn signal(&self) {
367-
let this = cast::transmute_mut(self);
368-
this.l.signal();
357+
pub unsafe fn signal(&mut self) {
358+
self.l.signal();
369359
}
360+
}
370361

371-
pub unsafe fn lock_and_wait(&self, f: || -> bool) {
372-
let this = cast::transmute_mut(self);
373-
do atomically {
374-
this.l.lock();
375-
do (|| {
376-
if f() {
377-
this.l.wait();
378-
}
379-
}).finally {
380-
this.l.unlock();
381-
}
382-
}
362+
impl<'a> LittleGuard<'a> {
363+
pub unsafe fn wait(&mut self) {
364+
self.l.wait();
383365
}
384366
}
385367

@@ -431,15 +413,14 @@ impl<T:Send> Exclusive<T> {
431413
#[inline]
432414
pub unsafe fn with<U>(&self, f: |x: &mut T| -> U) -> U {
433415
let rec = self.x.get();
434-
do (*rec).lock.lock {
435-
if (*rec).failed {
436-
fail!("Poisoned Exclusive::new - another task failed inside!");
437-
}
438-
(*rec).failed = true;
439-
let result = f(&mut (*rec).data);
440-
(*rec).failed = false;
441-
result
416+
let _l = (*rec).lock.lock();
417+
if (*rec).failed {
418+
fail!("Poisoned Exclusive::new - another task failed inside!");
442419
}
420+
(*rec).failed = true;
421+
let result = f(&mut (*rec).data);
422+
(*rec).failed = false;
423+
result
443424
}
444425

445426
#[inline]
@@ -452,28 +433,28 @@ impl<T:Send> Exclusive<T> {
452433
#[inline]
453434
pub unsafe fn hold_and_signal(&self, f: |x: &mut T|) {
454435
let rec = self.x.get();
455-
do (*rec).lock.lock {
456-
if (*rec).failed {
457-
fail!("Poisoned Exclusive::new - another task failed inside!");
458-
}
459-
(*rec).failed = true;
460-
f(&mut (*rec).data);
461-
(*rec).failed = false;
462-
(*rec).lock.signal();
436+
let _l = (*rec).lock.lock();
437+
if (*rec).failed {
438+
fail!("Poisoned Exclusive::new - another task failed inside!");
463439
}
440+
(*rec).failed = true;
441+
f(&mut (*rec).data);
442+
(*rec).failed = false;
443+
(*rec).lock.signal();
464444
}
465445

466446
#[inline]
467447
pub unsafe fn hold_and_wait(&self, f: |x: &T| -> bool) {
468448
let rec = self.x.get();
469-
do (*rec).lock.lock_and_wait {
470-
if (*rec).failed {
471-
fail!("Poisoned Exclusive::new - another task failed inside!");
472-
}
473-
(*rec).failed = true;
474-
let result = f(&(*rec).data);
475-
(*rec).failed = false;
476-
result
449+
let mut l = (*rec).lock.lock();
450+
if (*rec).failed {
451+
fail!("Poisoned Exclusive::new - another task failed inside!");
452+
}
453+
(*rec).failed = true;
454+
let result = f(&(*rec).data);
455+
(*rec).failed = false;
456+
if result {
457+
l.wait();
477458
}
478459
}
479460

0 commit comments

Comments
 (0)