Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

std: replace std::unstable::finally with a RAII finally! macro #11905

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 27 additions & 25 deletions src/libextra/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,22 @@ use std::comm;
use std::unstable::sync::Exclusive;
use std::sync::arc::UnsafeArc;
use std::sync::atomics;
use std::unstable::finally::Finally;
use std::util;
use std::util::NonCopyable;

use arc::MutexArc;

#[cfg(stage0)] // SNAP b6400f9
macro_rules! finally {
($e: expr) => {
// this `let` has to be free-standing, so that it's directly
// in the scope of the callee of `finally!`, to get the dtor to
// run at the right time.
let _guard = ::std::finally::FinallyGuard::new(|| $e);
}
}


/****************************************************************************
* Internals
****************************************************************************/
Expand Down Expand Up @@ -140,12 +150,9 @@ impl<Q:Send> Sem<Q> {
}

pub fn access<U>(&self, blk: || -> U) -> U {
(|| {
self.acquire();
blk()
}).finally(|| {
self.release();
})
self.acquire();
finally!(self.release());
blk()
}
}

Expand Down Expand Up @@ -233,15 +240,13 @@ impl<'a> Condvar<'a> {
// Unconditionally "block". (Might not actually block if a
// signaller already sent -- I mean 'unconditionally' in contrast
// with acquire().)
(|| {
let _ = WaitEnd.take_unwrap().recv();
}).finally(|| {
finally!(
// Reacquire the condvar.
match self.order {
Just(lock) => lock.access(|| self.sem.acquire()),
Nothing => self.sem.acquire(),
}
})
});
let _ = WaitEnd.take_unwrap().recv();
})
}

Expand Down Expand Up @@ -497,9 +502,8 @@ impl RWLock {
state.read_mode = true;
}
});
(|| {
blk()
}).finally(|| {

finally!({
let state = &mut *self.state.get();
assert!(state.read_mode);
let old_count = state.read_count.fetch_sub(1, atomics::Release);
Expand All @@ -512,7 +516,8 @@ impl RWLock {
// this access MUST NOT go inside the exclusive access.
(&self.access_lock).release();
}
})
});
blk()
}
}

Expand Down Expand Up @@ -600,9 +605,7 @@ impl RWLock {
(&self.order_lock).acquire();
(&self.access_lock).acquire();
(&self.order_lock).release();
(|| {
blk(RWLockWriteMode { lock: self, token: NonCopyable })
}).finally(|| {
finally!({
let writer_or_last_reader;
// Check if we're releasing from read mode or from write mode.
let state = unsafe { &mut *self.state.get() };
Expand All @@ -627,7 +630,8 @@ impl RWLock {
// Nobody left inside; release the "reader cloud" lock.
(&self.access_lock).release();
}
})
});
blk(RWLockWriteMode { lock: self, token: NonCopyable })
}

