From b8ffad5964e328340de0c03779577eb14caa16fc Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Fri, 26 Dec 2014 16:04:27 -0500 Subject: s/task/thread/g A part of #20038 --- src/libstd/sync/task_pool.rs | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'src/libstd/sync') diff --git a/src/libstd/sync/task_pool.rs b/src/libstd/sync/task_pool.rs index 366e4b7d35b..5fc02e7b316 100644 --- a/src/libstd/sync/task_pool.rs +++ b/src/libstd/sync/task_pool.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Abstraction of a task pool for basic parallelism. +//! Abstraction of a thread pool for basic parallelism. use core::prelude::*; @@ -45,9 +45,9 @@ impl<'a> Drop for Sentinel<'a> { } } -/// A task pool used to execute functions in parallel. +/// A thread pool used to execute functions in parallel. /// -/// Spawns `n` worker tasks and replenishes the pool if any worker tasks +/// Spawns `n` worker threads and replenishes the pool if any worker threads /// panic. /// /// # Example @@ -69,34 +69,34 @@ impl<'a> Drop for Sentinel<'a> { /// assert_eq!(rx.iter().take(8u).sum(), 8u); /// ``` pub struct TaskPool { - // How the taskpool communicates with subtasks. + // How the threadpool communicates with subthreads. // - // This is the only such Sender, so when it is dropped all subtasks will + // This is the only such Sender, so when it is dropped all subthreads will // quit. jobs: Sender } impl TaskPool { - /// Spawns a new task pool with `tasks` tasks. + /// Spawns a new thread pool with `threads` threads. /// /// # Panics /// - /// This function will panic if `tasks` is 0. - pub fn new(tasks: uint) -> TaskPool { - assert!(tasks >= 1); + /// This function will panic if `threads` is 0. + pub fn new(threads: uint) -> TaskPool { + assert!(threads >= 1); let (tx, rx) = channel::(); let rx = Arc::new(Mutex::new(rx)); - // Taskpool tasks. - for _ in range(0, tasks) { + // Threadpool threads + for _ in range(0, threads) { spawn_in_pool(rx.clone()); } TaskPool { jobs: tx } } - /// Executes the function `job` on a task in the pool. + /// Executes the function `job` on a thread in the pool. pub fn execute(&self, job: F) where F : FnOnce(), F : Send { @@ -106,7 +106,7 @@ impl TaskPool { fn spawn_in_pool(jobs: Arc>>) { Thread::spawn(move |:| { - // Will spawn a new task on panic unless it is cancelled. + // Will spawn a new thread on panic unless it is cancelled. let sentinel = Sentinel::new(&jobs); loop { @@ -165,12 +165,12 @@ mod test { let pool = TaskPool::new(TEST_TASKS); - // Panic all the existing tasks. + // Panic all the existing threads. for _ in range(0, TEST_TASKS) { pool.execute(move|| -> () { panic!() }); } - // Ensure new tasks were spawned to compensate. + // Ensure new threads were spawned to compensate. let (tx, rx) = channel(); for _ in range(0, TEST_TASKS) { let tx = tx.clone(); @@ -189,7 +189,7 @@ mod test { let pool = TaskPool::new(TEST_TASKS); let waiter = Arc::new(Barrier::new(TEST_TASKS + 1)); - // Panic all the existing tasks in a bit. + // Panic all the existing threads in a bit. for _ in range(0, TEST_TASKS) { let waiter = waiter.clone(); pool.execute(move|| { -- cgit 1.4.1-3-g733a5 From 1e89bbcb67020892bc0af5af218c35f0fd453fa4 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sun, 28 Dec 2014 02:20:47 +0200 Subject: Rename TaskRng to ThreadRng MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since runtime is removed, rust has no tasks anymore and everything is moving from being task-* to thread-*. Let’s rename TaskRng as well! * Rename TaskRng to ThreadRng * Rename task_rng to thread_rng [breaking-change] --- src/libcollections/slice.rs | 6 +- src/libflate/lib.rs | 2 +- src/librand/distributions/exponential.rs | 2 +- src/librand/distributions/gamma.rs | 8 +-- src/librand/distributions/mod.rs | 2 +- src/librand/distributions/normal.rs | 4 +- src/librand/distributions/range.rs | 2 +- src/librand/lib.rs | 36 +++++----- src/librand/rand_impls.rs | 6 +- src/libregex/test/bench.rs | 4 +- src/libserialize/base64.rs | 4 +- src/libstd/hash.rs | 2 +- src/libstd/os.rs | 2 +- src/libstd/rand/mod.rs | 88 +++++++++++------------ src/libstd/sync/rwlock.rs | 2 +- src/libsyntax/parse/token.rs | 2 +- src/test/bench/core-std.rs | 6 +- src/test/compile-fail/task-rng-isnt-sendable.rs | 4 +- src/test/run-make/unicode-input/multiple_files.rs | 4 +- src/test/run-make/unicode-input/span_length.rs | 6 +- src/test/run-pass/vector-sort-panic-safe.rs | 4 +- 21 files changed, 98 insertions(+), 98 deletions(-) (limited to 'src/libstd/sync') diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index d6d94f57acf..60c360de094 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -1347,7 +1347,7 @@ mod tests { use core::cell::Cell; use core::default::Default; use core::mem; - use std::rand::{Rng, task_rng}; + use std::rand::{Rng, thread_rng}; use std::rc::Rc; use super::ElementSwaps; @@ -1963,7 +1963,7 @@ mod tests { fn test_sort() { for len in range(4u, 25) { for _ in range(0i, 100) { - let mut v = task_rng().gen_iter::().take(len) + let mut v = thread_rng().gen_iter::().take(len) .collect::>(); let mut v1 = v.clone(); @@ -1999,7 +1999,7 @@ mod tests { // number this element is, i.e. the second elements // will occur in sorted order. let mut v = range(0, len).map(|_| { - let n = task_rng().gen::() % 10; + let n = thread_rng().gen::() % 10; counts[n] += 1; (n, counts[n]) }).collect::>(); diff --git a/src/libflate/lib.rs b/src/libflate/lib.rs index 8c4f74027a5..aa1550ae5b8 100644 --- a/src/libflate/lib.rs +++ b/src/libflate/lib.rs @@ -112,7 +112,7 @@ mod tests { #[test] fn test_flate_round_trip() { - let mut r = rand::task_rng(); + let mut r = rand::thread_rng(); let mut words = vec!(); for _ in range(0u, 20) { let range = r.gen_range(1u, 10); diff --git a/src/librand/distributions/exponential.rs b/src/librand/distributions/exponential.rs index 431a530726a..f31f3468a4c 100644 --- a/src/librand/distributions/exponential.rs +++ b/src/librand/distributions/exponential.rs @@ -64,7 +64,7 @@ impl Rand for Exp1 { /// use std::rand::distributions::{Exp, IndependentSample}; /// /// let exp = Exp::new(2.0); -/// let v = exp.ind_sample(&mut rand::task_rng()); +/// let v = exp.ind_sample(&mut rand::thread_rng()); /// println!("{} is from a Exp(2) distribution", v); /// ``` #[deriving(Copy)] diff --git a/src/librand/distributions/gamma.rs b/src/librand/distributions/gamma.rs index d33d838766f..618db380db8 100644 --- a/src/librand/distributions/gamma.rs +++ b/src/librand/distributions/gamma.rs @@ -44,7 +44,7 @@ use super::{IndependentSample, Sample, Exp}; /// use std::rand::distributions::{IndependentSample, Gamma}; /// /// let gamma = Gamma::new(2.0, 5.0); -/// let v = gamma.ind_sample(&mut rand::task_rng()); +/// let v = gamma.ind_sample(&mut rand::thread_rng()); /// println!("{} is from a Gamma(2, 5) distribution", v); /// ``` /// @@ -191,7 +191,7 @@ impl IndependentSample for GammaLargeShape { /// use std::rand::distributions::{ChiSquared, IndependentSample}; /// /// let chi = ChiSquared::new(11.0); -/// let v = chi.ind_sample(&mut rand::task_rng()); +/// let v = chi.ind_sample(&mut rand::thread_rng()); /// println!("{} is from a χ²(11) distribution", v) /// ``` pub struct ChiSquared { @@ -248,7 +248,7 @@ impl IndependentSample for ChiSquared { /// use std::rand::distributions::{FisherF, IndependentSample}; /// /// let f = FisherF::new(2.0, 32.0); -/// let v = f.ind_sample(&mut rand::task_rng()); +/// let v = f.ind_sample(&mut rand::thread_rng()); /// println!("{} is from an F(2, 32) distribution", v) /// ``` pub struct FisherF { @@ -292,7 +292,7 @@ impl IndependentSample for FisherF { /// use std::rand::distributions::{StudentT, IndependentSample}; /// /// let t = StudentT::new(11.0); -/// let v = t.ind_sample(&mut rand::task_rng()); +/// let v = t.ind_sample(&mut rand::thread_rng()); /// println!("{} is from a t(11) distribution", v) /// ``` pub struct StudentT { diff --git a/src/librand/distributions/mod.rs b/src/librand/distributions/mod.rs index 58125c67fda..54cb8ae1907 100644 --- a/src/librand/distributions/mod.rs +++ b/src/librand/distributions/mod.rs @@ -96,7 +96,7 @@ pub struct Weighted { /// Weighted { weight: 4, item: 'b' }, /// Weighted { weight: 1, item: 'c' }); /// let wc = WeightedChoice::new(items.as_mut_slice()); -/// let mut rng = rand::task_rng(); +/// let mut rng = rand::thread_rng(); /// for _ in range(0u, 16) { /// // on average prints 'a' 4 times, 'b' 8 and 'c' twice. /// println!("{}", wc.ind_sample(&mut rng)); diff --git a/src/librand/distributions/normal.rs b/src/librand/distributions/normal.rs index 16413af6267..3507282ec48 100644 --- a/src/librand/distributions/normal.rs +++ b/src/librand/distributions/normal.rs @@ -81,7 +81,7 @@ impl Rand for StandardNormal { /// /// // mean 2, standard deviation 3 /// let normal = Normal::new(2.0, 3.0); -/// let v = normal.ind_sample(&mut rand::task_rng()); +/// let v = normal.ind_sample(&mut rand::thread_rng()); /// println!("{} is from a N(2, 9) distribution", v) /// ``` #[deriving(Copy)] @@ -129,7 +129,7 @@ impl IndependentSample for Normal { /// /// // mean 2, standard deviation 3 /// let log_normal = LogNormal::new(2.0, 3.0); -/// let v = log_normal.ind_sample(&mut rand::task_rng()); +/// let v = log_normal.ind_sample(&mut rand::thread_rng()); /// println!("{} is from an ln N(2, 9) distribution", v) /// ``` #[deriving(Copy)] diff --git a/src/librand/distributions/range.rs b/src/librand/distributions/range.rs index 6301623bbdc..20ba3566d5b 100644 --- a/src/librand/distributions/range.rs +++ b/src/librand/distributions/range.rs @@ -39,7 +39,7 @@ use distributions::{Sample, IndependentSample}; /// /// fn main() { /// let between = Range::new(10u, 10000u); -/// let mut rng = std::rand::task_rng(); +/// let mut rng = std::rand::thread_rng(); /// let mut sum = 0; /// for _ in range(0u, 1000) { /// sum += between.ind_sample(&mut rng); diff --git a/src/librand/lib.rs b/src/librand/lib.rs index 514ff81da51..273b991bc22 100644 --- a/src/librand/lib.rs +++ b/src/librand/lib.rs @@ -138,10 +138,10 @@ pub trait Rng { /// # Example /// /// ```rust - /// use std::rand::{task_rng, Rng}; + /// use std::rand::{thread_rng, Rng}; /// /// let mut v = [0u8, .. 13579]; - /// task_rng().fill_bytes(&mut v); + /// thread_rng().fill_bytes(&mut v); /// println!("{}", v.as_slice()); /// ``` fn fill_bytes(&mut self, dest: &mut [u8]) { @@ -173,9 +173,9 @@ pub trait Rng { /// # Example /// /// ```rust - /// use std::rand::{task_rng, Rng}; + /// use std::rand::{thread_rng, Rng}; /// - /// let mut rng = task_rng(); + /// let mut rng = thread_rng(); /// let x: uint = rng.gen(); /// println!("{}", x); /// println!("{}", rng.gen::<(f64, bool)>()); @@ -191,9 +191,9 @@ pub trait Rng { /// # Example /// /// ``` - /// use std::rand::{task_rng, Rng}; + /// use std::rand::{thread_rng, Rng}; /// - /// let mut rng = task_rng(); + /// let mut rng = thread_rng(); /// let x = rng.gen_iter::().take(10).collect::>(); /// println!("{}", x); /// println!("{}", rng.gen_iter::<(f64, bool)>().take(5) @@ -218,9 +218,9 @@ pub trait Rng { /// # Example /// /// ```rust - /// use std::rand::{task_rng, Rng}; + /// use std::rand::{thread_rng, Rng}; /// - /// let mut rng = task_rng(); + /// let mut rng = thread_rng(); /// let n: uint = rng.gen_range(0u, 10); /// println!("{}", n); /// let m: f64 = rng.gen_range(-40.0f64, 1.3e5f64); @@ -236,9 +236,9 @@ pub trait Rng { /// # Example /// /// ```rust - /// use std::rand::{task_rng, Rng}; + /// use std::rand::{thread_rng, Rng}; /// - /// let mut rng = task_rng(); + /// let mut rng = thread_rng(); /// println!("{}", rng.gen_weighted_bool(3)); /// ``` fn gen_weighted_bool(&mut self, n: uint) -> bool { @@ -250,9 +250,9 @@ pub trait Rng { /// # Example /// /// ```rust - /// use std::rand::{task_rng, Rng}; + /// use std::rand::{thread_rng, Rng}; /// - /// let s: String = task_rng().gen_ascii_chars().take(10).collect(); + /// let s: String = thread_rng().gen_ascii_chars().take(10).collect(); /// println!("{}", s); /// ``` fn gen_ascii_chars<'a>(&'a mut self) -> AsciiGenerator<'a, Self> { @@ -266,10 +266,10 @@ pub trait Rng { /// # Example /// /// ``` - /// use std::rand::{task_rng, Rng}; + /// use std::rand::{thread_rng, Rng}; /// /// let choices = [1i, 2, 4, 8, 16, 32]; - /// let mut rng = task_rng(); + /// let mut rng = thread_rng(); /// println!("{}", rng.choose(&choices)); /// assert_eq!(rng.choose(choices[..0]), None); /// ``` @@ -286,9 +286,9 @@ pub trait Rng { /// # Example /// /// ```rust - /// use std::rand::{task_rng, Rng}; + /// use std::rand::{thread_rng, Rng}; /// - /// let mut rng = task_rng(); + /// let mut rng = thread_rng(); /// let mut y = [1i, 2, 3]; /// rng.shuffle(&mut y); /// println!("{}", y.as_slice()); @@ -520,8 +520,8 @@ mod test { } } - pub fn rng() -> MyRng { - MyRng { inner: rand::task_rng() } + pub fn rng() -> MyRng { + MyRng { inner: rand::thread_rng() } } pub fn weak_rng() -> MyRng { diff --git a/src/librand/rand_impls.rs b/src/librand/rand_impls.rs index 3b38fde3884..e50153076c3 100644 --- a/src/librand/rand_impls.rs +++ b/src/librand/rand_impls.rs @@ -215,7 +215,7 @@ impl Rand for Option { #[cfg(test)] mod tests { use std::prelude::*; - use std::rand::{Rng, task_rng, Open01, Closed01}; + use std::rand::{Rng, thread_rng, Open01, Closed01}; struct ConstantRng(u64); impl Rng for ConstantRng { @@ -240,7 +240,7 @@ mod tests { fn rand_open() { // this is unlikely to catch an incorrect implementation that // generates exactly 0 or 1, but it keeps it sane. - let mut rng = task_rng(); + let mut rng = thread_rng(); for _ in range(0u, 1_000) { // strict inequalities let Open01(f) = rng.gen::>(); @@ -253,7 +253,7 @@ mod tests { #[test] fn rand_closed() { - let mut rng = task_rng(); + let mut rng = thread_rng(); for _ in range(0u, 1_000) { // strict inequalities let Closed01(f) = rng.gen::>(); diff --git a/src/libregex/test/bench.rs b/src/libregex/test/bench.rs index 0c204f759e6..38f030c3bda 100644 --- a/src/libregex/test/bench.rs +++ b/src/libregex/test/bench.rs @@ -9,7 +9,7 @@ // except according to those terms. #![allow(non_snake_case)] -use std::rand::{Rng, task_rng}; +use std::rand::{Rng, thread_rng}; use stdtest::Bencher; use regex::{Regex, NoExpand}; @@ -154,7 +154,7 @@ fn medium() -> Regex { regex!("[XYZ]ABCDEFGHIJKLMNOPQRSTUVWXYZ$") } fn hard() -> Regex { regex!("[ -~]*ABCDEFGHIJKLMNOPQRSTUVWXYZ$") } fn gen_text(n: uint) -> String { - let mut rng = task_rng(); + let mut rng = thread_rng(); let mut bytes = rng.gen_ascii_chars().map(|n| n as u8).take(n) .collect::>(); for (i, b) in bytes.iter_mut().enumerate() { diff --git a/src/libserialize/base64.rs b/src/libserialize/base64.rs index f1dffa55bb0..fae73cc834f 100644 --- a/src/libserialize/base64.rs +++ b/src/libserialize/base64.rs @@ -392,10 +392,10 @@ mod tests { #[test] fn test_base64_random() { - use std::rand::{task_rng, random, Rng}; + use std::rand::{thread_rng, random, Rng}; for _ in range(0u, 1000) { - let times = task_rng().gen_range(1u, 100); + let times = thread_rng().gen_range(1u, 100); let v = Vec::from_fn(times, |_| random::()); assert_eq!(v.to_base64(STANDARD) .from_base64() diff --git a/src/libstd/hash.rs b/src/libstd/hash.rs index 52e3c718b2d..737fef23c74 100644 --- a/src/libstd/hash.rs +++ b/src/libstd/hash.rs @@ -79,7 +79,7 @@ impl RandomSipHasher { /// Construct a new `RandomSipHasher` that is initialized with random keys. #[inline] pub fn new() -> RandomSipHasher { - let mut r = rand::task_rng(); + let mut r = rand::thread_rng(); let r0 = r.gen(); let r1 = r.gen(); RandomSipHasher { diff --git a/src/libstd/os.rs b/src/libstd/os.rs index ceb9a4102f6..822ba643f83 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -1438,7 +1438,7 @@ mod tests { } fn make_rand_name() -> String { - let mut rng = rand::task_rng(); + let mut rng = rand::thread_rng(); let n = format!("TEST{}", rng.gen_ascii_chars().take(10u) .collect::()); assert!(getenv(n.as_slice()).is_none()); diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs index c590c0f575e..d4f72a53aec 100644 --- a/src/libstd/rand/mod.rs +++ b/src/libstd/rand/mod.rs @@ -18,10 +18,10 @@ //! See the `distributions` submodule for sampling random numbers from //! distributions like normal and exponential. //! -//! # Task-local RNG +//! # Thread-local RNG //! -//! There is built-in support for a RNG associated with each task stored -//! in task-local storage. This RNG can be accessed via `task_rng`, or +//! There is built-in support for a RNG associated with each thread stored +//! in thread-local storage. This RNG can be accessed via `thread_rng`, or //! used implicitly via `random`. This RNG is normally randomly seeded //! from an operating-system source of randomness, e.g. `/dev/urandom` on //! Unix systems, and will automatically reseed itself from this source @@ -61,7 +61,7 @@ //! use std::rand; //! use std::rand::Rng; //! -//! let mut rng = rand::task_rng(); +//! let mut rng = rand::thread_rng(); //! if rng.gen() { // random bool //! println!("int: {}, uint: {}", rng.gen::(), rng.gen::()) //! } @@ -97,7 +97,7 @@ //! //! fn main() { //! let between = Range::new(-1f64, 1.); -//! let mut rng = rand::task_rng(); +//! let mut rng = rand::thread_rng(); //! //! let total = 1_000_000u; //! let mut in_circle = 0u; @@ -183,7 +183,7 @@ //! // The estimation will be more accurate with more simulations //! let num_simulations = 10000u; //! -//! let mut rng = rand::task_rng(); +//! let mut rng = rand::thread_rng(); //! let random_door = Range::new(0u, 3); //! //! let (mut switch_wins, mut switch_losses) = (0u, 0u); @@ -257,7 +257,7 @@ impl StdRng { /// randomness from the operating system and use this in an /// expensive seeding operation. If one is only generating a small /// number of random numbers, or doesn't need the utmost speed for - /// generating each number, `task_rng` and/or `random` may be more + /// generating each number, `thread_rng` and/or `random` may be more /// appropriate. /// /// Reading the randomness from the OS may fail, and any error is @@ -307,28 +307,28 @@ pub fn weak_rng() -> XorShiftRng { } } -/// Controls how the task-local RNG is reseeded. -struct TaskRngReseeder; +/// Controls how the thread-local RNG is reseeded. +struct ThreadRngReseeder; -impl reseeding::Reseeder for TaskRngReseeder { +impl reseeding::Reseeder for ThreadRngReseeder { fn reseed(&mut self, rng: &mut StdRng) { *rng = match StdRng::new() { Ok(r) => r, - Err(e) => panic!("could not reseed task_rng: {}", e) + Err(e) => panic!("could not reseed thread_rng: {}", e) } } } -static TASK_RNG_RESEED_THRESHOLD: uint = 32_768; -type TaskRngInner = reseeding::ReseedingRng; +static THREAD_RNG_RESEED_THRESHOLD: uint = 32_768; +type ThreadRngInner = reseeding::ReseedingRng; -/// The task-local RNG. -pub struct TaskRng { - rng: Rc>, +/// The thread-local RNG. +pub struct ThreadRng { + rng: Rc>, } -/// Retrieve the lazily-initialized task-local random number +/// Retrieve the lazily-initialized thread-local random number /// generator, seeded by the system. Intended to be used in method -/// chaining style, e.g. `task_rng().gen::()`. +/// chaining style, e.g. `thread_rng().gen::()`. /// /// The RNG provided will reseed itself from the operating system /// after generating a certain amount of randomness. @@ -337,23 +337,23 @@ pub struct TaskRng { /// if the operating system random number generator is rigged to give /// the same sequence always. If absolute consistency is required, /// explicitly select an RNG, e.g. `IsaacRng` or `Isaac64Rng`. -pub fn task_rng() -> TaskRng { +pub fn thread_rng() -> ThreadRng { // used to make space in TLS for a random number generator - thread_local!(static TASK_RNG_KEY: Rc> = { + thread_local!(static THREAD_RNG_KEY: Rc> = { let r = match StdRng::new() { Ok(r) => r, - Err(e) => panic!("could not initialize task_rng: {}", e) + Err(e) => panic!("could not initialize thread_rng: {}", e) }; let rng = reseeding::ReseedingRng::new(r, - TASK_RNG_RESEED_THRESHOLD, - TaskRngReseeder); + THREAD_RNG_RESEED_THRESHOLD, + ThreadRngReseeder); Rc::new(RefCell::new(rng)) }); - TaskRng { rng: TASK_RNG_KEY.with(|t| t.clone()) } + ThreadRng { rng: THREAD_RNG_KEY.with(|t| t.clone()) } } -impl Rng for TaskRng { +impl Rng for ThreadRng { fn next_u32(&mut self) -> u32 { self.rng.borrow_mut().next_u32() } @@ -368,7 +368,7 @@ impl Rng for TaskRng { } } -/// Generates a random value using the task-local random number generator. +/// Generates a random value using the thread-local random number generator. /// /// `random()` can generate various types of random things, and so may require /// type hinting to generate the specific type you want. @@ -390,7 +390,7 @@ impl Rng for TaskRng { /// ``` #[inline] pub fn random() -> T { - task_rng().gen() + thread_rng().gen() } /// Randomly sample up to `amount` elements from an iterator. @@ -398,9 +398,9 @@ pub fn random() -> T { /// # Example /// /// ```rust -/// use std::rand::{task_rng, sample}; +/// use std::rand::{thread_rng, sample}; /// -/// let mut rng = task_rng(); +/// let mut rng = thread_rng(); /// let sample = sample(&mut rng, range(1i, 100), 5); /// println!("{}", sample); /// ``` @@ -420,7 +420,7 @@ pub fn sample, R: Rng>(rng: &mut R, #[cfg(test)] mod test { use prelude::*; - use super::{Rng, task_rng, random, SeedableRng, StdRng, sample}; + use super::{Rng, thread_rng, random, SeedableRng, StdRng, sample}; use iter::order; struct ConstRng { i: u64 } @@ -453,7 +453,7 @@ mod test { #[test] fn test_gen_range() { - let mut r = task_rng(); + let mut r = thread_rng(); for _ in range(0u, 1000) { let a = r.gen_range(-3i, 42); assert!(a >= -3 && a < 42); @@ -473,20 +473,20 @@ mod test { #[test] #[should_fail] fn test_gen_range_panic_int() { - let mut r = task_rng(); + let mut r = thread_rng(); r.gen_range(5i, -2); } #[test] #[should_fail] fn test_gen_range_panic_uint() { - let mut r = task_rng(); + let mut r = thread_rng(); r.gen_range(5u, 2u); } #[test] fn test_gen_f64() { - let mut r = task_rng(); + let mut r = thread_rng(); let a = r.gen::(); let b = r.gen::(); debug!("{}", (a, b)); @@ -494,14 +494,14 @@ mod test { #[test] fn test_gen_weighted_bool() { - let mut r = task_rng(); + let mut r = thread_rng(); assert_eq!(r.gen_weighted_bool(0u), true); assert_eq!(r.gen_weighted_bool(1u), true); } #[test] fn test_gen_ascii_str() { - let mut r = task_rng(); + let mut r = thread_rng(); assert_eq!(r.gen_ascii_chars().take(0).count(), 0u); assert_eq!(r.gen_ascii_chars().take(10).count(), 10u); assert_eq!(r.gen_ascii_chars().take(16).count(), 16u); @@ -509,7 +509,7 @@ mod test { #[test] fn test_gen_vec() { - let mut r = task_rng(); + let mut r = thread_rng(); assert_eq!(r.gen_iter::().take(0).count(), 0u); assert_eq!(r.gen_iter::().take(10).count(), 10u); assert_eq!(r.gen_iter::().take(16).count(), 16u); @@ -517,7 +517,7 @@ mod test { #[test] fn test_choose() { - let mut r = task_rng(); + let mut r = thread_rng(); assert_eq!(r.choose(&[1i, 1, 1]).map(|&x|x), Some(1)); let v: &[int] = &[]; @@ -526,7 +526,7 @@ mod test { #[test] fn test_shuffle() { - let mut r = task_rng(); + let mut r = thread_rng(); let empty: &mut [int] = &mut []; r.shuffle(empty); let mut one = [1i]; @@ -545,8 +545,8 @@ mod test { } #[test] - fn test_task_rng() { - let mut r = task_rng(); + fn test_thread_rng() { + let mut r = thread_rng(); r.gen::(); let mut v = [1i, 1, 1]; r.shuffle(&mut v); @@ -574,7 +574,7 @@ mod test { let min_val = 1i; let max_val = 100i; - let mut r = task_rng(); + let mut r = thread_rng(); let vals = range(min_val, max_val).collect::>(); let small_sample = sample(&mut r, vals.iter(), 5); let large_sample = sample(&mut r, vals.iter(), vals.len() + 5); @@ -589,7 +589,7 @@ mod test { #[test] fn test_std_rng_seeded() { - let s = task_rng().gen_iter::().take(256).collect::>(); + let s = thread_rng().gen_iter::().take(256).collect::>(); let mut ra: StdRng = SeedableRng::from_seed(s.as_slice()); let mut rb: StdRng = SeedableRng::from_seed(s.as_slice()); assert!(order::equals(ra.gen_ascii_chars().take(100), @@ -598,7 +598,7 @@ mod test { #[test] fn test_std_rng_reseed() { - let s = task_rng().gen_iter::().take(256).collect::>(); + let s = thread_rng().gen_iter::().take(256).collect::>(); let mut r: StdRng = SeedableRng::from_seed(s.as_slice()); let string1 = r.gen_ascii_chars().take(100).collect::(); diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index 76d05d9bfd4..7b6a6be7885 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -394,7 +394,7 @@ mod tests { for _ in range(0, N) { let tx = tx.clone(); spawn(move|| { - let mut rng = rand::task_rng(); + let mut rng = rand::thread_rng(); for _ in range(0, M) { if rng.gen_weighted_bool(N) { drop(R.write()); diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index f575d3d6c67..f22a4b5c6ed 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -724,7 +724,7 @@ pub fn fresh_name(src: &ast::Ident) -> ast::Name { // following: debug version. Could work in final except that it's incompatible with // good error messages and uses of struct names in ambiguous could-be-binding // locations. Also definitely destroys the guarantee given above about ptr_eq. - /*let num = rand::task_rng().gen_uint_range(0,0xffff); + /*let num = rand::thread_rng().gen_uint_range(0,0xffff); gensym(format!("{}_{}",ident_to_string(src),num))*/ } diff --git a/src/test/bench/core-std.rs b/src/test/bench/core-std.rs index 16129593485..d9a4aede7d7 100644 --- a/src/test/bench/core-std.rs +++ b/src/test/bench/core-std.rs @@ -83,7 +83,7 @@ fn read_line() { } fn vec_plus() { - let mut r = rand::task_rng(); + let mut r = rand::thread_rng(); let mut v = Vec::new(); let mut i = 0; @@ -101,7 +101,7 @@ fn vec_plus() { } fn vec_append() { - let mut r = rand::task_rng(); + let mut r = rand::thread_rng(); let mut v = Vec::new(); let mut i = 0; @@ -122,7 +122,7 @@ fn vec_append() { } fn vec_push_all() { - let mut r = rand::task_rng(); + let mut r = rand::thread_rng(); let mut v = Vec::new(); for i in range(0u, 1500) { diff --git a/src/test/compile-fail/task-rng-isnt-sendable.rs b/src/test/compile-fail/task-rng-isnt-sendable.rs index d96599404de..f673c3b7978 100644 --- a/src/test/compile-fail/task-rng-isnt-sendable.rs +++ b/src/test/compile-fail/task-rng-isnt-sendable.rs @@ -8,14 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ensure that the TaskRng isn't/doesn't become accidentally sendable. +// ensure that the ThreadRng isn't/doesn't become accidentally sendable. use std::rand; fn test_send() {} pub fn main() { - test_send::(); + test_send::(); //~^ ERROR `core::kinds::Send` is not implemented //~^^ ERROR `core::kinds::Send` is not implemented } diff --git a/src/test/run-make/unicode-input/multiple_files.rs b/src/test/run-make/unicode-input/multiple_files.rs index 2aa4264225c..88d8f10e709 100644 --- a/src/test/run-make/unicode-input/multiple_files.rs +++ b/src/test/run-make/unicode-input/multiple_files.rs @@ -10,7 +10,7 @@ use std::{char, os}; use std::io::{File, Command}; -use std::rand::{task_rng, Rng}; +use std::rand::{thread_rng, Rng}; // creates unicode_input_multiple_files_{main,chars}.rs, where the // former imports the latter. `_chars` just contains an identifier @@ -19,7 +19,7 @@ use std::rand::{task_rng, Rng}; // this span used to upset the compiler). fn random_char() -> char { - let mut rng = task_rng(); + let mut rng = thread_rng(); // a subset of the XID_start Unicode table (ensuring that the // compiler doesn't fail with an "unrecognised token" error) let (lo, hi): (u32, u32) = match rng.gen_range(1u32, 4u32 + 1) { diff --git a/src/test/run-make/unicode-input/span_length.rs b/src/test/run-make/unicode-input/span_length.rs index 7b096d7d583..f83734b1502 100644 --- a/src/test/run-make/unicode-input/span_length.rs +++ b/src/test/run-make/unicode-input/span_length.rs @@ -10,7 +10,7 @@ use std::{char, os}; use std::io::{File, Command}; -use std::rand::{task_rng, Rng}; +use std::rand::{thread_rng, Rng}; // creates a file with `fn main() { }` and checks the // compiler emits a span of the appropriate length (for the @@ -18,7 +18,7 @@ use std::rand::{task_rng, Rng}; // points, but should be the number of graphemes (FIXME #7043) fn random_char() -> char { - let mut rng = task_rng(); + let mut rng = thread_rng(); // a subset of the XID_start Unicode table (ensuring that the // compiler doesn't fail with an "unrecognised token" error) let (lo, hi): (u32, u32) = match rng.gen_range(1u32, 4u32 + 1) { @@ -38,7 +38,7 @@ fn main() { let main_file = tmpdir.join("span_main.rs"); for _ in range(0u, 100) { - let n = task_rng().gen_range(3u, 20); + let n = thread_rng().gen_range(3u, 20); { let _ = write!(&mut File::create(&main_file).unwrap(), diff --git a/src/test/run-pass/vector-sort-panic-safe.rs b/src/test/run-pass/vector-sort-panic-safe.rs index fe89c7532ee..6ff1cffb4a4 100644 --- a/src/test/run-pass/vector-sort-panic-safe.rs +++ b/src/test/run-pass/vector-sort-panic-safe.rs @@ -10,7 +10,7 @@ use std::task; use std::sync::atomic::{AtomicUint, INIT_ATOMIC_UINT, Relaxed}; -use std::rand::{task_rng, Rng, Rand}; +use std::rand::{thread_rng, Rng, Rand}; const REPEATS: uint = 5; const MAX_LEN: uint = 32; @@ -59,7 +59,7 @@ pub fn main() { // IDs start from 0. creation_count.store(0, Relaxed); - let main = task_rng().gen_iter::() + let main = thread_rng().gen_iter::() .take(len) .collect::>(); -- cgit 1.4.1-3-g733a5 From ac095351fba2750bddd84c3f434d16c1ed7f1640 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Mon, 29 Dec 2014 16:52:10 +1300 Subject: Fallout from globs/re-export/shadowing change --- src/libcollections/slice.rs | 5 ++++- src/libcollections/str.rs | 2 +- src/libstd/c_str.rs | 3 ++- src/libstd/comm/mod.rs | 5 +++-- src/libstd/io/mem.rs | 4 ++-- src/libstd/io/mod.rs | 4 ++-- src/libstd/io/net/pipe.rs | 2 +- src/libstd/io/net/tcp.rs | 7 +++++-- src/libstd/io/net/udp.rs | 4 ++-- src/libstd/io/process.rs | 6 ++++-- src/libstd/io/util.rs | 2 +- src/libstd/num/mod.rs | 6 ++++-- src/libstd/path/posix.rs | 2 +- src/libstd/sync/atomic.rs | 2 +- 14 files changed, 33 insertions(+), 21 deletions(-) (limited to 'src/libstd/sync') diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index d6d94f57acf..cca071836dd 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -1343,7 +1343,10 @@ pub mod raw { #[cfg(test)] mod tests { use std::boxed::Box; - use prelude::*; + use prelude::{Some, None, range, Vec, ToString, Clone, Greater, Less, Equal}; + use prelude::{SliceExt, Iterator, IteratorExt, DoubleEndedIteratorExt}; + use prelude::{OrdSliceExt, CloneSliceExt, PartialEqSliceExt, AsSlice}; + use prelude::{RandomAccessIterator, Ord, VectorVector}; use core::cell::Cell; use core::default::Default; use core::mem; diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index bccd2a1198a..5b26dc29478 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -3331,7 +3331,7 @@ mod tests { #[cfg(test)] mod bench { use super::*; - use prelude::*; + use prelude::{SliceExt, IteratorExt, DoubleEndedIteratorExt}; use test::Bencher; use test::black_box; diff --git a/src/libstd/c_str.rs b/src/libstd/c_str.rs index ffe19203769..39c57b99b36 100644 --- a/src/libstd/c_str.rs +++ b/src/libstd/c_str.rs @@ -537,7 +537,8 @@ pub unsafe fn from_c_multistring(buf: *const libc::c_char, #[cfg(test)] mod tests { use super::*; - use prelude::*; + use prelude::{spawn, Some, None, Option, FnOnce, ToString, CloneSliceExt}; + use prelude::{Clone, RawPtr, Iterator, SliceExt, StrExt}; use ptr; use thread::Thread; use libc; diff --git a/src/libstd/comm/mod.rs b/src/libstd/comm/mod.rs index 4b0b21ec8d8..a405627aecc 100644 --- a/src/libstd/comm/mod.rs +++ b/src/libstd/comm/mod.rs @@ -336,7 +336,8 @@ macro_rules! test { use super::*; use comm::*; use thread::Thread; - use prelude::*; + use prelude::{Ok, Err, spawn, range, drop, Box, Some, None, Option}; + use prelude::{Vec, Buffer, from_str, Clone}; $(#[$a])* #[test] fn f() { $b } } @@ -1046,7 +1047,7 @@ unsafe impl kinds::Sync for RacyCell { } // Oh dear #[cfg(test)] mod test { use super::*; - use prelude::*; + use prelude::{spawn, range, Some, None, from_str, Clone, Str}; use os; pub fn stress_factor() -> uint { diff --git a/src/libstd/io/mem.rs b/src/libstd/io/mem.rs index 01151059530..ccece874ce7 100644 --- a/src/libstd/io/mem.rs +++ b/src/libstd/io/mem.rs @@ -400,8 +400,8 @@ impl<'a> Buffer for BufReader<'a> { mod test { extern crate "test" as test_crate; use super::*; - use io::*; - use prelude::*; + use io::{SeekSet, SeekCur, SeekEnd, Reader, Writer, Seek}; + use prelude::{Ok, Err, range, Vec, Buffer, AsSlice, SliceExt, IteratorExt, CloneSliceExt}; use io; use self::test_crate::Bencher; diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index b6f8bb25b65..82aa00dc98e 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -1959,8 +1959,8 @@ impl fmt::Show for FilePermission { #[cfg(test)] mod tests { use self::BadReaderBehavior::*; - use super::{IoResult, Reader, MemReader, NoProgress, InvalidInput}; - use prelude::*; + use super::{IoResult, Reader, MemReader, NoProgress, InvalidInput, Writer}; + use prelude::{Ok, Vec, Buffer, CloneSliceExt}; use uint; #[deriving(Clone, PartialEq, Show)] diff --git a/src/libstd/io/net/pipe.rs b/src/libstd/io/net/pipe.rs index 4afc72cde71..93f37a8c98f 100644 --- a/src/libstd/io/net/pipe.rs +++ b/src/libstd/io/net/pipe.rs @@ -269,7 +269,7 @@ mod tests { use super::*; use io::*; use io::test::*; - use prelude::*; + use prelude::{Ok, Err, spawn, range, drop, Some, None, channel, Send, FnOnce, Clone}; use io::fs::PathExtensions; use time::Duration; diff --git a/src/libstd/io/net/tcp.rs b/src/libstd/io/net/tcp.rs index 6adb5387f2e..24cf06973cc 100644 --- a/src/libstd/io/net/tcp.rs +++ b/src/libstd/io/net/tcp.rs @@ -484,9 +484,12 @@ impl sys_common::AsInner for TcpAcceptor { mod test { use io::net::tcp::*; use io::net::ip::*; - use io::*; + use io::{EndOfFile, TimedOut, IoError, ShortWrite, OtherIoError, ConnectionAborted}; + use io::{ConnectionRefused, ConnectionReset, BrokenPipe, NotConnected}; + use io::{PermissionDenied, Listener, Acceptor}; use io::test::*; - use prelude::*; + use prelude::{Ok, Err, spawn, range, drop, Some, None, channel, Clone}; + use prelude::{Reader, Writer, IteratorExt}; // FIXME #11530 this fails on android because tests are run as root #[cfg_attr(any(windows, target_os = "android"), ignore)] diff --git a/src/libstd/io/net/udp.rs b/src/libstd/io/net/udp.rs index a36703172c3..a165232c5f5 100644 --- a/src/libstd/io/net/udp.rs +++ b/src/libstd/io/net/udp.rs @@ -250,9 +250,9 @@ impl Writer for UdpStream { mod test { use super::*; use io::net::ip::*; - use io::*; + use io::{ShortWrite, IoError, TimedOut, PermissionDenied}; use io::test::*; - use prelude::*; + use prelude::{Ok, Err, spawn, range, drop, Some, None, channel, Clone, Reader, Writer}; // FIXME #11530 this fails on android because tests are run as root #[cfg_attr(any(windows, target_os = "android"), ignore)] diff --git a/src/libstd/io/process.rs b/src/libstd/io/process.rs index 93aa627ffba..9e0c76e4e79 100644 --- a/src/libstd/io/process.rs +++ b/src/libstd/io/process.rs @@ -745,8 +745,10 @@ mod tests { use super::*; use io::timer::*; - use io::*; - use prelude::*; + use io::{Truncate, Write, TimedOut, timer, process, FileNotFound}; + use prelude::{Ok, Err, spawn, range, drop, Box, Some, None, Option, Vec, Buffer}; + use prelude::{from_str, Path, String, channel, Reader, Writer, Clone, Slice}; + use prelude::{SliceExt, Str, StrExt, AsSlice, ToString, GenericPath}; use io::fs::PathExtensions; use time::Duration; use str; diff --git a/src/libstd/io/util.rs b/src/libstd/io/util.rs index 18fabcbd1a2..79a2b8b84f0 100644 --- a/src/libstd/io/util.rs +++ b/src/libstd/io/util.rs @@ -280,7 +280,7 @@ mod test { use io; use boxed::Box; use super::*; - use prelude::*; + use prelude::{Ok, range, Vec, Buffer, Writer, Reader, ToString, AsSlice}; #[test] fn test_limit_reader_unlimited() { diff --git a/src/libstd/num/mod.rs b/src/libstd/num/mod.rs index 7c8763979bb..48ff1a364e9 100644 --- a/src/libstd/num/mod.rs +++ b/src/libstd/num/mod.rs @@ -147,8 +147,10 @@ pub fn test_num(ten: T, two: T) where #[cfg(test)] mod tests { - use prelude::*; - use super::*; + use prelude::{range, Some, None, Option, IteratorExt}; + use super::{from_int, from_uint, from_i32, from_i64, from_u64, from_u32}; + use super::{from_f64, from_f32, from_u16, from_i16, from_u8, from_i8, Int}; + use super::{cast, NumCast, ToPrimitive, FromPrimitive, UnsignedInt}; use i8; use i16; use i32; diff --git a/src/libstd/path/posix.rs b/src/libstd/path/posix.rs index d941665f048..60f147eac9b 100644 --- a/src/libstd/path/posix.rs +++ b/src/libstd/path/posix.rs @@ -1239,7 +1239,7 @@ mod bench { extern crate test; use self::test::Bencher; use super::*; - use prelude::*; + use prelude::{Clone, GenericPath}; #[bench] fn join_home_dir(b: &mut Bencher) { diff --git a/src/libstd/sync/atomic.rs b/src/libstd/sync/atomic.rs index 26778ef70b3..bdf947438f3 100644 --- a/src/libstd/sync/atomic.rs +++ b/src/libstd/sync/atomic.rs @@ -180,7 +180,7 @@ impl Drop for AtomicOption { #[cfg(test)] mod test { - use prelude::*; + use prelude::{Some, None}; use super::*; #[test] -- cgit 1.4.1-3-g733a5 From 76e5ed655c762b812c3da4749a55f1bb1b52c787 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 8 Dec 2014 20:20:03 -0800 Subject: std: Return Result from RWLock/Mutex methods All of the current std::sync primitives have poisoning enable which means that when a task fails inside of a write-access lock then all future attempts to acquire the lock will fail. This strategy ensures that stale data whose invariants are possibly not upheld are never viewed by other tasks to help propagate unexpected panics (bugs in a program) among tasks. Currently there is no way to test whether a mutex or rwlock is poisoned. One method would be to duplicate all the methods with a sister foo_catch function, for example. This pattern is, however, against our [error guidelines][errors]. As a result, this commit exposes the fact that a task has failed internally through the return value of a `Result`. [errors]: https://github.com/rust-lang/rfcs/blob/master/text/0236-error-conventions.md#do-not-provide-both-result-and-fail-variants All methods now return a `LockResult` or a `TryLockResult` which communicates whether the lock was poisoned or not. In a `LockResult`, both the `Ok` and `Err` variants contains the `MutexGuard` that is being returned in order to allow access to the data if poisoning is not desired. This also means that the lock is *always* held upon returning from `.lock()`. A new type, `PoisonError`, was added with one method `into_guard` which can consume the assertion that a lock is poisoned to gain access to the underlying data. This is a breaking change because the signatures of these methods have changed, often incompatible ways. One major difference is that the `wait` methods on a condition variable now consume the guard and return it in as a `LockResult` to indicate whether the lock was poisoned while waiting. Most code can be updated by calling `.unwrap()` on the return value of `.lock()`. [breaking-change] --- src/doc/intro.md | 2 +- src/liballoc/arc.rs | 4 +- src/librustc_trans/back/write.rs | 6 +- src/libstd/comm/shared.rs | 4 +- src/libstd/comm/sync.rs | 26 +- src/libstd/io/stdio.rs | 20 +- src/libstd/sync/barrier.rs | 4 +- src/libstd/sync/condvar.rs | 99 ++++--- src/libstd/sync/mod.rs | 15 +- src/libstd/sync/mutex.rs | 243 ++++++++++------ src/libstd/sync/poison.rs | 115 +++++++- src/libstd/sync/rwlock.rs | 306 +++++++++++---------- src/libstd/sync/semaphore.rs | 6 +- src/libstd/sync/task_pool.rs | 2 +- src/libstd/sys/common/helper_thread.rs | 10 +- src/libstd/thread.rs | 7 +- src/libstd/thread_local/mod.rs | 13 +- src/test/bench/msgsend-ring-mutex-arcs.rs | 6 +- .../run-pass/match-ref-binding-in-guard-3256.rs | 14 +- src/test/run-pass/writealias.rs | 14 +- 20 files changed, 572 insertions(+), 344 deletions(-) (limited to 'src/libstd/sync') diff --git a/src/doc/intro.md b/src/doc/intro.md index 5be97034357..a4e9d85bffd 100644 --- a/src/doc/intro.md +++ b/src/doc/intro.md @@ -483,7 +483,7 @@ fn main() { for i in range(0u, 3u) { let number = numbers.clone(); Thread::spawn(move || { - let mut array = number.lock(); + let mut array = number.lock().unwrap(); (*array)[i] += 1; diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 3e235caab18..13ee8c26075 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -58,7 +58,7 @@ //! let five = five.clone(); //! //! Thread::spawn(move || { -//! let mut number = five.lock(); +//! let mut number = five.lock().unwrap(); //! //! *number += 1; //! @@ -722,7 +722,7 @@ mod tests { let a = Arc::new(Cycle { x: Mutex::new(None) }); let b = a.clone().downgrade(); - *a.x.lock() = Some(b); + *a.x.lock().unwrap() = Some(b); // hopefully we don't double-free (or leak)... } diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 513b955da3f..99e11bf5202 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -98,7 +98,7 @@ impl SharedEmitter { } fn dump(&mut self, handler: &Handler) { - let mut buffer = self.buffer.lock(); + let mut buffer = self.buffer.lock().unwrap(); for diag in buffer.iter() { match diag.code { Some(ref code) => { @@ -123,7 +123,7 @@ impl Emitter for SharedEmitter { msg: &str, code: Option<&str>, lvl: Level) { assert!(cmsp.is_none(), "SharedEmitter doesn't support spans"); - self.buffer.lock().push(Diagnostic { + self.buffer.lock().unwrap().push(Diagnostic { msg: msg.to_string(), code: code.map(|s| s.to_string()), lvl: lvl, @@ -915,7 +915,7 @@ fn run_work_multithreaded(sess: &Session, loop { // Avoid holding the lock for the entire duration of the match. - let maybe_work = work_items_arc.lock().pop(); + let maybe_work = work_items_arc.lock().unwrap().pop(); match maybe_work { Some(work) => { execute_work_item(&cgcx, work); diff --git a/src/libstd/comm/shared.rs b/src/libstd/comm/shared.rs index 1022694e634..3f23ec5dc66 100644 --- a/src/libstd/comm/shared.rs +++ b/src/libstd/comm/shared.rs @@ -86,7 +86,7 @@ impl Packet { // and that could cause problems on platforms where it is // represented by opaque data structure pub fn postinit_lock(&self) -> MutexGuard<()> { - self.select_lock.lock() + self.select_lock.lock().unwrap() } // This function is used at the creation of a shared packet to inherit a @@ -435,7 +435,7 @@ impl Packet { // about looking at and dealing with to_wake. Once we have acquired the // lock, we are guaranteed that inherit_blocker is done. { - let _guard = self.select_lock.lock(); + let _guard = self.select_lock.lock().unwrap(); } // Like the stream implementation, we want to make sure that the count diff --git a/src/libstd/comm/sync.rs b/src/libstd/comm/sync.rs index 88338849965..82ec1814ebd 100644 --- a/src/libstd/comm/sync.rs +++ b/src/libstd/comm/sync.rs @@ -121,9 +121,9 @@ fn wait<'a, 'b, T: Send>(lock: &'a Mutex>, NoneBlocked => {} _ => unreachable!(), } - drop(guard); // unlock - wait_token.wait(); // block - lock.lock() // relock + drop(guard); // unlock + wait_token.wait(); // block + lock.lock().unwrap() // relock } /// Wakes up a thread, dropping the lock at the correct time @@ -161,7 +161,7 @@ impl Packet { fn acquire_send_slot(&self) -> MutexGuard> { let mut node = Node { token: None, next: 0 as *mut Node }; loop { - let mut guard = self.lock.lock(); + let mut guard = self.lock.lock().unwrap(); // are we ready to go? if guard.disconnected || guard.buf.size() < guard.buf.cap() { return guard; @@ -202,7 +202,7 @@ impl Packet { } pub fn try_send(&self, t: T) -> Result<(), super::TrySendError> { - let mut guard = self.lock.lock(); + let mut guard = self.lock.lock().unwrap(); if guard.disconnected { Err(super::RecvDisconnected(t)) } else if guard.buf.size() == guard.buf.cap() { @@ -239,7 +239,7 @@ impl Packet { // When reading this, remember that there can only ever be one receiver at // time. pub fn recv(&self) -> Result { - let mut guard = self.lock.lock(); + let mut guard = self.lock.lock().unwrap(); // Wait for the buffer to have something in it. No need for a while loop // because we're the only receiver. @@ -258,7 +258,7 @@ impl Packet { } pub fn try_recv(&self) -> Result { - let mut guard = self.lock.lock(); + let mut guard = self.lock.lock().unwrap(); // Easy cases first if guard.disconnected { return Err(Disconnected) } @@ -315,7 +315,7 @@ impl Packet { } // Not much to do other than wake up a receiver if one's there - let mut guard = self.lock.lock(); + let mut guard = self.lock.lock().unwrap(); if guard.disconnected { return } guard.disconnected = true; match mem::replace(&mut guard.blocker, NoneBlocked) { @@ -326,7 +326,7 @@ impl Packet { } pub fn drop_port(&self) { - let mut guard = self.lock.lock(); + let mut guard = self.lock.lock().unwrap(); if guard.disconnected { return } guard.disconnected = true; @@ -372,14 +372,14 @@ impl Packet { // If Ok, the value is whether this port has data, if Err, then the upgraded // port needs to be checked instead of this one. pub fn can_recv(&self) -> bool { - let guard = self.lock.lock(); + let guard = self.lock.lock().unwrap(); guard.disconnected || guard.buf.size() > 0 } // Attempts to start selection on this port. This can either succeed or fail // because there is data waiting. pub fn start_selection(&self, token: SignalToken) -> StartResult { - let mut guard = self.lock.lock(); + let mut guard = self.lock.lock().unwrap(); if guard.disconnected || guard.buf.size() > 0 { Abort } else { @@ -397,7 +397,7 @@ impl Packet { // // The return value indicates whether there's data on this port. pub fn abort_selection(&self) -> bool { - let mut guard = self.lock.lock(); + let mut guard = self.lock.lock().unwrap(); match mem::replace(&mut guard.blocker, NoneBlocked) { NoneBlocked => true, BlockedSender(token) => { @@ -413,7 +413,7 @@ impl Packet { impl Drop for Packet { fn drop(&mut self) { assert_eq!(self.channels.load(atomic::SeqCst), 0); - let mut guard = self.lock.lock(); + let mut guard = self.lock.lock().unwrap(); assert!(guard.queue.dequeue().is_none()); assert!(guard.canceled.is_none()); } diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index 6bd721599f3..6c8e4eea40f 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -146,7 +146,7 @@ impl StdinReader { /// ``` pub fn lock<'a>(&'a mut self) -> StdinReaderGuard<'a> { StdinReaderGuard { - inner: self.inner.lock() + inner: self.inner.lock().unwrap() } } @@ -155,7 +155,7 @@ impl StdinReader { /// The read is performed atomically - concurrent read calls in other /// threads will not interleave with this one. pub fn read_line(&mut self) -> IoResult { - self.inner.lock().0.read_line() + self.inner.lock().unwrap().0.read_line() } /// Like `Buffer::read_until`. @@ -163,7 +163,7 @@ impl StdinReader { /// The read is performed atomically - concurrent read calls in other /// threads will not interleave with this one. pub fn read_until(&mut self, byte: u8) -> IoResult> { - self.inner.lock().0.read_until(byte) + self.inner.lock().unwrap().0.read_until(byte) } /// Like `Buffer::read_char`. @@ -171,13 +171,13 @@ impl StdinReader { /// The read is performed atomically - concurrent read calls in other /// threads will not interleave with this one. pub fn read_char(&mut self) -> IoResult { - self.inner.lock().0.read_char() + self.inner.lock().unwrap().0.read_char() } } impl Reader for StdinReader { fn read(&mut self, buf: &mut [u8]) -> IoResult { - self.inner.lock().0.read(buf) + self.inner.lock().unwrap().0.read(buf) } // We have to manually delegate all of these because the default impls call @@ -185,23 +185,23 @@ impl Reader for StdinReader { // incur the costs of repeated locking). fn read_at_least(&mut self, min: uint, buf: &mut [u8]) -> IoResult { - self.inner.lock().0.read_at_least(min, buf) + self.inner.lock().unwrap().0.read_at_least(min, buf) } fn push_at_least(&mut self, min: uint, len: uint, buf: &mut Vec) -> IoResult { - self.inner.lock().0.push_at_least(min, len, buf) + self.inner.lock().unwrap().0.push_at_least(min, len, buf) } fn read_to_end(&mut self) -> IoResult> { - self.inner.lock().0.read_to_end() + self.inner.lock().unwrap().0.read_to_end() } fn read_le_uint_n(&mut self, nbytes: uint) -> IoResult { - self.inner.lock().0.read_le_uint_n(nbytes) + self.inner.lock().unwrap().0.read_le_uint_n(nbytes) } fn read_be_uint_n(&mut self, nbytes: uint) -> IoResult { - self.inner.lock().0.read_be_uint_n(nbytes) + self.inner.lock().unwrap().0.read_be_uint_n(nbytes) } } diff --git a/src/libstd/sync/barrier.rs b/src/libstd/sync/barrier.rs index 6cdb199819a..4091f0df395 100644 --- a/src/libstd/sync/barrier.rs +++ b/src/libstd/sync/barrier.rs @@ -69,7 +69,7 @@ impl Barrier { /// Barriers are re-usable after all threads have rendezvoused once, and can /// be used continuously. pub fn wait(&self) { - let mut lock = self.lock.lock(); + let mut lock = self.lock.lock().unwrap(); let local_gen = lock.generation_id; lock.count += 1; if lock.count < self.num_threads { @@ -77,7 +77,7 @@ impl Barrier { // http://en.wikipedia.org/wiki/Spurious_wakeup while local_gen == lock.generation_id && lock.count < self.num_threads { - self.cvar.wait(&lock); + lock = self.cvar.wait(lock).unwrap(); } } else { lock.count = 0; diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index f1940bfd829..3e17d8b6be1 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -11,7 +11,8 @@ use prelude::*; use sync::atomic::{mod, AtomicUint}; -use sync::{mutex, StaticMutexGuard}; +use sync::poison::{mod, LockResult}; +use sync::CondvarGuard; use sys_common::condvar as sys; use sys_common::mutex as sys_mutex; use time::Duration; @@ -44,16 +45,16 @@ use time::Duration; /// // Inside of our lock, spawn a new thread, and then wait for it to start /// Thread::spawn(move|| { /// let &(ref lock, ref cvar) = &*pair2; -/// let mut started = lock.lock(); +/// let mut started = lock.lock().unwrap(); /// *started = true; /// cvar.notify_one(); /// }).detach(); /// /// // wait for the thread to start up /// let &(ref lock, ref cvar) = &*pair; -/// let started = lock.lock(); +/// let mut started = lock.lock().unwrap(); /// while !*started { -/// cvar.wait(&started); +/// started = cvar.wait(started).unwrap(); /// } /// ``` pub struct Condvar { inner: Box } @@ -92,9 +93,9 @@ pub const CONDVAR_INIT: StaticCondvar = StaticCondvar { /// /// Note that this trait should likely not be implemented manually unless you /// really know what you're doing. -pub trait AsMutexGuard { +pub trait AsGuard { #[allow(missing_docs)] - unsafe fn as_mutex_guard(&self) -> &StaticMutexGuard; + fn as_guard(&self) -> CondvarGuard; } impl Condvar { @@ -113,8 +114,8 @@ impl Condvar { /// notification. /// /// This function will atomically unlock the mutex specified (represented by - /// `guard`) and block the current thread. This means that any calls to - /// `notify_*()` which happen logically after the mutex is unlocked are + /// `mutex_guard`) and block the current thread. This means that any calls + /// to `notify_*()` which happen logically after the mutex is unlocked are /// candidates to wake this thread up. When this function call returns, the /// lock specified will have been re-acquired. /// @@ -123,13 +124,20 @@ impl Condvar { /// the predicate must always be checked each time this function returns to /// protect against spurious wakeups. /// + /// # Failure + /// + /// This function will return an error if the mutex being waited on is + /// poisoned when this thread re-acquires the lock. For more information, + /// see information about poisoning on the Mutex type. + /// /// # Panics /// /// This function will `panic!()` if it is used with more than one mutex /// over time. Each condition variable is dynamically bound to exactly one /// mutex to ensure defined behavior across platforms. If this functionality /// is not desired, then unsafe primitives in `sys` are provided. - pub fn wait(&self, mutex_guard: &T) { + pub fn wait(&self, mutex_guard: T) + -> LockResult { unsafe { let me: &'static Condvar = &*(self as *const _); me.inner.wait(mutex_guard) @@ -156,8 +164,8 @@ impl Condvar { // provide. There are also additional concerns about the unix-specific // implementation which may need to be addressed. #[allow(dead_code)] - fn wait_timeout(&self, mutex_guard: &T, - dur: Duration) -> bool { + fn wait_timeout(&self, mutex_guard: T, dur: Duration) + -> LockResult<(T, bool)> { unsafe { let me: &'static Condvar = &*(self as *const _); me.inner.wait_timeout(mutex_guard, dur) @@ -194,13 +202,17 @@ impl StaticCondvar { /// notification. /// /// See `Condvar::wait`. - pub fn wait(&'static self, mutex_guard: &T) { - unsafe { - let lock = mutex_guard.as_mutex_guard(); - let sys = mutex::guard_lock(lock); - self.verify(sys); - self.inner.wait(sys); - (*mutex::guard_poison(lock)).check("mutex"); + pub fn wait(&'static self, mutex_guard: T) -> LockResult { + let poisoned = unsafe { + let cvar_guard = mutex_guard.as_guard(); + self.verify(cvar_guard.lock); + self.inner.wait(cvar_guard.lock); + cvar_guard.poisoned.get() + }; + if poisoned { + Err(poison::new_poison_error(mutex_guard)) + } else { + Ok(mutex_guard) } } @@ -209,15 +221,18 @@ impl StaticCondvar { /// /// See `Condvar::wait_timeout`. #[allow(dead_code)] // may want to stabilize this later, see wait_timeout above - fn wait_timeout(&'static self, mutex_guard: &T, - dur: Duration) -> bool { - unsafe { - let lock = mutex_guard.as_mutex_guard(); - let sys = mutex::guard_lock(lock); - self.verify(sys); - let ret = self.inner.wait_timeout(sys, dur); - (*mutex::guard_poison(lock)).check("mutex"); - return ret; + fn wait_timeout(&'static self, mutex_guard: T, dur: Duration) + -> LockResult<(T, bool)> { + let (poisoned, success) = unsafe { + let cvar_guard = mutex_guard.as_guard(); + self.verify(cvar_guard.lock); + let success = self.inner.wait_timeout(cvar_guard.lock, dur); + (cvar_guard.poisoned.get(), success) + }; + if poisoned { + Err(poison::new_poison_error((mutex_guard, success))) + } else { + Ok((mutex_guard, success)) } } @@ -288,12 +303,12 @@ mod tests { static C: StaticCondvar = CONDVAR_INIT; static M: StaticMutex = MUTEX_INIT; - let g = M.lock(); + let g = M.lock().unwrap(); spawn(move|| { - let _g = M.lock(); + let _g = M.lock().unwrap(); C.notify_one(); }); - C.wait(&g); + let g = C.wait(g).unwrap(); drop(g); unsafe { C.destroy(); M.destroy(); } } @@ -309,13 +324,13 @@ mod tests { let tx = tx.clone(); spawn(move|| { let &(ref lock, ref cond) = &*data; - let mut cnt = lock.lock(); + let mut cnt = lock.lock().unwrap(); *cnt += 1; if *cnt == N { tx.send(()); } while *cnt != 0 { - cond.wait(&cnt); + cnt = cond.wait(cnt).unwrap(); } tx.send(()); }); @@ -324,7 +339,7 @@ mod tests { let &(ref lock, ref cond) = &*data; rx.recv(); - let mut cnt = lock.lock(); + let mut cnt = lock.lock().unwrap(); *cnt = 0; cond.notify_all(); drop(cnt); @@ -339,13 +354,15 @@ mod tests { static C: StaticCondvar = CONDVAR_INIT; static M: StaticMutex = MUTEX_INIT; - let g = M.lock(); - assert!(!C.wait_timeout(&g, Duration::nanoseconds(1000))); + let g = M.lock().unwrap(); + let (g, success) = C.wait_timeout(g, Duration::nanoseconds(1000)).unwrap(); + assert!(!success); spawn(move|| { - let _g = M.lock(); + let _g = M.lock().unwrap(); C.notify_one(); }); - assert!(C.wait_timeout(&g, Duration::days(1))); + let (g, success) = C.wait_timeout(g, Duration::days(1)).unwrap(); + assert!(success); drop(g); unsafe { C.destroy(); M.destroy(); } } @@ -357,15 +374,15 @@ mod tests { static M2: StaticMutex = MUTEX_INIT; static C: StaticCondvar = CONDVAR_INIT; - let g = M1.lock(); + let mut g = M1.lock().unwrap(); spawn(move|| { - let _g = M1.lock(); + let _g = M1.lock().unwrap(); C.notify_one(); }); - C.wait(&g); + g = C.wait(g).unwrap(); drop(g); - C.wait(&M2.lock()); + C.wait(M2.lock().unwrap()).unwrap(); } } diff --git a/src/libstd/sync/mod.rs b/src/libstd/sync/mod.rs index 7605a6a96a0..3f95eac5090 100644 --- a/src/libstd/sync/mod.rs +++ b/src/libstd/sync/mod.rs @@ -17,16 +17,20 @@ #![experimental] +use sys_common::mutex as sys_mutex; + pub use alloc::arc::{Arc, Weak}; -pub use self::mutex::{Mutex, MutexGuard, StaticMutex, StaticMutexGuard, MUTEX_INIT}; +pub use self::mutex::{Mutex, MutexGuard, StaticMutex, StaticMutexGuard}; +pub use self::mutex::MUTEX_INIT; pub use self::rwlock::{RWLock, StaticRWLock, RWLOCK_INIT}; pub use self::rwlock::{RWLockReadGuard, RWLockWriteGuard}; pub use self::rwlock::{StaticRWLockReadGuard, StaticRWLockWriteGuard}; -pub use self::condvar::{Condvar, StaticCondvar, CONDVAR_INIT, AsMutexGuard}; +pub use self::condvar::{Condvar, StaticCondvar, CONDVAR_INIT, AsGuard}; pub use self::once::{Once, ONCE_INIT}; pub use self::semaphore::{Semaphore, SemaphoreGuard}; pub use self::barrier::Barrier; +pub use self::poison::{PoisonError, TryLockError, TryLockResult, LockResult}; pub use self::future::Future; pub use self::task_pool::TaskPool; @@ -41,3 +45,10 @@ mod poison; mod rwlock; mod semaphore; mod task_pool; + +/// Structure returned by `AsGuard` to wait on a condition variable. +// NB: defined here to all modules have access to these private fields. +pub struct CondvarGuard<'a> { + lock: &'a sys_mutex::Mutex, + poisoned: &'a poison::Flag, +} diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 4d2fbfc4055..621d7274062 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -12,7 +12,8 @@ use prelude::*; use cell::UnsafeCell; use kinds::marker; -use sync::{poison, AsMutexGuard}; +use sync::{AsGuard, CondvarGuard}; +use sync::poison::{mod, TryLockError, TryLockResult, LockResult}; use sys_common::mutex as sys; /// A mutual exclusion primitive useful for protecting shared data @@ -26,12 +27,23 @@ use sys_common::mutex as sys; /// /// # Poisoning /// -/// In order to prevent access to otherwise invalid data, each mutex will -/// propagate any panics which occur while the lock is held. Once a thread has -/// panicked while holding the lock, then all other threads will immediately -/// panic as well once they hold the lock. +/// The mutexes in this module implement a strategy called "poisoning" where a +/// mutex is considered poisoned whenever a thread panics while holding the +/// lock. Once a mutex is poisoned, all other tasks are unable to access the +/// data by default as it is likely tainted (some invariant is not being +/// upheld). /// -/// # Example +/// 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_guard` 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. +/// +/// # Examples /// /// ```rust /// use std::sync::{Arc, Mutex}; @@ -48,11 +60,14 @@ use sys_common::mutex as sys; /// let (tx, rx) = channel(); /// for _ in range(0u, 10) { /// let (data, tx) = (data.clone(), tx.clone()); -/// Thread::spawn(move|| { +/// Thread::spawn(move || { /// // The shared static 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. -/// let mut data = data.lock(); +/// // +/// // We unwrap() the return value to assert that we are not expecting +/// // tasks to ever fail while holding the lock. +/// let mut data = data.lock().unwrap(); /// *data += 1; /// if *data == N { /// tx.send(()); @@ -63,6 +78,35 @@ use sys_common::mutex as sys; /// /// rx.recv(); /// ``` +/// +/// To recover from a poisoned mutex: +/// +/// ```rust +/// use std::sync::{Arc, Mutex}; +/// use std::thread::Thread; +/// +/// let lock = Arc::new(Mutex::new(0u)); +/// 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 _lock = 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_guard(), +/// }; +/// +/// *guard += 1; +/// ``` pub struct Mutex { // Note that this static mutex is in a *box*, not inlined into the struct // itself. Once a native mutex has been used once, its address can never @@ -93,14 +137,14 @@ unsafe impl Sync for Mutex { } /// static LOCK: StaticMutex = MUTEX_INIT; /// /// { -/// let _g = LOCK.lock(); +/// let _g = LOCK.lock().unwrap(); /// // do some productive work /// } /// // lock is unlocked here. /// ``` pub struct StaticMutex { lock: sys::Mutex, - poison: UnsafeCell, + poison: poison::Flag, } unsafe impl Sync for StaticMutex {} @@ -114,24 +158,27 @@ unsafe impl Sync for StaticMutex {} pub struct MutexGuard<'a, T: 'a> { // funny underscores due to how Deref/DerefMut currently work (they // disregard field privacy). - __lock: &'a Mutex, - __guard: StaticMutexGuard, + __inner: Guard<'a, Mutex>, } /// An RAII implementation of a "scoped lock" of a static mutex. When this /// structure is dropped (falls out of scope), the lock will be unlocked. #[must_use] pub struct StaticMutexGuard { - lock: &'static sys::Mutex, - marker: marker::NoSend, - poison: poison::Guard<'static>, + inner: Guard<'static, StaticMutex>, +} + +struct Guard<'a, T: 'a> { + inner: &'a T, + poison: poison::Guard, + marker: marker::NoSend, // even if 'a is static, this cannot be sent } /// Static initialization of a mutex. This constant can be used to initialize /// other mutex constants. pub const MUTEX_INIT: StaticMutex = StaticMutex { lock: sys::MUTEX_INIT, - poison: UnsafeCell { value: poison::Flag { failed: false } }, + poison: poison::FLAG_INIT, }; impl Mutex { @@ -150,15 +197,13 @@ impl Mutex { /// 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. /// - /// # Panics + /// # Failure /// /// If another user of this mutex panicked while holding the mutex, then - /// this call will immediately panic once the mutex is acquired. - pub fn lock(&self) -> MutexGuard { - unsafe { - let lock: &'static StaticMutex = &*(&*self.inner as *const _); - MutexGuard::new(self, lock.lock()) - } + /// this call will return an error once the mutex is acquired. + pub fn lock(&self) -> LockResult> { + unsafe { self.inner.lock.lock() } + MutexGuard::new(self) } /// Attempts to acquire this lock. @@ -169,17 +214,16 @@ impl Mutex { /// /// This function does not block. /// - /// # Panics + /// # Failure /// /// If another user of this mutex panicked while holding the mutex, then - /// this call will immediately panic if the mutex would otherwise be + /// this call will return failure if the mutex would otherwise be /// acquired. - pub fn try_lock(&self) -> Option> { - unsafe { - let lock: &'static StaticMutex = &*(&*self.inner as *const _); - lock.try_lock().map(|guard| { - MutexGuard::new(self, guard) - }) + pub fn try_lock(&self) -> TryLockResult> { + if unsafe { self.inner.lock.try_lock() } { + Ok(try!(MutexGuard::new(self))) + } else { + Err(TryLockError::WouldBlock) } } } @@ -196,17 +240,19 @@ impl Drop for Mutex { impl StaticMutex { /// Acquires this lock, see `Mutex::lock` - pub fn lock(&'static self) -> StaticMutexGuard { + #[inline] + pub fn lock(&'static self) -> LockResult { unsafe { self.lock.lock() } StaticMutexGuard::new(self) } /// Attempts to grab this lock, see `Mutex::try_lock` - pub fn try_lock(&'static self) -> Option { + #[inline] + pub fn try_lock(&'static self) -> TryLockResult { if unsafe { self.lock.try_lock() } { - Some(StaticMutexGuard::new(self)) + Ok(try!(StaticMutexGuard::new(self))) } else { - None + Err(TryLockError::WouldBlock) } } @@ -226,53 +272,85 @@ impl StaticMutex { } impl<'mutex, T> MutexGuard<'mutex, T> { - fn new(lock: &Mutex, guard: StaticMutexGuard) -> MutexGuard { - MutexGuard { __lock: lock, __guard: guard } + fn new(lock: &Mutex) -> LockResult> { + poison::map_result(Guard::new(lock), |guard| { + MutexGuard { __inner: guard } + }) } } -impl<'mutex, T> AsMutexGuard for MutexGuard<'mutex, T> { - unsafe fn as_mutex_guard(&self) -> &StaticMutexGuard { &self.__guard } +impl AsGuard for Mutex { + fn as_guard(&self) -> CondvarGuard { self.inner.as_guard() } +} + +impl<'mutex, T> AsGuard for MutexGuard<'mutex, T> { + fn as_guard(&self) -> CondvarGuard { + CondvarGuard { + lock: &self.__inner.inner.inner.lock, + poisoned: &self.__inner.inner.inner.poison, + } + } } impl<'mutex, T> Deref for MutexGuard<'mutex, T> { - fn deref<'a>(&'a self) -> &'a T { unsafe { &*self.__lock.data.get() } } + fn deref<'a>(&'a self) -> &'a T { + unsafe { &*self.__inner.inner.data.get() } + } } impl<'mutex, T> DerefMut for MutexGuard<'mutex, T> { fn deref_mut<'a>(&'a mut self) -> &'a mut T { - unsafe { &mut *self.__lock.data.get() } + unsafe { &mut *self.__inner.inner.data.get() } } } impl StaticMutexGuard { - fn new(lock: &'static StaticMutex) -> StaticMutexGuard { - unsafe { - let guard = StaticMutexGuard { - lock: &lock.lock, - marker: marker::NoSend, - poison: (*lock.poison.get()).borrow(), - }; - guard.poison.check("mutex"); - return guard; - } + #[inline] + fn new(lock: &'static StaticMutex) -> LockResult { + poison::map_result(Guard::new(lock), |guard| { + StaticMutexGuard { inner: guard } + }) } } -pub fn guard_lock(guard: &StaticMutexGuard) -> &sys::Mutex { guard.lock } -pub fn guard_poison(guard: &StaticMutexGuard) -> &poison::Guard { - &guard.poison +impl AsGuard for StaticMutex { + #[inline] + fn as_guard(&self) -> CondvarGuard { + CondvarGuard { lock: &self.lock, poisoned: &self.poison } + } } -impl AsMutexGuard for StaticMutexGuard { - unsafe fn as_mutex_guard(&self) -> &StaticMutexGuard { self } +impl AsGuard for StaticMutexGuard { + #[inline] + fn as_guard(&self) -> CondvarGuard { + CondvarGuard { + lock: &self.inner.inner.lock, + poisoned: &self.inner.inner.poison, + } + } +} + +impl<'a, T: AsGuard> Guard<'a, T> { + #[inline] + fn new(t: &T) -> LockResult> { + let data = t.as_guard(); + poison::map_result(data.poisoned.borrow(), |guard| { + Guard { + inner: t, + poison: guard, + marker: marker::NoSend, + } + }) + } } #[unsafe_destructor] -impl Drop for StaticMutexGuard { +impl<'a, T: AsGuard> Drop for Guard<'a, T> { + #[inline] fn drop(&mut self) { unsafe { - self.poison.done(); - self.lock.unlock(); + let data = self.inner.as_guard(); + data.poisoned.done(&self.poison); + data.lock.unlock(); } } } @@ -292,16 +370,16 @@ mod test { #[test] fn smoke() { let m = Mutex::new(()); - drop(m.lock()); - drop(m.lock()); + drop(m.lock().unwrap()); + drop(m.lock().unwrap()); } #[test] fn smoke_static() { static M: StaticMutex = MUTEX_INIT; unsafe { - drop(M.lock()); - drop(M.lock()); + drop(M.lock().unwrap()); + drop(M.lock().unwrap()); M.destroy(); } } @@ -316,7 +394,7 @@ mod test { fn inc() { for _ in range(0, J) { unsafe { - let _g = M.lock(); + let _g = M.lock().unwrap(); CNT += 1; } } @@ -343,7 +421,7 @@ mod test { #[test] fn try_lock() { let m = Mutex::new(()); - assert!(m.try_lock().is_some()); + *m.try_lock().unwrap() = (); } #[test] @@ -355,22 +433,21 @@ mod test { // wait until parent gets in rx.recv(); let &(ref lock, ref cvar) = &*packet2.0; - let mut lock = lock.lock(); + let mut lock = lock.lock().unwrap(); *lock = true; cvar.notify_one(); }); let &(ref lock, ref cvar) = &*packet.0; - let lock = lock.lock(); + let mut lock = lock.lock().unwrap(); tx.send(()); assert!(!*lock); while !*lock { - cvar.wait(&lock); + lock = cvar.wait(lock).unwrap(); } } #[test] - #[should_fail] fn test_arc_condvar_poison() { let packet = Packet(Arc::new((Mutex::new(1i), Condvar::new()))); let packet2 = Packet(packet.0.clone()); @@ -379,31 +456,35 @@ mod test { spawn(move|| { rx.recv(); let &(ref lock, ref cvar) = &*packet2.0; - let _g = lock.lock(); + let _g = lock.lock().unwrap(); cvar.notify_one(); // Parent should fail when it wakes up. panic!(); }); let &(ref lock, ref cvar) = &*packet.0; - let lock = lock.lock(); + let mut lock = lock.lock().unwrap(); tx.send(()); while *lock == 1 { - cvar.wait(&lock); + match cvar.wait(lock) { + Ok(l) => { + lock = l; + assert_eq!(*lock, 1); + } + Err(..) => break, + } } } #[test] - #[should_fail] fn test_mutex_arc_poison() { let arc = Arc::new(Mutex::new(1i)); let arc2 = arc.clone(); - let _ = Thread::spawn(move|| { - let lock = arc2.lock(); + Thread::spawn(move|| { + let lock = arc2.lock().unwrap(); assert_eq!(*lock, 2); }).join(); - let lock = arc.lock(); - assert_eq!(*lock, 1); + assert!(arc.lock().is_err()); } #[test] @@ -414,8 +495,8 @@ mod test { let arc2 = Arc::new(Mutex::new(arc)); let (tx, rx) = channel(); spawn(move|| { - let lock = arc2.lock(); - let lock2 = lock.deref().lock(); + let lock = arc2.lock().unwrap(); + let lock2 = lock.deref().lock().unwrap(); assert_eq!(*lock2, 1); tx.send(()); }); @@ -432,13 +513,13 @@ mod test { } impl Drop for Unwinder { fn drop(&mut self) { - *self.i.lock() += 1; + *self.i.lock().unwrap() += 1; } } let _u = Unwinder { i: arc2 }; panic!(); }).join(); - let lock = arc.lock(); + let lock = arc.lock().unwrap(); assert_eq!(*lock, 2); } } diff --git a/src/libstd/sync/poison.rs b/src/libstd/sync/poison.rs index ad08e9873fa..d99fd91d0ac 100644 --- a/src/libstd/sync/poison.rs +++ b/src/libstd/sync/poison.rs @@ -8,31 +8,120 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use prelude::*; + +use cell::UnsafeCell; +use error::FromError; +use fmt; use thread::Thread; -pub struct Flag { pub failed: bool } +pub struct Flag { failed: UnsafeCell } +pub const FLAG_INIT: Flag = Flag { failed: UnsafeCell { value: false } }; impl Flag { - pub fn borrow(&mut self) -> Guard { - Guard { flag: &mut self.failed, panicking: Thread::panicking() } + #[inline] + pub fn borrow(&self) -> LockResult { + let ret = Guard { panicking: Thread::panicking() }; + if unsafe { *self.failed.get() } { + Err(new_poison_error(ret)) + } else { + Ok(ret) + } + } + + #[inline] + pub fn done(&self, guard: &Guard) { + if !guard.panicking && Thread::panicking() { + unsafe { *self.failed.get() = true; } + } + } + + #[inline] + pub fn get(&self) -> bool { + unsafe { *self.failed.get() } } } -pub struct Guard<'a> { - flag: &'a mut bool, +#[allow(missing_copy_implementations)] +pub struct Guard { panicking: bool, } -impl<'a> Guard<'a> { - pub fn check(&self, name: &str) { - if *self.flag { - panic!("poisoned {} - another task failed inside", name); - } +/// A type of error which can be returned whenever a lock is acquired. +/// +/// Both Mutexes and RWLocks are poisoned whenever a task fails while the lock +/// is held. The precise semantics for when a lock is poisoned is documented on +/// each lock, but once a lock is poisoned then all future acquisitions will +/// return this error. +pub struct PoisonError { + guard: T, +} + +/// An enumeration of possible errors which can occur while calling the +/// `try_lock` method. +pub enum TryLockError { + /// The lock could not be acquired because another task failed while holding + /// the lock. + Poisoned(PoisonError), + /// The lock could not be acquired at this time because the operation would + /// otherwise block. + WouldBlock, +} + +/// A type alias for the result of a lock method which can be poisoned. +/// +/// The `Ok` variant of this result indicates that the primitive was not +/// poisoned, and the `Guard` is contained within. The `Err` variant indicates +/// that the primitive was poisoned. Note that the `Err` variant *also* carries +/// the associated guard, and it can be acquired through the `into_inner` +/// method. +pub type LockResult = Result>; + +/// A type alias for the result of a nonblocking locking method. +/// +/// For more information, see `LockResult`. A `TryLockResult` doesn't +/// necessarily hold the associated guard in the `Err` type as the lock may not +/// have been acquired for other reasons. +pub type TryLockResult = Result>; + +impl fmt::Show for PoisonError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + "poisoned lock: another task failed inside".fmt(f) + } +} + +impl PoisonError { + /// Consumes this error indicating that a lock is poisoned, returning the + /// underlying guard to allow access regardless. + pub fn into_guard(self) -> T { self.guard } +} + +impl FromError> for TryLockError { + fn from_error(err: PoisonError) -> TryLockError { + TryLockError::Poisoned(err) } +} - pub fn done(&mut self) { - if !self.panicking && Thread::panicking() { - *self.flag = true; +impl fmt::Show for TryLockError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + TryLockError::Poisoned(ref p) => p.fmt(f), + TryLockError::WouldBlock => { + "try_lock failed because the operation would block".fmt(f) + } } } } + +pub fn new_poison_error(guard: T) -> PoisonError { + PoisonError { guard: guard } +} + +pub fn map_result(result: LockResult, f: F) + -> LockResult + where F: FnOnce(T) -> U { + match result { + Ok(t) => Ok(f(t)), + Err(PoisonError { guard }) => Err(new_poison_error(f(guard))) + } +} diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index 76d05d9bfd4..f7632c4f8b5 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -10,10 +10,10 @@ use prelude::*; -use kinds::marker; use cell::UnsafeCell; +use kinds::marker; +use sync::poison::{mod, LockResult, TryLockError, TryLockResult}; use sys_common::rwlock as sys; -use sync::poison; /// A reader-writer lock /// @@ -28,12 +28,14 @@ use sync::poison; /// locking methods implement `Deref` (and `DerefMut` for the `write` methods) /// to allow access to the contained of the lock. /// +/// # Poisoning +/// /// RWLocks, like Mutexes, will become poisoned on panics. Note, however, that /// an RWLock may only be poisoned if a panic occurs while it is locked /// exclusively (write mode). If a panic occurs in any reader, then the lock /// will not be poisoned. /// -/// # Example +/// # Examples /// /// ``` /// use std::sync::RWLock; @@ -42,15 +44,15 @@ use sync::poison; /// /// // many reader locks can be held at once /// { -/// let r1 = lock.read(); -/// let r2 = lock.read(); +/// let r1 = lock.read().unwrap(); +/// let r2 = lock.read().unwrap(); /// assert_eq!(*r1, 5); /// assert_eq!(*r2, 5); /// } // read locks are dropped at this point /// /// // only one write lock may be held, however /// { -/// let mut w = lock.write(); +/// let mut w = lock.write().unwrap(); /// *w += 1; /// assert_eq!(*w, 6); /// } // write lock is dropped here @@ -77,18 +79,18 @@ unsafe impl Sync for RWLock {} /// static LOCK: StaticRWLock = RWLOCK_INIT; /// /// { -/// let _g = LOCK.read(); +/// let _g = LOCK.read().unwrap(); /// // ... shared read access /// } /// { -/// let _g = LOCK.write(); +/// let _g = LOCK.write().unwrap(); /// // ... exclusive write access /// } /// unsafe { LOCK.destroy() } // free all resources /// ``` pub struct StaticRWLock { - inner: sys::RWLock, - poison: UnsafeCell, + lock: sys::RWLock, + poison: poison::Flag, } unsafe impl Send for StaticRWLock {} @@ -96,41 +98,52 @@ unsafe impl Sync for StaticRWLock {} /// Constant initialization for a statically-initialized rwlock. pub const RWLOCK_INIT: StaticRWLock = StaticRWLock { - inner: sys::RWLOCK_INIT, - poison: UnsafeCell { value: poison::Flag { failed: false } }, + lock: sys::RWLOCK_INIT, + poison: poison::FLAG_INIT, }; /// RAII structure used to release the shared read access of a lock when /// dropped. #[must_use] pub struct RWLockReadGuard<'a, T: 'a> { - __lock: &'a RWLock, - __guard: StaticRWLockReadGuard, + __inner: ReadGuard<'a, RWLock>, } /// RAII structure used to release the exclusive write access of a lock when /// dropped. #[must_use] pub struct RWLockWriteGuard<'a, T: 'a> { - __lock: &'a RWLock, - __guard: StaticRWLockWriteGuard, + __inner: WriteGuard<'a, RWLock>, } /// RAII structure used to release the shared read access of a lock when /// dropped. #[must_use] pub struct StaticRWLockReadGuard { - lock: &'static sys::RWLock, - marker: marker::NoSend, + _inner: ReadGuard<'static, StaticRWLock>, } /// RAII structure used to release the exclusive write access of a lock when /// dropped. #[must_use] pub struct StaticRWLockWriteGuard { - lock: &'static sys::RWLock, - marker: marker::NoSend, - poison: poison::Guard<'static>, + _inner: WriteGuard<'static, StaticRWLock>, +} + +struct ReadGuard<'a, T: 'a> { + inner: &'a T, + marker: marker::NoSend, // even if 'a == static, cannot send +} + +struct WriteGuard<'a, T: 'a> { + inner: &'a T, + poison: poison::Guard, + marker: marker::NoSend, // even if 'a == static, cannot send +} + +#[doc(hidden)] +trait AsStaticRWLock { + fn as_static_rwlock(&self) -> &StaticRWLock; } impl RWLock { @@ -151,17 +164,15 @@ impl RWLock { /// Returns an RAII guard which will release this thread's shared access /// once it is dropped. /// - /// # Panics + /// # Failure /// - /// This function will panic if the RWLock is poisoned. An RWLock is - /// poisoned whenever a writer panics while holding an exclusive lock. The - /// panic will occur immediately after the lock has been acquired. + /// This function will return an error if the RWLock is poisoned. An RWLock + /// is poisoned whenever a writer panics while holding an exclusive lock. + /// The failure will occur immediately after the lock has been acquired. #[inline] - pub fn read(&self) -> RWLockReadGuard { - unsafe { - let lock: &'static StaticRWLock = &*(&*self.inner as *const _); - RWLockReadGuard::new(self, lock.read()) - } + pub fn read(&self) -> LockResult> { + unsafe { self.inner.lock.read() } + RWLockReadGuard::new(self) } /// Attempt to acquire this lock with shared read access. @@ -173,18 +184,18 @@ impl RWLock { /// guarantees with respect to the ordering of whether contentious readers /// or writers will acquire the lock first. /// - /// # Panics + /// # Failure /// - /// This function will panic if the RWLock is poisoned. An RWLock is - /// poisoned whenever a writer panics while holding an exclusive lock. A - /// panic will only occur if the lock is acquired. + /// This function will return an error if the RWLock is poisoned. An RWLock + /// is poisoned whenever a writer panics while holding an exclusive lock. An + /// error will only be returned if the lock would have otherwise been + /// acquired. #[inline] - pub fn try_read(&self) -> Option> { - unsafe { - let lock: &'static StaticRWLock = &*(&*self.inner as *const _); - lock.try_read().map(|guard| { - RWLockReadGuard::new(self, guard) - }) + pub fn try_read(&self) -> TryLockResult> { + if unsafe { self.inner.lock.try_read() } { + Ok(try!(RWLockReadGuard::new(self))) + } else { + Err(TryLockError::WouldBlock) } } @@ -197,17 +208,15 @@ impl RWLock { /// Returns an RAII guard which will drop the write access of this rwlock /// when dropped. /// - /// # Panics + /// # Failure /// - /// This function will panic if the RWLock is poisoned. An RWLock is - /// poisoned whenever a writer panics while holding an exclusive lock. The - /// panic will occur when the lock is acquired. + /// This function will return an error if the RWLock is poisoned. An RWLock + /// is poisoned whenever a writer panics while holding an exclusive lock. + /// An error will be returned when the lock is acquired. #[inline] - pub fn write(&self) -> RWLockWriteGuard { - unsafe { - let lock: &'static StaticRWLock = &*(&*self.inner as *const _); - RWLockWriteGuard::new(self, lock.write()) - } + pub fn write(&self) -> LockResult> { + unsafe { self.inner.lock.write() } + RWLockWriteGuard::new(self) } /// Attempt to lock this rwlock with exclusive write access. @@ -216,18 +225,18 @@ impl RWLock { /// to `write` would otherwise block. If successful, an RAII guard is /// returned. /// - /// # Panics + /// # Failure /// - /// This function will panic if the RWLock is poisoned. An RWLock is - /// poisoned whenever a writer panics while holding an exclusive lock. A - /// panic will only occur if the lock is acquired. + /// This function will return an error if the RWLock is poisoned. An RWLock + /// is poisoned whenever a writer panics while holding an exclusive lock. An + /// error will only be returned if the lock would have otherwise been + /// acquired. #[inline] - pub fn try_write(&self) -> Option> { - unsafe { - let lock: &'static StaticRWLock = &*(&*self.inner as *const _); - lock.try_write().map(|guard| { - RWLockWriteGuard::new(self, guard) - }) + pub fn try_write(&self) -> TryLockResult> { + if unsafe { self.inner.lock.try_read() } { + Ok(try!(RWLockWriteGuard::new(self))) + } else { + Err(TryLockError::WouldBlock) } } } @@ -235,7 +244,7 @@ impl RWLock { #[unsafe_destructor] impl Drop for RWLock { fn drop(&mut self) { - unsafe { self.inner.inner.destroy() } + unsafe { self.inner.lock.destroy() } } } @@ -245,8 +254,8 @@ impl StaticRWLock { /// /// See `RWLock::read`. #[inline] - pub fn read(&'static self) -> StaticRWLockReadGuard { - unsafe { self.inner.read() } + pub fn read(&'static self) -> LockResult { + unsafe { self.lock.read() } StaticRWLockReadGuard::new(self) } @@ -254,11 +263,11 @@ impl StaticRWLock { /// /// See `RWLock::try_read`. #[inline] - pub fn try_read(&'static self) -> Option { - if unsafe { self.inner.try_read() } { - Some(StaticRWLockReadGuard::new(self)) + pub fn try_read(&'static self) -> TryLockResult { + if unsafe { self.lock.try_read() } { + Ok(try!(StaticRWLockReadGuard::new(self))) } else { - None + Err(TryLockError::WouldBlock) } } @@ -267,8 +276,8 @@ impl StaticRWLock { /// /// See `RWLock::write`. #[inline] - pub fn write(&'static self) -> StaticRWLockWriteGuard { - unsafe { self.inner.write() } + pub fn write(&'static self) -> LockResult { + unsafe { self.lock.write() } StaticRWLockWriteGuard::new(self) } @@ -276,11 +285,11 @@ impl StaticRWLock { /// /// See `RWLock::try_write`. #[inline] - pub fn try_write(&'static self) -> Option { - if unsafe { self.inner.try_write() } { - Some(StaticRWLockWriteGuard::new(self)) + pub fn try_write(&'static self) -> TryLockResult { + if unsafe { self.lock.try_write() } { + Ok(try!(StaticRWLockWriteGuard::new(self))) } else { - None + Err(TryLockError::WouldBlock) } } @@ -291,69 +300,92 @@ impl StaticRWLock { /// of this lock. This method is required to be called to not leak memory on /// all platforms. pub unsafe fn destroy(&'static self) { - self.inner.destroy() + self.lock.destroy() } } impl<'rwlock, T> RWLockReadGuard<'rwlock, T> { - fn new(lock: &RWLock, guard: StaticRWLockReadGuard) - -> RWLockReadGuard { - RWLockReadGuard { __lock: lock, __guard: guard } + fn new(lock: &RWLock) -> LockResult> { + poison::map_result(ReadGuard::new(lock), |guard| { + RWLockReadGuard { __inner: guard } + }) } } impl<'rwlock, T> RWLockWriteGuard<'rwlock, T> { - fn new(lock: &RWLock, guard: StaticRWLockWriteGuard) - -> RWLockWriteGuard { - RWLockWriteGuard { __lock: lock, __guard: guard } + fn new(lock: &RWLock) -> LockResult> { + poison::map_result(WriteGuard::new(lock), |guard| { + RWLockWriteGuard { __inner: guard } + }) } } impl<'rwlock, T> Deref for RWLockReadGuard<'rwlock, T> { - fn deref(&self) -> &T { unsafe { &*self.__lock.data.get() } } + fn deref(&self) -> &T { unsafe { &*self.__inner.inner.data.get() } } } impl<'rwlock, T> Deref for RWLockWriteGuard<'rwlock, T> { - fn deref(&self) -> &T { unsafe { &*self.__lock.data.get() } } + fn deref(&self) -> &T { unsafe { &*self.__inner.inner.data.get() } } } impl<'rwlock, T> DerefMut for RWLockWriteGuard<'rwlock, T> { - fn deref_mut(&mut self) -> &mut T { unsafe { &mut *self.__lock.data.get() } } + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *self.__inner.inner.data.get() } + } } impl StaticRWLockReadGuard { - fn new(lock: &'static StaticRWLock) -> StaticRWLockReadGuard { - let guard = StaticRWLockReadGuard { - lock: &lock.inner, - marker: marker::NoSend, - }; - unsafe { (*lock.poison.get()).borrow().check("rwlock"); } - return guard; + #[inline] + fn new(lock: &'static StaticRWLock) -> LockResult { + poison::map_result(ReadGuard::new(lock), |guard| { + StaticRWLockReadGuard { _inner: guard } + }) } } impl StaticRWLockWriteGuard { - fn new(lock: &'static StaticRWLock) -> StaticRWLockWriteGuard { - unsafe { - let guard = StaticRWLockWriteGuard { - lock: &lock.inner, - marker: marker::NoSend, - poison: (*lock.poison.get()).borrow(), - }; - guard.poison.check("rwlock"); - return guard; - } + #[inline] + fn new(lock: &'static StaticRWLock) -> LockResult { + poison::map_result(WriteGuard::new(lock), |guard| { + StaticRWLockWriteGuard { _inner: guard } + }) + } +} + +impl AsStaticRWLock for RWLock { + #[inline] + fn as_static_rwlock(&self) -> &StaticRWLock { &*self.inner } +} +impl AsStaticRWLock for StaticRWLock { + #[inline] + fn as_static_rwlock(&self) -> &StaticRWLock { self } +} + +impl<'a, T: AsStaticRWLock> ReadGuard<'a, T> { + fn new(t: &'a T) -> LockResult> { + poison::map_result(t.as_static_rwlock().poison.borrow(), |_| { + ReadGuard { inner: t, marker: marker::NoSend } + }) + } +} + +impl<'a, T: AsStaticRWLock> WriteGuard<'a, T> { + fn new(t: &'a T) -> LockResult> { + poison::map_result(t.as_static_rwlock().poison.borrow(), |guard| { + WriteGuard { inner: t, marker: marker::NoSend, poison: guard } + }) } } #[unsafe_destructor] -impl Drop for StaticRWLockReadGuard { +impl<'a, T: AsStaticRWLock> Drop for ReadGuard<'a, T> { fn drop(&mut self) { - unsafe { self.lock.read_unlock(); } + unsafe { self.inner.as_static_rwlock().lock.read_unlock(); } } } #[unsafe_destructor] -impl Drop for StaticRWLockWriteGuard { +impl<'a, T: AsStaticRWLock> Drop for WriteGuard<'a, T> { fn drop(&mut self) { - self.poison.done(); - unsafe { self.lock.write_unlock(); } + let inner = self.inner.as_static_rwlock(); + inner.poison.done(&self.poison); + unsafe { inner.lock.write_unlock(); } } } @@ -368,19 +400,19 @@ mod tests { #[test] fn smoke() { let l = RWLock::new(()); - drop(l.read()); - drop(l.write()); - drop((l.read(), l.read())); - drop(l.write()); + drop(l.read().unwrap()); + drop(l.write().unwrap()); + drop((l.read().unwrap(), l.read().unwrap())); + drop(l.write().unwrap()); } #[test] fn static_smoke() { static R: StaticRWLock = RWLOCK_INIT; - drop(R.read()); - drop(R.write()); - drop((R.read(), R.read())); - drop(R.write()); + drop(R.read().unwrap()); + drop(R.write().unwrap()); + drop((R.read().unwrap(), R.read().unwrap())); + drop(R.write().unwrap()); unsafe { R.destroy(); } } @@ -397,9 +429,9 @@ mod tests { let mut rng = rand::task_rng(); for _ in range(0, M) { if rng.gen_weighted_bool(N) { - drop(R.write()); + drop(R.write().unwrap()); } else { - drop(R.read()); + drop(R.read().unwrap()); } } drop(tx); @@ -411,51 +443,47 @@ mod tests { } #[test] - #[should_fail] fn test_rw_arc_poison_wr() { let arc = Arc::new(RWLock::new(1i)); let arc2 = arc.clone(); - let _ = Thread::spawn(move|| { - let lock = arc2.write(); - assert_eq!(*lock, 2); + let _: Result = Thread::spawn(move|| { + let _lock = arc2.write().unwrap(); + panic!(); }).join(); - let lock = arc.read(); - assert_eq!(*lock, 1); + assert!(arc.read().is_err()); } #[test] - #[should_fail] fn test_rw_arc_poison_ww() { let arc = Arc::new(RWLock::new(1i)); let arc2 = arc.clone(); - let _ = Thread::spawn(move|| { - let lock = arc2.write(); - assert_eq!(*lock, 2); + let _: Result = Thread::spawn(move|| { + let _lock = arc2.write().unwrap(); + panic!(); }).join(); - let lock = arc.write(); - assert_eq!(*lock, 1); + assert!(arc.write().is_err()); } #[test] fn test_rw_arc_no_poison_rr() { let arc = Arc::new(RWLock::new(1i)); let arc2 = arc.clone(); - let _ = Thread::spawn(move|| { - let lock = arc2.read(); - assert_eq!(*lock, 2); + let _: Result = Thread::spawn(move|| { + let _lock = arc2.read().unwrap(); + panic!(); }).join(); - let lock = arc.read(); + let lock = arc.read().unwrap(); assert_eq!(*lock, 1); } #[test] fn test_rw_arc_no_poison_rw() { let arc = Arc::new(RWLock::new(1i)); let arc2 = arc.clone(); - let _ = Thread::spawn(move|| { - let lock = arc2.read(); - assert_eq!(*lock, 2); + let _: Result = Thread::spawn(move|| { + let _lock = arc2.read().unwrap(); + panic!() }).join(); - let lock = arc.write(); + let lock = arc.write().unwrap(); assert_eq!(*lock, 1); } @@ -466,7 +494,7 @@ mod tests { let (tx, rx) = channel(); Thread::spawn(move|| { - let mut lock = arc2.write(); + let mut lock = arc2.write().unwrap(); for _ in range(0u, 10) { let tmp = *lock; *lock = -1; @@ -481,7 +509,7 @@ mod tests { for _ in range(0u, 5) { let arc3 = arc.clone(); children.push(Thread::spawn(move|| { - let lock = arc3.read(); + let lock = arc3.read().unwrap(); assert!(*lock >= 0); })); } @@ -493,7 +521,7 @@ mod tests { // Wait for writer to finish rx.recv(); - let lock = arc.read(); + let lock = arc.read().unwrap(); assert_eq!(*lock, 10); } @@ -507,14 +535,14 @@ mod tests { } impl Drop for Unwinder { fn drop(&mut self) { - let mut lock = self.i.write(); + let mut lock = self.i.write().unwrap(); *lock += 1; } } let _u = Unwinder { i: arc2 }; panic!(); }).join(); - let lock = arc.read(); + let lock = arc.read().unwrap(); assert_eq!(*lock, 2); } } diff --git a/src/libstd/sync/semaphore.rs b/src/libstd/sync/semaphore.rs index 574b0f22bee..e3b683a6ccb 100644 --- a/src/libstd/sync/semaphore.rs +++ b/src/libstd/sync/semaphore.rs @@ -68,9 +68,9 @@ impl Semaphore { /// This method will block until the internal count of the semaphore is at /// least 1. pub fn acquire(&self) { - let mut count = self.lock.lock(); + let mut count = self.lock.lock().unwrap(); while *count <= 0 { - self.cvar.wait(&count); + count = self.cvar.wait(count).unwrap(); } *count -= 1; } @@ -80,7 +80,7 @@ impl Semaphore { /// This will increment the number of resources in this semaphore by 1 and /// will notify any pending waiters in `acquire` or `access` if necessary. pub fn release(&self) { - *self.lock.lock() += 1; + *self.lock.lock().unwrap() += 1; self.cvar.notify_one(); } diff --git a/src/libstd/sync/task_pool.rs b/src/libstd/sync/task_pool.rs index 366e4b7d35b..98da5ccc554 100644 --- a/src/libstd/sync/task_pool.rs +++ b/src/libstd/sync/task_pool.rs @@ -113,7 +113,7 @@ fn spawn_in_pool(jobs: Arc>>) { let message = { // Only lock jobs for the time it takes // to get a job, not run it. - let lock = jobs.lock(); + let lock = jobs.lock().unwrap(); lock.recv_opt() }; diff --git a/src/libstd/sys/common/helper_thread.rs b/src/libstd/sys/common/helper_thread.rs index a629f035b07..9ef1c33312f 100644 --- a/src/libstd/sys/common/helper_thread.rs +++ b/src/libstd/sys/common/helper_thread.rs @@ -83,7 +83,7 @@ impl Helper { F: FnOnce() -> T, { unsafe { - let _guard = self.lock.lock(); + let _guard = self.lock.lock().unwrap(); if !*self.initialized.get() { let (tx, rx) = channel(); *self.chan.get() = mem::transmute(box tx); @@ -95,7 +95,7 @@ impl Helper { let t = f(); Thread::spawn(move |:| { helper(receive.0, rx, t); - let _g = self.lock.lock(); + let _g = self.lock.lock().unwrap(); *self.shutdown.get() = true; self.cond.notify_one() }).detach(); @@ -111,7 +111,7 @@ impl Helper { /// This is only valid if the worker thread has previously booted pub fn send(&'static self, msg: M) { unsafe { - let _guard = self.lock.lock(); + let _guard = self.lock.lock().unwrap(); // Must send and *then* signal to ensure that the child receives the // message. Otherwise it could wake up and go to sleep before we @@ -127,7 +127,7 @@ impl Helper { // Shut down, but make sure this is done inside our lock to ensure // that we'll always receive the exit signal when the thread // returns. - let guard = self.lock.lock(); + let mut guard = self.lock.lock().unwrap(); // Close the channel by destroying it let chan: Box> = mem::transmute(*self.chan.get()); @@ -137,7 +137,7 @@ impl Helper { // Wait for the child to exit while !*self.shutdown.get() { - self.cond.wait(&guard); + guard = self.cond.wait(guard).unwrap(); } drop(guard); diff --git a/src/libstd/thread.rs b/src/libstd/thread.rs index 56731bd7ec3..38e304ccfec 100644 --- a/src/libstd/thread.rs +++ b/src/libstd/thread.rs @@ -334,6 +334,7 @@ impl Thread { } /// Determines whether the current thread is panicking. + #[inline] pub fn panicking() -> bool { unwind::panicking() } @@ -349,9 +350,9 @@ impl Thread { // or futuxes, and in either case may allow spurious wakeups. pub fn park() { let thread = Thread::current(); - let mut guard = thread.inner.lock.lock(); + let mut guard = thread.inner.lock.lock().unwrap(); while !*guard { - thread.inner.cvar.wait(&guard); + guard = thread.inner.cvar.wait(guard).unwrap(); } *guard = false; } @@ -360,7 +361,7 @@ impl Thread { /// /// See the module doc for more detail. pub fn unpark(&self) { - let mut guard = self.inner.lock.lock(); + let mut guard = self.inner.lock.lock().unwrap(); if !*guard { *guard = true; self.inner.cvar.notify_one(); diff --git a/src/libstd/thread_local/mod.rs b/src/libstd/thread_local/mod.rs index 242dceb4256..4cfa2709352 100644 --- a/src/libstd/thread_local/mod.rs +++ b/src/libstd/thread_local/mod.rs @@ -240,13 +240,18 @@ impl Key { unsafe { let slot = slot.get().expect("cannot access a TLS value during or \ after it is destroyed"); - if (*slot.get()).is_none() { - *slot.get() = Some((self.init)()); - } - f((*slot.get()).as_ref().unwrap()) + f(match *slot.get() { + Some(ref inner) => inner, + None => self.init(slot), + }) } } + unsafe fn init(&self, slot: &UnsafeCell>) -> &T { + *slot.get() = Some((self.init)()); + (*slot.get()).as_ref().unwrap() + } + /// Test this TLS key to determine whether its value has been destroyed for /// the current thread or not. /// diff --git a/src/test/bench/msgsend-ring-mutex-arcs.rs b/src/test/bench/msgsend-ring-mutex-arcs.rs index 49f53bf9d38..8ec44b2dd3c 100644 --- a/src/test/bench/msgsend-ring-mutex-arcs.rs +++ b/src/test/bench/msgsend-ring-mutex-arcs.rs @@ -28,15 +28,15 @@ type pipe = Arc<(Mutex>, Condvar)>; fn send(p: &pipe, msg: uint) { let &(ref lock, ref cond) = &**p; - let mut arr = lock.lock(); + let mut arr = lock.lock().unwrap(); arr.push(msg); cond.notify_one(); } fn recv(p: &pipe) -> uint { let &(ref lock, ref cond) = &**p; - let mut arr = lock.lock(); + let mut arr = lock.lock().unwrap(); while arr.is_empty() { - cond.wait(&arr); + arr = cond.wait(arr).unwrap(); } arr.pop().unwrap() } diff --git a/src/test/run-pass/match-ref-binding-in-guard-3256.rs b/src/test/run-pass/match-ref-binding-in-guard-3256.rs index 9bb912e081c..a83bc73457e 100644 --- a/src/test/run-pass/match-ref-binding-in-guard-3256.rs +++ b/src/test/run-pass/match-ref-binding-in-guard-3256.rs @@ -11,13 +11,11 @@ use std::sync::Mutex; pub fn main() { - unsafe { - let x = Some(Mutex::new(true)); - match x { - Some(ref z) if *z.lock() => { - assert!(*z.lock()); - }, - _ => panic!() - } + let x = Some(Mutex::new(true)); + match x { + Some(ref z) if *z.lock().unwrap() => { + assert!(*z.lock().unwrap()); + }, + _ => panic!() } } diff --git a/src/test/run-pass/writealias.rs b/src/test/run-pass/writealias.rs index f48272366e2..dacfeb00819 100644 --- a/src/test/run-pass/writealias.rs +++ b/src/test/run-pass/writealias.rs @@ -15,13 +15,11 @@ struct Point {x: int, y: int, z: int} fn f(p: &mut Point) { p.z = 13; } pub fn main() { - unsafe { - let x = Some(Mutex::new(true)); - match x { - Some(ref z) if *z.lock() => { - assert!(*z.lock()); - }, - _ => panic!() - } + let x = Some(Mutex::new(true)); + match x { + Some(ref z) if *z.lock().unwrap() => { + assert!(*z.lock().unwrap()); + }, + _ => panic!() } } -- cgit 1.4.1-3-g733a5 From 35e63e382783c1dfea6f8c8ec451bab9f4076f9c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 29 Dec 2014 10:01:38 -0800 Subject: std: Stabilization pass for mutex/rwlock/condvar This commit performs a stabilization pass over the sync::{mutex, rwlock, condvar} modules, marking the following items as stable: * Mutex * Mutex::new * Mutex::lock * Mutex::try_lock * MutexGuard * RWLock * RWLock::new * RWLock::read * RWLock::try_read * RWLock::write * RWLock::try_write * RWLockReadGuard * RWLockWriteGuard * Condvar * Condvar::new * Condvar::wait * Condvar::notify_one * Condvar::notify_all * PoisonError * TryLockError * TryLockError::Poisoned * TryLockError::WouldBlock * LockResult * TryLockResult The following items remain unstable to explore future possibilities of unifying the static/non-static variants of the types: * StaticMutex * StaticMutex::new * StaticMutex::lock * StaticMutex::try_lock * StaticMutex::desroy * StaticRWLock * StaticRWLock::new * StaticRWLock::read * StaticRWLock::try_read * StaticRWLock::write * StaticRWLock::try_write * StaticRWLock::destroy The following items were removed in favor of `Guard<'static, ()>` instead. * StaticMutexGuard * StaticRWLockReadGuard * StaticRWLockWriteGuard --- src/libstd/sync/condvar.rs | 66 +++++++++--------- src/libstd/sync/mod.rs | 14 +--- src/libstd/sync/mutex.rs | 125 ++++++++++++---------------------- src/libstd/sync/poison.rs | 7 ++ src/libstd/sync/rwlock.rs | 164 +++++++++++++++++---------------------------- 5 files changed, 149 insertions(+), 227 deletions(-) (limited to 'src/libstd/sync') diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index 3e17d8b6be1..15faf5be258 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -12,10 +12,10 @@ use prelude::*; use sync::atomic::{mod, AtomicUint}; use sync::poison::{mod, LockResult}; -use sync::CondvarGuard; use sys_common::condvar as sys; use sys_common::mutex as sys_mutex; use time::Duration; +use sync::{mutex, MutexGuard}; /// A Condition Variable /// @@ -57,6 +57,7 @@ use time::Duration; /// started = cvar.wait(started).unwrap(); /// } /// ``` +#[stable] pub struct Condvar { inner: Box } unsafe impl Send for Condvar {} @@ -74,6 +75,7 @@ unsafe impl Sync for Condvar {} /// /// static CVAR: StaticCondvar = CONDVAR_INIT; /// ``` +#[unstable = "may be merged with Condvar in the future"] pub struct StaticCondvar { inner: sys::Condvar, mutex: AtomicUint, @@ -83,24 +85,16 @@ unsafe impl Send for StaticCondvar {} unsafe impl Sync for StaticCondvar {} /// Constant initializer for a statically allocated condition variable. +#[unstable = "may be merged with Condvar in the future"] pub const CONDVAR_INIT: StaticCondvar = StaticCondvar { inner: sys::CONDVAR_INIT, mutex: atomic::INIT_ATOMIC_UINT, }; -/// A trait for vaules which can be passed to the waiting methods of condition -/// variables. This is implemented by the mutex guards in this module. -/// -/// Note that this trait should likely not be implemented manually unless you -/// really know what you're doing. -pub trait AsGuard { - #[allow(missing_docs)] - fn as_guard(&self) -> CondvarGuard; -} - impl Condvar { /// Creates a new condition variable which is ready to be waited on and /// notified. + #[stable] pub fn new() -> Condvar { Condvar { inner: box StaticCondvar { @@ -136,11 +130,12 @@ impl Condvar { /// over time. Each condition variable is dynamically bound to exactly one /// mutex to ensure defined behavior across platforms. If this functionality /// is not desired, then unsafe primitives in `sys` are provided. - pub fn wait(&self, mutex_guard: T) - -> LockResult { + #[stable] + pub fn wait<'a, T>(&self, guard: MutexGuard<'a, T>) + -> LockResult> { unsafe { let me: &'static Condvar = &*(self as *const _); - me.inner.wait(mutex_guard) + me.inner.wait(guard) } } @@ -164,11 +159,11 @@ impl Condvar { // provide. There are also additional concerns about the unix-specific // implementation which may need to be addressed. #[allow(dead_code)] - fn wait_timeout(&self, mutex_guard: T, dur: Duration) - -> LockResult<(T, bool)> { + fn wait_timeout<'a, T>(&self, guard: MutexGuard<'a, T>, dur: Duration) + -> LockResult<(MutexGuard<'a, T>, bool)> { unsafe { let me: &'static Condvar = &*(self as *const _); - me.inner.wait_timeout(mutex_guard, dur) + me.inner.wait_timeout(guard, dur) } } @@ -179,6 +174,7 @@ impl Condvar { /// `notify_one` are not buffered in any way. /// /// To wake up all threads, see `notify_one()`. + #[stable] pub fn notify_one(&self) { unsafe { self.inner.inner.notify_one() } } /// Wake up all blocked threads on this condvar. @@ -188,6 +184,7 @@ impl Condvar { /// way. /// /// To wake up only one thread, see `notify_one()`. + #[stable] pub fn notify_all(&self) { unsafe { self.inner.inner.notify_all() } } } @@ -202,17 +199,19 @@ impl StaticCondvar { /// notification. /// /// See `Condvar::wait`. - pub fn wait(&'static self, mutex_guard: T) -> LockResult { + #[unstable = "may be merged with Condvar in the future"] + pub fn wait<'a, T>(&'static self, guard: MutexGuard<'a, T>) + -> LockResult> { let poisoned = unsafe { - let cvar_guard = mutex_guard.as_guard(); - self.verify(cvar_guard.lock); - self.inner.wait(cvar_guard.lock); - cvar_guard.poisoned.get() + let lock = mutex::guard_lock(&guard); + self.verify(lock); + self.inner.wait(lock); + mutex::guard_poison(&guard).get() }; if poisoned { - Err(poison::new_poison_error(mutex_guard)) + Err(poison::new_poison_error(guard)) } else { - Ok(mutex_guard) + Ok(guard) } } @@ -221,29 +220,31 @@ impl StaticCondvar { /// /// See `Condvar::wait_timeout`. #[allow(dead_code)] // may want to stabilize this later, see wait_timeout above - fn wait_timeout(&'static self, mutex_guard: T, dur: Duration) - -> LockResult<(T, bool)> { + fn wait_timeout<'a, T>(&'static self, guard: MutexGuard<'a, T>, dur: Duration) + -> LockResult<(MutexGuard<'a, T>, bool)> { let (poisoned, success) = unsafe { - let cvar_guard = mutex_guard.as_guard(); - self.verify(cvar_guard.lock); - let success = self.inner.wait_timeout(cvar_guard.lock, dur); - (cvar_guard.poisoned.get(), success) + let lock = mutex::guard_lock(&guard); + self.verify(lock); + let success = self.inner.wait_timeout(lock, dur); + (mutex::guard_poison(&guard).get(), success) }; if poisoned { - Err(poison::new_poison_error((mutex_guard, success))) + Err(poison::new_poison_error((guard, success))) } else { - Ok((mutex_guard, success)) + Ok((guard, success)) } } /// Wake up one blocked thread on this condvar. /// /// See `Condvar::notify_one`. + #[unstable = "may be merged with Condvar in the future"] pub fn notify_one(&'static self) { unsafe { self.inner.notify_one() } } /// Wake up all blocked threads on this condvar. /// /// See `Condvar::notify_all`. + #[unstable = "may be merged with Condvar in the future"] pub fn notify_all(&'static self) { unsafe { self.inner.notify_all() } } /// Deallocate all resources associated with this static condvar. @@ -252,6 +253,7 @@ impl StaticCondvar { /// active users of the condvar, and this also doesn't prevent any future /// users of the condvar. This method is required to be called to not leak /// memory on all platforms. + #[unstable = "may be merged with Condvar in the future"] pub unsafe fn destroy(&'static self) { self.inner.destroy() } diff --git a/src/libstd/sync/mod.rs b/src/libstd/sync/mod.rs index 3f95eac5090..092acc7ff25 100644 --- a/src/libstd/sync/mod.rs +++ b/src/libstd/sync/mod.rs @@ -17,16 +17,13 @@ #![experimental] -use sys_common::mutex as sys_mutex; - pub use alloc::arc::{Arc, Weak}; -pub use self::mutex::{Mutex, MutexGuard, StaticMutex, StaticMutexGuard}; +pub use self::mutex::{Mutex, MutexGuard, StaticMutex}; pub use self::mutex::MUTEX_INIT; pub use self::rwlock::{RWLock, StaticRWLock, RWLOCK_INIT}; pub use self::rwlock::{RWLockReadGuard, RWLockWriteGuard}; -pub use self::rwlock::{StaticRWLockReadGuard, StaticRWLockWriteGuard}; -pub use self::condvar::{Condvar, StaticCondvar, CONDVAR_INIT, AsGuard}; +pub use self::condvar::{Condvar, StaticCondvar, CONDVAR_INIT}; pub use self::once::{Once, ONCE_INIT}; pub use self::semaphore::{Semaphore, SemaphoreGuard}; pub use self::barrier::Barrier; @@ -45,10 +42,3 @@ mod poison; mod rwlock; mod semaphore; mod task_pool; - -/// Structure returned by `AsGuard` to wait on a condition variable. -// NB: defined here to all modules have access to these private fields. -pub struct CondvarGuard<'a> { - lock: &'a sys_mutex::Mutex, - poisoned: &'a poison::Flag, -} diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 621d7274062..32c2c67152f 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -12,7 +12,6 @@ use prelude::*; use cell::UnsafeCell; use kinds::marker; -use sync::{AsGuard, CondvarGuard}; use sync::poison::{mod, TryLockError, TryLockResult, LockResult}; use sys_common::mutex as sys; @@ -107,6 +106,7 @@ use sys_common::mutex as sys; /// /// *guard += 1; /// ``` +#[stable] pub struct Mutex { // Note that this static mutex is in a *box*, not inlined into the struct // itself. Once a native mutex has been used once, its address can never @@ -142,6 +142,7 @@ unsafe impl Sync for Mutex { } /// } /// // lock is unlocked here. /// ``` +#[unstable = "may be merged with Mutex in the future"] pub struct StaticMutex { lock: sys::Mutex, poison: poison::Flag, @@ -155,27 +156,19 @@ unsafe impl Sync for StaticMutex {} /// The data protected by the mutex can be access through this guard via its /// Deref and DerefMut implementations #[must_use] +#[stable] pub struct MutexGuard<'a, T: 'a> { // funny underscores due to how Deref/DerefMut currently work (they // disregard field privacy). - __inner: Guard<'a, Mutex>, -} - -/// An RAII implementation of a "scoped lock" of a static mutex. When this -/// structure is dropped (falls out of scope), the lock will be unlocked. -#[must_use] -pub struct StaticMutexGuard { - inner: Guard<'static, StaticMutex>, -} - -struct Guard<'a, T: 'a> { - inner: &'a T, - poison: poison::Guard, - marker: marker::NoSend, // even if 'a is static, this cannot be sent + __lock: &'a StaticMutex, + __data: &'a UnsafeCell, + __poison: poison::Guard, + __marker: marker::NoSend, } /// Static initialization of a mutex. This constant can be used to initialize /// other mutex constants. +#[unstable = "may be merged with Mutex in the future"] pub const MUTEX_INIT: StaticMutex = StaticMutex { lock: sys::MUTEX_INIT, poison: poison::FLAG_INIT, @@ -183,6 +176,7 @@ pub const MUTEX_INIT: StaticMutex = StaticMutex { impl Mutex { /// Creates a new mutex in an unlocked state ready for use. + #[stable] pub fn new(t: T) -> Mutex { Mutex { inner: box MUTEX_INIT, @@ -201,9 +195,10 @@ impl Mutex { /// /// If another user of this mutex panicked while holding the mutex, then /// this call will return an error once the mutex is acquired. + #[stable] pub fn lock(&self) -> LockResult> { unsafe { self.inner.lock.lock() } - MutexGuard::new(self) + MutexGuard::new(&*self.inner, &self.data) } /// Attempts to acquire this lock. @@ -219,9 +214,10 @@ impl Mutex { /// If another user of this mutex panicked while holding the mutex, then /// this call will return failure if the mutex would otherwise be /// acquired. + #[stable] pub fn try_lock(&self) -> TryLockResult> { if unsafe { self.inner.lock.try_lock() } { - Ok(try!(MutexGuard::new(self))) + Ok(try!(MutexGuard::new(&*self.inner, &self.data))) } else { Err(TryLockError::WouldBlock) } @@ -238,19 +234,23 @@ impl Drop for Mutex { } } +static DUMMY: UnsafeCell<()> = UnsafeCell { value: () }; + impl StaticMutex { /// Acquires this lock, see `Mutex::lock` #[inline] - pub fn lock(&'static self) -> LockResult { + #[unstable = "may be merged with Mutex in the future"] + pub fn lock(&'static self) -> LockResult> { unsafe { self.lock.lock() } - StaticMutexGuard::new(self) + MutexGuard::new(self, &DUMMY) } /// Attempts to grab this lock, see `Mutex::try_lock` #[inline] - pub fn try_lock(&'static self) -> TryLockResult { + #[unstable = "may be merged with Mutex in the future"] + pub fn try_lock(&'static self) -> TryLockResult> { if unsafe { self.lock.try_lock() } { - Ok(try!(StaticMutexGuard::new(self))) + Ok(try!(MutexGuard::new(self, &DUMMY))) } else { Err(TryLockError::WouldBlock) } @@ -266,93 +266,54 @@ impl StaticMutex { /// *all* platforms. It may be the case that some platforms do not leak /// memory if this method is not called, but this is not guaranteed to be /// true on all platforms. + #[unstable = "may be merged with Mutex in the future"] pub unsafe fn destroy(&'static self) { self.lock.destroy() } } impl<'mutex, T> MutexGuard<'mutex, T> { - fn new(lock: &Mutex) -> LockResult> { - poison::map_result(Guard::new(lock), |guard| { - MutexGuard { __inner: guard } + fn new(lock: &'mutex StaticMutex, data: &'mutex UnsafeCell) + -> LockResult> { + poison::map_result(lock.poison.borrow(), |guard| { + MutexGuard { + __lock: lock, + __data: data, + __poison: guard, + __marker: marker::NoSend, + } }) } } -impl AsGuard for Mutex { - fn as_guard(&self) -> CondvarGuard { self.inner.as_guard() } -} - -impl<'mutex, T> AsGuard for MutexGuard<'mutex, T> { - fn as_guard(&self) -> CondvarGuard { - CondvarGuard { - lock: &self.__inner.inner.inner.lock, - poisoned: &self.__inner.inner.inner.poison, - } - } -} - impl<'mutex, T> Deref for MutexGuard<'mutex, T> { fn deref<'a>(&'a self) -> &'a T { - unsafe { &*self.__inner.inner.data.get() } + unsafe { &*self.__data.get() } } } impl<'mutex, T> DerefMut for MutexGuard<'mutex, T> { fn deref_mut<'a>(&'a mut self) -> &'a mut T { - unsafe { &mut *self.__inner.inner.data.get() } - } -} - -impl StaticMutexGuard { - #[inline] - fn new(lock: &'static StaticMutex) -> LockResult { - poison::map_result(Guard::new(lock), |guard| { - StaticMutexGuard { inner: guard } - }) + unsafe { &mut *self.__data.get() } } } -impl AsGuard for StaticMutex { - #[inline] - fn as_guard(&self) -> CondvarGuard { - CondvarGuard { lock: &self.lock, poisoned: &self.poison } - } -} - -impl AsGuard for StaticMutexGuard { +#[unsafe_destructor] +impl<'a, T> Drop for MutexGuard<'a, T> { #[inline] - fn as_guard(&self) -> CondvarGuard { - CondvarGuard { - lock: &self.inner.inner.lock, - poisoned: &self.inner.inner.poison, + fn drop(&mut self) { + unsafe { + self.__lock.poison.done(&self.__poison); + self.__lock.lock.unlock(); } } } -impl<'a, T: AsGuard> Guard<'a, T> { - #[inline] - fn new(t: &T) -> LockResult> { - let data = t.as_guard(); - poison::map_result(data.poisoned.borrow(), |guard| { - Guard { - inner: t, - poison: guard, - marker: marker::NoSend, - } - }) - } +pub fn guard_lock<'a, T>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex { + &guard.__lock.lock } -#[unsafe_destructor] -impl<'a, T: AsGuard> Drop for Guard<'a, T> { - #[inline] - fn drop(&mut self) { - unsafe { - let data = self.inner.as_guard(); - data.poisoned.done(&self.poison); - data.lock.unlock(); - } - } +pub fn guard_poison<'a, T>(guard: &MutexGuard<'a, T>) -> &'a poison::Flag { + &guard.__lock.poison } #[cfg(test)] diff --git a/src/libstd/sync/poison.rs b/src/libstd/sync/poison.rs index d99fd91d0ac..edf16d99f49 100644 --- a/src/libstd/sync/poison.rs +++ b/src/libstd/sync/poison.rs @@ -53,18 +53,22 @@ pub struct Guard { /// is held. The precise semantics for when a lock is poisoned is documented on /// each lock, but once a lock is poisoned then all future acquisitions will /// return this error. +#[stable] pub struct PoisonError { guard: T, } /// An enumeration of possible errors which can occur while calling the /// `try_lock` method. +#[stable] pub enum TryLockError { /// The lock could not be acquired because another task failed while holding /// the lock. + #[stable] Poisoned(PoisonError), /// The lock could not be acquired at this time because the operation would /// otherwise block. + #[stable] WouldBlock, } @@ -75,6 +79,7 @@ pub enum TryLockError { /// that the primitive was poisoned. Note that the `Err` variant *also* carries /// the associated guard, and it can be acquired through the `into_inner` /// method. +#[stable] pub type LockResult = Result>; /// A type alias for the result of a nonblocking locking method. @@ -82,6 +87,7 @@ pub type LockResult = Result>; /// For more information, see `LockResult`. A `TryLockResult` doesn't /// necessarily hold the associated guard in the `Err` type as the lock may not /// have been acquired for other reasons. +#[stable] pub type TryLockResult = Result>; impl fmt::Show for PoisonError { @@ -93,6 +99,7 @@ impl fmt::Show for PoisonError { impl PoisonError { /// Consumes this error indicating that a lock is poisoned, returning the /// underlying guard to allow access regardless. + #[stable] pub fn into_guard(self) -> T { self.guard } } diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index f7632c4f8b5..29cc1f8563f 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -57,6 +57,7 @@ use sys_common::rwlock as sys; /// assert_eq!(*w, 6); /// } // write lock is dropped here /// ``` +#[stable] pub struct RWLock { inner: Box, data: UnsafeCell, @@ -88,6 +89,7 @@ unsafe impl Sync for RWLock {} /// } /// unsafe { LOCK.destroy() } // free all resources /// ``` +#[unstable = "may be merged with RWLock in the future"] pub struct StaticRWLock { lock: sys::RWLock, poison: poison::Flag, @@ -97,6 +99,7 @@ unsafe impl Send for StaticRWLock {} unsafe impl Sync for StaticRWLock {} /// Constant initialization for a statically-initialized rwlock. +#[unstable = "may be merged with RWLock in the future"] pub const RWLOCK_INIT: StaticRWLock = StaticRWLock { lock: sys::RWLOCK_INIT, poison: poison::FLAG_INIT, @@ -105,49 +108,27 @@ pub const RWLOCK_INIT: StaticRWLock = StaticRWLock { /// RAII structure used to release the shared read access of a lock when /// dropped. #[must_use] +#[stable] pub struct RWLockReadGuard<'a, T: 'a> { - __inner: ReadGuard<'a, RWLock>, + __lock: &'a StaticRWLock, + __data: &'a UnsafeCell, + __marker: marker::NoSend, } /// RAII structure used to release the exclusive write access of a lock when /// dropped. #[must_use] +#[stable] pub struct RWLockWriteGuard<'a, T: 'a> { - __inner: WriteGuard<'a, RWLock>, -} - -/// RAII structure used to release the shared read access of a lock when -/// dropped. -#[must_use] -pub struct StaticRWLockReadGuard { - _inner: ReadGuard<'static, StaticRWLock>, -} - -/// RAII structure used to release the exclusive write access of a lock when -/// dropped. -#[must_use] -pub struct StaticRWLockWriteGuard { - _inner: WriteGuard<'static, StaticRWLock>, -} - -struct ReadGuard<'a, T: 'a> { - inner: &'a T, - marker: marker::NoSend, // even if 'a == static, cannot send -} - -struct WriteGuard<'a, T: 'a> { - inner: &'a T, - poison: poison::Guard, - marker: marker::NoSend, // even if 'a == static, cannot send -} - -#[doc(hidden)] -trait AsStaticRWLock { - fn as_static_rwlock(&self) -> &StaticRWLock; + __lock: &'a StaticRWLock, + __data: &'a UnsafeCell, + __poison: poison::Guard, + __marker: marker::NoSend, } impl RWLock { /// Creates a new instance of an RWLock which is unlocked and read to go. + #[stable] pub fn new(t: T) -> RWLock { RWLock { inner: box RWLOCK_INIT, data: UnsafeCell::new(t) } } @@ -170,9 +151,10 @@ impl RWLock { /// is poisoned whenever a writer panics while holding an exclusive lock. /// The failure will occur immediately after the lock has been acquired. #[inline] + #[stable] pub fn read(&self) -> LockResult> { unsafe { self.inner.lock.read() } - RWLockReadGuard::new(self) + RWLockReadGuard::new(&*self.inner, &self.data) } /// Attempt to acquire this lock with shared read access. @@ -191,9 +173,10 @@ impl RWLock { /// error will only be returned if the lock would have otherwise been /// acquired. #[inline] + #[stable] pub fn try_read(&self) -> TryLockResult> { if unsafe { self.inner.lock.try_read() } { - Ok(try!(RWLockReadGuard::new(self))) + Ok(try!(RWLockReadGuard::new(&*self.inner, &self.data))) } else { Err(TryLockError::WouldBlock) } @@ -214,9 +197,10 @@ impl RWLock { /// is poisoned whenever a writer panics while holding an exclusive lock. /// An error will be returned when the lock is acquired. #[inline] + #[stable] pub fn write(&self) -> LockResult> { unsafe { self.inner.lock.write() } - RWLockWriteGuard::new(self) + RWLockWriteGuard::new(&*self.inner, &self.data) } /// Attempt to lock this rwlock with exclusive write access. @@ -232,9 +216,10 @@ impl RWLock { /// error will only be returned if the lock would have otherwise been /// acquired. #[inline] + #[stable] pub fn try_write(&self) -> TryLockResult> { if unsafe { self.inner.lock.try_read() } { - Ok(try!(RWLockWriteGuard::new(self))) + Ok(try!(RWLockWriteGuard::new(&*self.inner, &self.data))) } else { Err(TryLockError::WouldBlock) } @@ -248,24 +233,29 @@ impl Drop for RWLock { } } +static DUMMY: UnsafeCell<()> = UnsafeCell { value: () }; + impl StaticRWLock { /// Locks this rwlock with shared read access, blocking the current thread /// until it can be acquired. /// /// See `RWLock::read`. #[inline] - pub fn read(&'static self) -> LockResult { + #[unstable = "may be merged with RWLock in the future"] + pub fn read(&'static self) -> LockResult> { unsafe { self.lock.read() } - StaticRWLockReadGuard::new(self) + RWLockReadGuard::new(self, &DUMMY) } /// Attempt to acquire this lock with shared read access. /// /// See `RWLock::try_read`. #[inline] - pub fn try_read(&'static self) -> TryLockResult { + #[unstable = "may be merged with RWLock in the future"] + pub fn try_read(&'static self) + -> TryLockResult> { if unsafe { self.lock.try_read() } { - Ok(try!(StaticRWLockReadGuard::new(self))) + Ok(try!(RWLockReadGuard::new(self, &DUMMY))) } else { Err(TryLockError::WouldBlock) } @@ -276,18 +266,21 @@ impl StaticRWLock { /// /// See `RWLock::write`. #[inline] - pub fn write(&'static self) -> LockResult { + #[unstable = "may be merged with RWLock in the future"] + pub fn write(&'static self) -> LockResult> { unsafe { self.lock.write() } - StaticRWLockWriteGuard::new(self) + RWLockWriteGuard::new(self, &DUMMY) } /// Attempt to lock this rwlock with exclusive write access. /// /// See `RWLock::try_write`. #[inline] - pub fn try_write(&'static self) -> TryLockResult { + #[unstable = "may be merged with RWLock in the future"] + pub fn try_write(&'static self) + -> TryLockResult> { if unsafe { self.lock.try_write() } { - Ok(try!(StaticRWLockWriteGuard::new(self))) + Ok(try!(RWLockWriteGuard::new(self, &DUMMY))) } else { Err(TryLockError::WouldBlock) } @@ -299,93 +292,62 @@ impl StaticRWLock { /// active users of the lock, and this also doesn't prevent any future users /// of this lock. This method is required to be called to not leak memory on /// all platforms. + #[unstable = "may be merged with RWLock in the future"] pub unsafe fn destroy(&'static self) { self.lock.destroy() } } impl<'rwlock, T> RWLockReadGuard<'rwlock, T> { - fn new(lock: &RWLock) -> LockResult> { - poison::map_result(ReadGuard::new(lock), |guard| { - RWLockReadGuard { __inner: guard } + fn new(lock: &'rwlock StaticRWLock, data: &'rwlock UnsafeCell) + -> LockResult> { + poison::map_result(lock.poison.borrow(), |_| { + RWLockReadGuard { + __lock: lock, + __data: data, + __marker: marker::NoSend, + } }) } } impl<'rwlock, T> RWLockWriteGuard<'rwlock, T> { - fn new(lock: &RWLock) -> LockResult> { - poison::map_result(WriteGuard::new(lock), |guard| { - RWLockWriteGuard { __inner: guard } + fn new(lock: &'rwlock StaticRWLock, data: &'rwlock UnsafeCell) + -> LockResult> { + poison::map_result(lock.poison.borrow(), |guard| { + RWLockWriteGuard { + __lock: lock, + __data: data, + __poison: guard, + __marker: marker::NoSend, + } }) } } impl<'rwlock, T> Deref for RWLockReadGuard<'rwlock, T> { - fn deref(&self) -> &T { unsafe { &*self.__inner.inner.data.get() } } + fn deref(&self) -> &T { unsafe { &*self.__data.get() } } } impl<'rwlock, T> Deref for RWLockWriteGuard<'rwlock, T> { - fn deref(&self) -> &T { unsafe { &*self.__inner.inner.data.get() } } + fn deref(&self) -> &T { unsafe { &*self.__data.get() } } } impl<'rwlock, T> DerefMut for RWLockWriteGuard<'rwlock, T> { fn deref_mut(&mut self) -> &mut T { - unsafe { &mut *self.__inner.inner.data.get() } - } -} - -impl StaticRWLockReadGuard { - #[inline] - fn new(lock: &'static StaticRWLock) -> LockResult { - poison::map_result(ReadGuard::new(lock), |guard| { - StaticRWLockReadGuard { _inner: guard } - }) - } -} -impl StaticRWLockWriteGuard { - #[inline] - fn new(lock: &'static StaticRWLock) -> LockResult { - poison::map_result(WriteGuard::new(lock), |guard| { - StaticRWLockWriteGuard { _inner: guard } - }) - } -} - -impl AsStaticRWLock for RWLock { - #[inline] - fn as_static_rwlock(&self) -> &StaticRWLock { &*self.inner } -} -impl AsStaticRWLock for StaticRWLock { - #[inline] - fn as_static_rwlock(&self) -> &StaticRWLock { self } -} - -impl<'a, T: AsStaticRWLock> ReadGuard<'a, T> { - fn new(t: &'a T) -> LockResult> { - poison::map_result(t.as_static_rwlock().poison.borrow(), |_| { - ReadGuard { inner: t, marker: marker::NoSend } - }) - } -} - -impl<'a, T: AsStaticRWLock> WriteGuard<'a, T> { - fn new(t: &'a T) -> LockResult> { - poison::map_result(t.as_static_rwlock().poison.borrow(), |guard| { - WriteGuard { inner: t, marker: marker::NoSend, poison: guard } - }) + unsafe { &mut *self.__data.get() } } } #[unsafe_destructor] -impl<'a, T: AsStaticRWLock> Drop for ReadGuard<'a, T> { +impl<'a, T> Drop for RWLockReadGuard<'a, T> { fn drop(&mut self) { - unsafe { self.inner.as_static_rwlock().lock.read_unlock(); } + unsafe { self.__lock.lock.read_unlock(); } } } #[unsafe_destructor] -impl<'a, T: AsStaticRWLock> Drop for WriteGuard<'a, T> { +impl<'a, T> Drop for RWLockWriteGuard<'a, T> { fn drop(&mut self) { - let inner = self.inner.as_static_rwlock(); - inner.poison.done(&self.poison); - unsafe { inner.lock.write_unlock(); } + self.__lock.poison.done(&self.__poison); + unsafe { self.__lock.lock.write_unlock(); } } } -- cgit 1.4.1-3-g733a5 From 470ae101d6e26a6ce07292b7fca6eaed527451c7 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 29 Dec 2014 16:38:07 -0800 Subject: Test fixes and rebase conflicts --- src/libarena/lib.rs | 2 +- src/libcollections/lib.rs | 4 ++-- src/libcollections/str.rs | 10 ++-------- src/libcollections/string.rs | 2 +- src/libstd/c_str.rs | 2 +- src/libstd/collections/hash/map.rs | 2 +- src/libstd/io/process.rs | 1 + src/libstd/os.rs | 2 +- src/libstd/rt/backtrace.rs | 6 +++--- src/libstd/sync/mutex.rs | 8 +++++--- src/libstd/sync/rwlock.rs | 12 +++++++----- src/libstd/sys/common/net.rs | 4 ++-- src/libstd/sys/unix/pipe.rs | 2 +- src/libstd/sys/windows/c.rs | 1 - src/libstd/sys/windows/fs.rs | 4 ++-- src/libstd/sys/windows/os.rs | 11 ++++++----- src/libstd/sys/windows/tty.rs | 4 ++-- src/test/compile-fail/issue-7364.rs | 1 - src/test/compile-fail/mut-not-freeze.rs | 1 - 19 files changed, 38 insertions(+), 41 deletions(-) (limited to 'src/libstd/sync') diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs index 1f4df1fd0a5..b0fa5434a14 100644 --- a/src/libarena/lib.rs +++ b/src/libarena/lib.rs @@ -412,7 +412,7 @@ impl TypedArenaChunk { let size = calculate_size::(self.capacity); deallocate(self as *mut TypedArenaChunk as *mut u8, size, mem::min_align_of::>()); - if next.is_not_null() { + if !next.is_null() { let capacity = (*next).capacity; (*next).destroy(capacity); } diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 363d30abd03..fe9d8de440a 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -114,14 +114,14 @@ mod prelude { pub use core::ops::{Drop, Fn, FnMut, FnOnce}; pub use core::option::Option; pub use core::option::Option::{Some, None}; - pub use core::ptr::RawPtr; + pub use core::ptr::PtrExt; pub use core::result::Result; pub use core::result::Result::{Ok, Err}; // in core and collections (may differ). pub use slice::{PartialEqSliceExt, OrdSliceExt}; pub use slice::{AsSlice, SliceExt}; - pub use str::{from_str, Str}; + pub use str::{from_str, Str, StrExt}; // from other crates. pub use alloc::boxed::Box; diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index fdc52ab8eb0..7c7a7e19a2f 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -1770,15 +1770,9 @@ mod tests { use core::default::Default; use core::iter::AdditiveIterator; - use super::{eq_slice, from_utf8, is_utf8, is_utf16, raw}; - use super::truncate_utf16_at_nul; + use super::{from_utf8, is_utf8, raw}; use super::MaybeOwned::{Owned, Slice}; - use std::slice::{AsSlice, SliceExt}; - use string::{String, ToString}; - use vec::Vec; - use slice::CloneSliceExt; - - use unicode::char::UnicodeChar; + use super::Utf8Error; #[test] fn test_le() { diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 51ad0b52b81..c6c19cae75f 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -1082,7 +1082,7 @@ mod tests { use prelude::*; use test::Bencher; - use str::{StrExt, Utf8Error}; + use str::Utf8Error; use str; use super::as_string; diff --git a/src/libstd/c_str.rs b/src/libstd/c_str.rs index 39c57b99b36..f28abcc10cf 100644 --- a/src/libstd/c_str.rs +++ b/src/libstd/c_str.rs @@ -538,7 +538,7 @@ pub unsafe fn from_c_multistring(buf: *const libc::c_char, mod tests { use super::*; use prelude::{spawn, Some, None, Option, FnOnce, ToString, CloneSliceExt}; - use prelude::{Clone, RawPtr, Iterator, SliceExt, StrExt}; + use prelude::{Clone, PtrExt, Iterator, SliceExt, StrExt}; use ptr; use thread::Thread; use libc; diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index c62ca6f5929..7b7473b2c99 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -278,7 +278,7 @@ fn test_resize_policy() { /// /// impl Viking { /// /// Create a new Viking. -/// pub fn new(name: &str, country: &str) -> Viking { +/// fn new(name: &str, country: &str) -> Viking { /// Viking { name: name.to_string(), country: country.to_string() } /// } /// } diff --git a/src/libstd/io/process.rs b/src/libstd/io/process.rs index 9e0c76e4e79..b127507f048 100644 --- a/src/libstd/io/process.rs +++ b/src/libstd/io/process.rs @@ -1207,6 +1207,7 @@ mod tests { #[test] #[cfg(windows)] fn env_map_keys_ci() { + use c_str::ToCStr; use super::EnvKey; let mut cmd = Command::new(""); cmd.env("path", "foo"); diff --git a/src/libstd/os.rs b/src/libstd/os.rs index 049d97798e4..989f44f7b8e 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -731,7 +731,7 @@ fn real_args() -> Vec { let ptr = ptr as *const u16; let buf = slice::from_raw_buf(&ptr, len); let opt_s = String::from_utf16(sys::os::truncate_utf16_at_nul(buf)); - opt_s.expect("CommandLineToArgvW returned invalid UTF-16") + opt_s.ok().expect("CommandLineToArgvW returned invalid UTF-16") }); unsafe { diff --git a/src/libstd/rt/backtrace.rs b/src/libstd/rt/backtrace.rs index 775e9bb526f..3eeb0ad3968 100644 --- a/src/libstd/rt/backtrace.rs +++ b/src/libstd/rt/backtrace.rs @@ -60,19 +60,19 @@ mod test { t!("_ZN4$UP$E", "Box"); t!("_ZN8$UP$testE", "Boxtest"); t!("_ZN8$UP$test4foobE", "Boxtest::foob"); - t!("_ZN8$x20test4foobE", " test::foob"); + t!("_ZN10$u{20}test4foobE", " test::foob"); } #[test] fn demangle_many_dollars() { - t!("_ZN12test$x20test4foobE", "test test::foob"); + t!("_ZN14test$u{20}test4foobE", "test test::foob"); t!("_ZN12test$UP$test4foobE", "testBoxtest::foob"); } #[test] fn demangle_windows() { t!("ZN4testE", "test"); - t!("ZN12test$x20test4foobE", "test test::foob"); + t!("ZN14test$u{20}test4foobE", "test test::foob"); t!("ZN12test$UP$test4foobE", "testBoxtest::foob"); } } diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 32c2c67152f..52004bb4a8f 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -234,7 +234,9 @@ impl Drop for Mutex { } } -static DUMMY: UnsafeCell<()> = UnsafeCell { value: () }; +struct Dummy(UnsafeCell<()>); +unsafe impl Sync for Dummy {} +static DUMMY: Dummy = Dummy(UnsafeCell { value: () }); impl StaticMutex { /// Acquires this lock, see `Mutex::lock` @@ -242,7 +244,7 @@ impl StaticMutex { #[unstable = "may be merged with Mutex in the future"] pub fn lock(&'static self) -> LockResult> { unsafe { self.lock.lock() } - MutexGuard::new(self, &DUMMY) + MutexGuard::new(self, &DUMMY.0) } /// Attempts to grab this lock, see `Mutex::try_lock` @@ -250,7 +252,7 @@ impl StaticMutex { #[unstable = "may be merged with Mutex in the future"] pub fn try_lock(&'static self) -> TryLockResult> { if unsafe { self.lock.try_lock() } { - Ok(try!(MutexGuard::new(self, &DUMMY))) + Ok(try!(MutexGuard::new(self, &DUMMY.0))) } else { Err(TryLockError::WouldBlock) } diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index 1b7a7f3f323..7f3c77c97ad 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -233,7 +233,9 @@ impl Drop for RWLock { } } -static DUMMY: UnsafeCell<()> = UnsafeCell { value: () }; +struct Dummy(UnsafeCell<()>); +unsafe impl Sync for Dummy {} +static DUMMY: Dummy = Dummy(UnsafeCell { value: () }); impl StaticRWLock { /// Locks this rwlock with shared read access, blocking the current thread @@ -244,7 +246,7 @@ impl StaticRWLock { #[unstable = "may be merged with RWLock in the future"] pub fn read(&'static self) -> LockResult> { unsafe { self.lock.read() } - RWLockReadGuard::new(self, &DUMMY) + RWLockReadGuard::new(self, &DUMMY.0) } /// Attempt to acquire this lock with shared read access. @@ -255,7 +257,7 @@ impl StaticRWLock { pub fn try_read(&'static self) -> TryLockResult> { if unsafe { self.lock.try_read() } { - Ok(try!(RWLockReadGuard::new(self, &DUMMY))) + Ok(try!(RWLockReadGuard::new(self, &DUMMY.0))) } else { Err(TryLockError::WouldBlock) } @@ -269,7 +271,7 @@ impl StaticRWLock { #[unstable = "may be merged with RWLock in the future"] pub fn write(&'static self) -> LockResult> { unsafe { self.lock.write() } - RWLockWriteGuard::new(self, &DUMMY) + RWLockWriteGuard::new(self, &DUMMY.0) } /// Attempt to lock this rwlock with exclusive write access. @@ -280,7 +282,7 @@ impl StaticRWLock { pub fn try_write(&'static self) -> TryLockResult> { if unsafe { self.lock.try_write() } { - Ok(try!(RWLockWriteGuard::new(self, &DUMMY))) + Ok(try!(RWLockWriteGuard::new(self, &DUMMY.0))) } else { Err(TryLockError::WouldBlock) } diff --git a/src/libstd/sys/common/net.rs b/src/libstd/sys/common/net.rs index 793e81e1ab5..7a09137a225 100644 --- a/src/libstd/sys/common/net.rs +++ b/src/libstd/sys/common/net.rs @@ -669,7 +669,7 @@ impl TcpStream { fn lock_nonblocking<'a>(&'a self) -> Guard<'a> { let ret = Guard { fd: self.fd(), - guard: self.inner.lock.lock(), + guard: self.inner.lock.lock().unwrap(), }; assert!(set_nonblocking(self.fd(), true).is_ok()); ret @@ -808,7 +808,7 @@ impl UdpSocket { fn lock_nonblocking<'a>(&'a self) -> Guard<'a> { let ret = Guard { fd: self.fd(), - guard: self.inner.lock.lock(), + guard: self.inner.lock.lock().unwrap(), }; assert!(set_nonblocking(self.fd(), true).is_ok()); ret diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs index f1b078b4e80..868b460aa5e 100644 --- a/src/libstd/sys/unix/pipe.rs +++ b/src/libstd/sys/unix/pipe.rs @@ -145,7 +145,7 @@ impl UnixStream { fn lock_nonblocking<'a>(&'a self) -> Guard<'a> { let ret = Guard { fd: self.fd(), - guard: unsafe { self.inner.lock.lock() }, + guard: unsafe { self.inner.lock.lock().unwrap() }, }; assert!(set_nonblocking(self.fd(), true).is_ok()); ret diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index d1cb91bcdb3..06259d61fcb 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -131,7 +131,6 @@ extern "system" { pub mod compat { use intrinsics::{atomic_store_relaxed, transmute}; - use iter::IteratorExt; use libc::types::os::arch::extra::{LPCWSTR, HMODULE, LPCSTR, LPVOID}; use prelude::*; diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs index 15eddd569be..3ad439078b9 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -265,8 +265,8 @@ pub fn readdir(p: &Path) -> IoResult> { { let filename = os::truncate_utf16_at_nul(&wfd.cFileName); match String::from_utf16(filename) { - Some(filename) => paths.push(Path::new(filename)), - None => { + Ok(filename) => paths.push(Path::new(filename)), + Err(..) => { assert!(libc::FindClose(find_handle) != 0); return Err(IoError { kind: io::InvalidInput, diff --git a/src/libstd/sys/windows/os.rs b/src/libstd/sys/windows/os.rs index e007b46b261..fa08290a888 100644 --- a/src/libstd/sys/windows/os.rs +++ b/src/libstd/sys/windows/os.rs @@ -99,8 +99,9 @@ pub fn error_string(errnum: i32) -> String { let msg = String::from_utf16(truncate_utf16_at_nul(&buf)); match msg { - Some(msg) => format!("OS Error {}: {}", errnum, msg), - None => format!("OS Error {} (FormatMessageW() returned invalid UTF-16)", errnum), + Ok(msg) => format!("OS Error {}: {}", errnum, msg), + Err(..) => format!("OS Error {} (FormatMessageW() returned \ + invalid UTF-16)", errnum), } } } @@ -147,7 +148,7 @@ pub fn fill_utf16_buf_and_decode(f: |*mut u16, DWORD| -> DWORD) -> Option IoResult { } match String::from_utf16(truncate_utf16_at_nul(&buf)) { - Some(ref cwd) => Ok(Path::new(cwd)), - None => Err(IoError { + Ok(ref cwd) => Ok(Path::new(cwd)), + Err(..) => Err(IoError { kind: OtherIoError, desc: "GetCurrentDirectoryW returned invalid UTF-16", detail: None, diff --git a/src/libstd/sys/windows/tty.rs b/src/libstd/sys/windows/tty.rs index f793de5bb57..99292b3b44b 100644 --- a/src/libstd/sys/windows/tty.rs +++ b/src/libstd/sys/windows/tty.rs @@ -101,8 +101,8 @@ impl TTY { }; utf16.truncate(num as uint); let utf8 = match String::from_utf16(utf16.as_slice()) { - Some(utf8) => utf8.into_bytes(), - None => return Err(invalid_encoding()), + Ok(utf8) => utf8.into_bytes(), + Err(..) => return Err(invalid_encoding()), }; self.utf8 = MemReader::new(utf8); } diff --git a/src/test/compile-fail/issue-7364.rs b/src/test/compile-fail/issue-7364.rs index ab5ba296652..77836143f27 100644 --- a/src/test/compile-fail/issue-7364.rs +++ b/src/test/compile-fail/issue-7364.rs @@ -16,6 +16,5 @@ static boxed: Box> = box RefCell::new(0); //~^ ERROR statics are not allowed to have custom pointers //~| ERROR: the trait `core::kinds::Sync` is not implemented for the type //~| ERROR: the trait `core::kinds::Sync` is not implemented for the type -//~| ERROR: the trait `core::kinds::Sync` is not implemented for the type fn main() { } diff --git a/src/test/compile-fail/mut-not-freeze.rs b/src/test/compile-fail/mut-not-freeze.rs index 4b058f6fdb3..95ebb8bd882 100644 --- a/src/test/compile-fail/mut-not-freeze.rs +++ b/src/test/compile-fail/mut-not-freeze.rs @@ -17,5 +17,4 @@ fn main() { f(x); //~^ ERROR `core::kinds::Sync` is not implemented //~^^ ERROR `core::kinds::Sync` is not implemented - //~^^^ ERROR `core::kinds::Sync` is not implemented } -- cgit 1.4.1-3-g733a5