/// To be called inside of the write_downgrade block.
Expand Down Expand Up @@ -1011,7 +1015,6 @@ mod tests {
#[ignore(reason = "linked failure")]
#[test]
fn test_mutex_killed_broadcast() {
use std::unstable::finally::Finally;

let m = Mutex::new();
let m2 = m.clone();
Expand All @@ -1027,13 +1030,12 @@ mod tests {
task::spawn(proc() { // linked
mi.lock_cond(|cond| {
c.send(()); // tell sibling to go ahead
(|| {
cond.wait(); // block forever
}).finally(|| {
finally!({
error!("task unwinding and sending");
c.send(());
error!("task unwinding and done sending");
})
});
cond.wait(); // block forever
})
});
}
Expand Down
102 changes: 102 additions & 0 deletions src/libstd/finally.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// 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.

//! Guarantee that a piece of code is always run.

#[macro_escape];

use ops::Drop;

#[macro_export]
macro_rules! finally {
($e: expr) => {
// this `let` has to be free-standing, so that it's directly
// in the finally of the callee of `finally!`, to get the dtor to
// run at the right time.
let _guard = ::std::finally::FinallyGuard::new(|| $e);
}
}

/// Runs a user-provided function on destruction.
///
/// One can use this to guarantee that a piece of code is always run,
/// even when the task fails. The `finally!` macro provides a convenient
/// interface, by taking an expression that is wrapped into the
/// appropriate closure.
///
/// # Example
///
/// ```rust
/// {
/// finally!(println!("bye"));
///
/// println!("hi");
/// } // `hi` then `bye`
///
/// {
/// finally!(println!("bye"));
///
/// fail!("oops");
/// } // always prints `bye`
/// ```
pub struct FinallyGuard<'a> {
priv f: 'a ||
}
impl<'a> FinallyGuard<'a> {
/// Create a new `FinallyGuard`.
pub fn new(f: 'a ||) -> FinallyGuard<'a> {
FinallyGuard { f: f }
}
}

#[unsafe_destructor]
impl<'a> Drop for FinallyGuard<'a> {
fn drop(&mut self) {
(self.f)()
}
}

#[cfg(test)]
mod test {
use finally::FinallyGuard;
use comm::Chan;
use task::task;

#[test]
fn test_no_fail() {
let mut ran = false;
{
finally!(ran = true);
assert!(!ran);
}
assert!(ran)
}


#[test]
fn test_fail() {
let mut t = task();
let completion = t.future_result();

let (p, c) = Chan::new();

t.spawn(proc() {
finally!(c.send("guarded"));
c.send("unguarded");
fail!()
});

// wait for the task to complete
completion.recv();

assert_eq!(p.recv(), "unguarded");
assert_eq!(p.recv(), "guarded");
}
}
9 changes: 4 additions & 5 deletions src/libstd/io/extensions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,6 @@ pub fn u64_from_be_bytes(data: &[u8],

#[cfg(test)]
mod test {
use unstable::finally::Finally;
use prelude::*;
use io::{MemReader, MemWriter};
use io::{io_error, placeholder_error};
Expand Down Expand Up @@ -371,13 +370,13 @@ mod test {
};
// FIXME (#7049): Figure out some other way to do this.
//let buf = RefCell::new(~[8, 9]);
(|| {
//reader.push_bytes(buf.borrow_mut().get(), 4);
}).finally(|| {
finally!(
// NB: Using rtassert here to trigger abort on failure since this is a should_fail test
// FIXME: #7049 This fails because buf is still borrowed
//rtassert!(buf.borrow().get() == ~[8, 9, 10]);
})
);

//reader.push_bytes(buf.borrow_mut().get(), 4);
}

#[test]
Expand Down
28 changes: 13 additions & 15 deletions src/libstd/io/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,6 @@ use str;
use str::{StrSlice, OwnedStr};
use to_str::ToStr;
use uint;
use unstable::finally::Finally;
use vec::{OwnedVector, MutableVector, ImmutableVector, OwnedCloneableVector};
use vec;

Expand Down Expand Up @@ -544,22 +543,21 @@ pub trait Reader {

buf.reserve_additional(len);
buf.set_len(start_len + len);

(|| {
while total_read < len {
let len = buf.len();
let slice = buf.mut_slice(start_len + total_read, len);
match self.read(slice) {
Some(nread) => {
total_read += nread;
}
None => {
io_error::cond.raise(standard_error(EndOfFile));
break;
}
finally!(buf.set_len(start_len + total_read));

while total_read < len {
let len = buf.len();
let slice = buf.mut_slice(start_len + total_read, len);
match self.read(slice) {
Some(nread) => {
total_read += nread;
}
None => {
io_error::cond.raise(standard_error(EndOfFile));
break;
}
}
}).finally(|| buf.set_len(start_len + total_read))
}
}
}

Expand Down
3 changes: 3 additions & 0 deletions src/libstd/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ pub mod bool;
pub mod char;
pub mod tuple;

pub mod scope;

pub mod vec;
pub mod vec_ng;
pub mod at_vec;
Expand Down Expand Up @@ -226,6 +228,7 @@ mod std {
pub use option;
pub use os;
pub use rt;
pub use scope;
pub use str;
pub use to_bytes;
pub use to_str;
Expand Down
10 changes: 4 additions & 6 deletions src/libstd/os.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ use prelude::*;
use ptr;
use str;
use fmt;
use unstable::finally::Finally;
use sync::atomics::{AtomicInt, INIT_ATOMIC_INT, SeqCst};

/// Delegates to the libc close() function, returning the same return value.
Expand Down Expand Up @@ -133,15 +132,14 @@ Serialize access through a global lock.
*/
fn with_env_lock<T>(f: || -> T) -> T {
use unstable::mutex::{Mutex, MUTEX_INIT};
use unstable::finally::Finally;

static mut lock: Mutex = MUTEX_INIT;

unsafe {
return (|| {
lock.lock();
f()
}).finally(|| lock.unlock());
lock.lock();
finally!(lock.unlock());

f()
}
}

Expand Down
Loading