diff options
| author | Alex Crichton <alex@alexcrichton.com> | 2015-01-05 19:08:37 -0800 |
|---|---|---|
| committer | Alex Crichton <alex@alexcrichton.com> | 2015-01-05 19:08:37 -0800 |
| commit | ee9921aaedb26de3cac4c1c174888528f68bbd3f (patch) | |
| tree | 6754f0144b41399d7703ce7f22d56e4df7ccdcb6 /src/libstd/sync | |
| parent | f331c568698db2361598a7ae017bfdb1fed9543d (diff) | |
| download | rust-ee9921aaedb26de3cac4c1c174888528f68bbd3f.tar.gz rust-ee9921aaedb26de3cac4c1c174888528f68bbd3f.zip | |
Revert "Remove i suffix in docs"
This reverts commit f031671c6ea79391eeb3e1ad8f06fe0e436103fb. Conflicts: src/libcollections/slice.rs src/libcore/iter.rs src/libstd/sync/mpsc/mod.rs src/libstd/sync/rwlock.rs
Diffstat (limited to 'src/libstd/sync')
| -rw-r--r-- | src/libstd/sync/mpsc/mod.rs | 1413 | ||||
| -rw-r--r-- | src/libstd/sync/rwlock.rs | 2 |
2 files changed, 722 insertions, 693 deletions
diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index bcfd61582a3..7c18b8a43fa 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -8,12 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Communication primitives for concurrent tasks -//! -//! Rust makes it very difficult to share data among tasks to prevent race -//! conditions and to improve parallelism, but there is often a need for -//! communication between concurrent tasks. The primitives defined in this -//! module are the building blocks for synchronization in rust. +//! Multi-producer, single-consumer communication primitives threads //! //! This module provides message-based communication over channels, concretely //! defined among three types: @@ -23,12 +18,10 @@ //! * `Receiver` //! //! A `Sender` or `SyncSender` is used to send data to a `Receiver`. Both -//! senders are clone-able such that many tasks can send simultaneously to one -//! receiver. These channels are *task blocking*, not *thread blocking*. This -//! means that if one task is blocked on a channel, other tasks can continue to -//! make progress. +//! senders are clone-able (multi-producer) such that many threads can send +//! simultaneously to one receiver (single-consumer). //! -//! Rust channels come in one of two flavors: +//! These channels come in two flavors: //! //! 1. An asynchronous, infinitely buffered channel. The `channel()` function //! will return a `(Sender, Receiver)` tuple where all sends will be @@ -43,36 +36,39 @@ //! "rendezvous" channel where each sender atomically hands off a message to //! a receiver. //! -//! ## Panic Propagation +//! ## Disconnection //! -//! In addition to being a core primitive for communicating in rust, channels -//! are the points at which panics are propagated among tasks. Whenever the one -//! half of channel is closed, the other half will have its next operation -//! `panic!`. The purpose of this is to allow propagation of panics among tasks -//! that are linked to one another via channels. +//! The send and receive operations on channels will all return a `Result` +//! indicating whether the operation succeeded or not. An unsuccessful operation +//! is normally indicative of the other half of a channel having "hung up" by +//! being dropped in its corresponding thread. //! -//! There are methods on both of senders and receivers to perform their -//! respective operations without panicking, however. +//! Once half of a channel has been deallocated, most operations can no longer +//! continue to make progress, so `Err` will be returned. Many applications will +//! continue to `unwrap()` the results returned from this module, instigating a +//! propagation of failure among threads if one unexpectedly dies. //! -//! # Example +//! # Examples //! //! Simple usage: //! //! ``` //! use std::thread::Thread; +//! use std::sync::mpsc::channel; //! //! // Create a simple streaming channel //! let (tx, rx) = channel(); //! Thread::spawn(move|| { -//! tx.send(10); +//! tx.send(10i).unwrap(); //! }).detach(); -//! assert_eq!(rx.recv(), 10); +//! assert_eq!(rx.recv().unwrap(), 10i); //! ``` //! //! Shared usage: //! //! ``` //! use std::thread::Thread; +//! use std::sync::mpsc::channel; //! //! // Create a shared channel that can be sent along from many threads //! // where tx is the sending half (tx for transmission), and rx is the receiving @@ -81,37 +77,40 @@ //! for i in range(0i, 10i) { //! let tx = tx.clone(); //! Thread::spawn(move|| { -//! tx.send(i); +//! tx.send(i).unwrap(); //! }).detach() //! } //! //! for _ in range(0i, 10i) { -//! let j = rx.recv(); +//! let j = rx.recv().unwrap(); //! assert!(0 <= j && j < 10); //! } //! ``` //! //! Propagating panics: //! -//! ```should_fail -//! // The call to recv() will panic!() because the channel has already hung -//! // up (or been deallocated) +//! ``` +//! use std::sync::mpsc::channel; +//! +//! // The call to recv() will return an error because the channel has already +//! // hung up (or been deallocated) //! let (tx, rx) = channel::<int>(); //! drop(tx); -//! rx.recv(); +//! assert!(rx.recv().is_err()); //! ``` //! //! Synchronous channels: //! //! ``` //! use std::thread::Thread; +//! use std::sync::mpsc::sync_channel; //! //! let (tx, rx) = sync_channel::<int>(0); //! Thread::spawn(move|| { //! // This will wait for the parent task to start receiving -//! tx.send(53); +//! tx.send(53).unwrap(); //! }).detach(); -//! rx.recv(); +//! rx.recv().unwrap(); //! ``` //! //! Reading from a channel with a timeout requires to use a Timer together @@ -120,6 +119,7 @@ //! after 10 seconds no matter what: //! //! ```no_run +//! use std::sync::mpsc::channel; //! use std::io::timer::Timer; //! use std::time::Duration; //! @@ -129,8 +129,8 @@ //! //! loop { //! select! { -//! val = rx.recv() => println!("Received {}", val), -//! () = timeout.recv() => { +//! val = rx.recv() => println!("Received {}", val.unwrap()), +//! _ = timeout.recv() => { //! println!("timed out, total time was more than 10 seconds"); //! break; //! } @@ -143,6 +143,7 @@ //! has been inactive for 5 seconds: //! //! ```no_run +//! use std::sync::mpsc::channel; //! use std::io::timer::Timer; //! use std::time::Duration; //! @@ -153,8 +154,8 @@ //! let timeout = timer.oneshot(Duration::seconds(5)); //! //! select! { -//! val = rx.recv() => println!("Received {}", val), -//! () = timeout.recv() => { +//! val = rx.recv() => println!("Received {}", val.unwrap()), +//! _ = timeout.recv() => { //! println!("timed out, no message received in 5 seconds"); //! break; //! } @@ -314,38 +315,19 @@ // And now that you've seen all the races that I found and attempted to fix, // here's the code for you to find some more! -use core::prelude::*; +use prelude::v1::*; -pub use self::TryRecvError::*; -pub use self::TrySendError::*; - -use alloc::arc::Arc; -use core::kinds; -use core::kinds::marker; -use core::mem; -use core::cell::UnsafeCell; +use sync::Arc; +use fmt; +use kinds::marker; +use mem; +use cell::UnsafeCell; pub use self::select::{Select, Handle}; use self::select::StartResult; use self::select::StartResult::*; use self::blocking::SignalToken; -macro_rules! test { - { fn $name:ident() $b:block $(#[$a:meta])*} => ( - mod $name { - #![allow(unused_imports)] - - use super::*; - use comm::*; - use thread::Thread; - use prelude::{Ok, Err, spawn, range, drop, Box, Some, None, Option}; - use prelude::{Vec, Buffer, from_str, Clone}; - - $(#[$a])* #[test] fn f() { $b } - } - ) -} - mod blocking; mod oneshot; mod select; @@ -357,7 +339,7 @@ mod spsc_queue; /// The receiving-half of Rust's channel type. This half can only be owned by /// one task -#[unstable] +#[stable] pub struct Receiver<T> { inner: UnsafeCell<Flavor<T>>, } @@ -369,14 +351,14 @@ unsafe impl<T:Send> Send for Receiver<T> { } /// An iterator over messages on a receiver, this iterator will block /// whenever `next` is called, waiting for a new message, and `None` will be /// returned when the corresponding channel has hung up. -#[unstable] -pub struct Messages<'a, T:'a> { +#[stable] +pub struct Iter<'a, T:'a> { rx: &'a Receiver<T> } /// The sending-half of Rust's asynchronous channel type. This half can only be /// owned by one task, but it can be cloned to send to other tasks. -#[unstable] +#[stable] pub struct Sender<T> { inner: UnsafeCell<Flavor<T>>, } @@ -387,30 +369,50 @@ unsafe impl<T:Send> Send for Sender<T> { } /// The sending-half of Rust's synchronous channel type. This half can only be /// owned by one task, but it can be cloned to send to other tasks. -#[unstable = "this type may be renamed, but it will always exist"] +#[stable] pub struct SyncSender<T> { inner: Arc<RacyCell<sync::Packet<T>>>, // can't share in an arc _marker: marker::NoSync, } +/// An error returned from the `send` function on channels. +/// +/// A `send` operation can only fail if the receiving end of a channel is +/// disconnected, implying that the data could never be received. The error +/// contains the data being sent as a payload so it can be recovered. +#[derive(PartialEq, Eq)] +#[stable] +pub struct SendError<T>(pub T); + +/// An error returned from the `recv` function on a `Receiver`. +/// +/// The `recv` operation can only fail if the sending half of a channel is +/// disconnected, implying that no further messages will ever be received. +#[derive(PartialEq, Eq, Clone, Copy)] +#[stable] +pub struct RecvError; + /// This enumeration is the list of the possible reasons that try_recv could not /// return data when called. -#[deriving(PartialEq, Clone, Copy, Show)] -#[experimental = "this is likely to be removed in changing try_recv()"] +#[derive(PartialEq, Clone, Copy)] +#[stable] pub enum TryRecvError { /// This channel is currently empty, but the sender(s) have not yet /// disconnected, so data may yet become available. + #[stable] Empty, + /// This channel's sending half has become disconnected, and there will /// never be any more data received on this channel + #[stable] Disconnected, } /// This enumeration is the list of the possible error outcomes for the /// `SyncSender::try_send` method. -#[deriving(PartialEq, Clone, Show)] -#[experimental = "this is likely to be removed in changing try_send()"] +#[derive(PartialEq, Clone)] +#[stable] pub enum TrySendError<T> { /// The data could not be sent on the channel because it would require that /// the callee block to send the data. @@ -418,10 +420,13 @@ pub enum TrySendError<T> { /// If this is a buffered channel, then the buffer is full at this time. If /// this is not a buffered channel, then there is no receiver available to /// acquire the data. + #[stable] Full(T), + /// This channel's receiving half has disconnected, so the data could not be /// sent. The data is returned back to the callee in this case. - RecvDisconnected(T), + #[stable] + Disconnected(T), } enum Flavor<T> { @@ -460,6 +465,7 @@ impl<T> UnsafeFlavor<T> for Receiver<T> { /// # Example /// /// ``` +/// use std::sync::mpsc::channel; /// use std::thread::Thread; /// /// // tx is is the sending half (tx for transmission), and rx is the receiving @@ -469,15 +475,15 @@ impl<T> UnsafeFlavor<T> for Receiver<T> { /// // Spawn off an expensive computation /// Thread::spawn(move|| { /// # fn expensive_computation() {} -/// tx.send(expensive_computation()); +/// tx.send(expensive_computation()).unwrap(); /// }).detach(); /// /// // Do some useful work for awhile /// /// // Let's see what that answer was -/// println!("{}", rx.recv()); +/// println!("{}", rx.recv().unwrap()); /// ``` -#[unstable] +#[stable] pub fn channel<T: Send>() -> (Sender<T>, Receiver<T>) { let a = Arc::new(RacyCell::new(oneshot::Packet::new())); (Sender::new(Flavor::Oneshot(a.clone())), Receiver::new(Flavor::Oneshot(a))) @@ -501,23 +507,23 @@ pub fn channel<T: Send>() -> (Sender<T>, Receiver<T>) { /// # Example /// /// ``` +/// use std::sync::mpsc::sync_channel; /// use std::thread::Thread; /// /// let (tx, rx) = sync_channel(1); /// /// // this returns immediately -/// tx.send(1); +/// tx.send(1i).unwrap(); /// /// Thread::spawn(move|| { /// // this will block until the previous message has been received -/// tx.send(2); +/// tx.send(2i).unwrap(); /// }).detach(); /// -/// assert_eq!(rx.recv(), 1); -/// assert_eq!(rx.recv(), 2); +/// assert_eq!(rx.recv().unwrap(), 1i); +/// assert_eq!(rx.recv().unwrap(), 2i); /// ``` -#[unstable = "this function may be renamed to more accurately reflect the type \ - of channel that is is creating"] +#[stable] pub fn sync_channel<T: Send>(bound: uint) -> (SyncSender<T>, Receiver<T>) { let a = Arc::new(RacyCell::new(sync::Packet::new(bound))); (SyncSender::new(a.clone()), Receiver::new(Flavor::Sync(a))) @@ -534,33 +540,6 @@ impl<T: Send> Sender<T> { } } - /// Sends a value along this channel to be received by the corresponding - /// receiver. - /// - /// Rust channels are infinitely buffered so this method will never block. - /// - /// # Panics - /// - /// This function will panic if the other end of the channel has hung up. - /// This means that if the corresponding receiver has fallen out of scope, - /// this function will trigger a panic message saying that a message is - /// being sent on a closed channel. - /// - /// Note that if this function does *not* panic, it does not mean that the - /// data will be successfully received. All sends are placed into a queue, - /// so it is possible for a send to succeed (the other end is alive), but - /// then the other end could immediately disconnect. - /// - /// The purpose of this functionality is to propagate panics among tasks. - /// If a panic is not desired, then consider using the `send_opt` method - #[experimental = "this function is being considered candidate for removal \ - to adhere to the general guidelines of rust"] - pub fn send(&self, t: T) { - if self.send_opt(t).is_err() { - panic!("sending on a closed channel"); - } - } - /// Attempts to send a value on this channel, returning it back if it could /// not be sent. /// @@ -572,24 +551,21 @@ impl<T: Send> Sender<T> { /// will be received. It is possible for the corresponding receiver to /// hang up immediately after this function returns `Ok`. /// - /// Like `send`, this method will never block. - /// - /// # Panics - /// - /// This method will never panic, it will return the message back to the - /// caller if the other end is disconnected + /// This method will never block the current thread. /// /// # Example /// /// ``` + /// use std::sync::mpsc::channel; + /// /// let (tx, rx) = channel(); /// /// // This send is always successful - /// assert_eq!(tx.send_opt(1), Ok(())); + /// tx.send(1i).unwrap(); /// /// // This send will fail because the receiver is gone /// drop(rx); - /// assert_eq!(tx.send_opt(1), Err(1)); + /// assert_eq!(tx.send(1i).err().unwrap().0, 1); /// ``` #[stable] pub fn send(&self, t: T) -> Result<(), SendError<T>> { @@ -598,11 +574,12 @@ impl<T: Send> Sender<T> { unsafe { let p = p.get(); if !(*p).sent() { - return (*p).send(t); + return (*p).send(t).map_err(SendError); } else { let a = Arc::new(RacyCell::new(stream::Packet::new())); - match (*p).upgrade(Receiver::new(Flavor::Stream(a.clone()))) { + let rx = Receiver::new(Flavor::Stream(a.clone())); + match (*p).upgrade(rx) { oneshot::UpSuccess => { let ret = (*a.get()).send(t); (a, ret) @@ -613,15 +590,19 @@ impl<T: Send> Sender<T> { // asleep (we're looking at it), so the receiver // can't go away. (*a.get()).send(t).ok().unwrap(); - token.signal(); + token.signal(); (a, Ok(())) } } } } } - Flavor::Stream(ref p) => return unsafe { (*p.get()).send(t) }, - Flavor::Shared(ref p) => return unsafe { (*p.get()).send(t) }, + Flavor::Stream(ref p) => return unsafe { + (*p.get()).send(t).map_err(SendError) + }, + Flavor::Shared(ref p) => return unsafe { + (*p.get()).send(t).map_err(SendError) + }, Flavor::Sync(..) => unreachable!(), }; @@ -629,7 +610,7 @@ impl<T: Send> Sender<T> { let tmp = Sender::new(Flavor::Stream(new_inner)); mem::swap(self.inner_mut(), tmp.inner_mut()); } - return ret; + ret.map_err(SendError) } } @@ -641,7 +622,8 @@ impl<T: Send> Clone for Sender<T> { let a = Arc::new(RacyCell::new(shared::Packet::new())); unsafe { let guard = (*a.get()).postinit_lock(); - match (*p.get()).upgrade(Receiver::new(Flavor::Shared(a.clone()))) { + let rx = Receiver::new(Flavor::Shared(a.clone())); + match (*p.get()).upgrade(rx) { oneshot::UpSuccess | oneshot::UpDisconnected => (a, None, guard), oneshot::UpWoke(task) => (a, Some(task), guard) @@ -652,7 +634,8 @@ impl<T: Send> Clone for Sender<T> { let a = Arc::new(RacyCell::new(shared::Packet::new())); unsafe { let guard = (*a.get()).postinit_lock(); - match (*p.get()).upgrade(Receiver::new(Flavor::Shared(a.clone()))) { + let rx = Receiver::new(Flavor::Shared(a.clone())); + match (*p.get()).upgrade(rx) { stream::UpSuccess | stream::UpDisconnected => (a, None, guard), stream::UpWoke(task) => (a, Some(task), guard), @@ -704,59 +687,29 @@ impl<T: Send> SyncSender<T> { /// available or a receiver is available to hand off the message to. /// /// Note that a successful send does *not* guarantee that the receiver will - /// ever see the data if there is a buffer on this channel. Messages may be + /// ever see the data if there is a buffer on this channel. Items may be /// enqueued in the internal buffer for the receiver to receive at a later /// time. If the buffer size is 0, however, it can be guaranteed that the /// receiver has indeed received the data if this function returns success. /// - /// # Panics - /// - /// Similarly to `Sender::send`, this function will panic if the - /// corresponding `Receiver` for this channel has disconnected. This - /// behavior is used to propagate panics among tasks. - /// - /// If a panic is not desired, you can achieve the same semantics with the - /// `SyncSender::send_opt` method which will not panic if the receiver - /// disconnects. - #[experimental = "this function is being considered candidate for removal \ - to adhere to the general guidelines of rust"] - pub fn send(&self, t: T) { - if self.send_opt(t).is_err() { - panic!("sending on a closed channel"); - } - } - - /// Send a value on a channel, returning it back if the receiver - /// disconnected - /// - /// This method will *block* to send the value `t` on the channel, but if - /// the value could not be sent due to the receiver disconnecting, the value - /// is returned back to the callee. This function is similar to `try_send`, - /// except that it will block if the channel is currently full. - /// - /// # Panics - /// - /// This function cannot panic. - #[unstable = "this function may be renamed to send() in the future"] - pub fn send_opt(&self, t: T) -> Result<(), T> { - unsafe { (*self.inner.get()).send(t) } + /// This function will never panic, but it may return `Err` if the + /// `Receiver` has disconnected and is no longer able to receive + /// information. + #[stable] + pub fn send(&self, t: T) -> Result<(), SendError<T>> { + unsafe { (*self.inner.get()).send(t).map_err(SendError) } } /// Attempts to send a value on this channel without blocking. /// - /// This method differs from `send_opt` by returning immediately if the + /// This method differs from `send` by returning immediately if the /// channel's buffer is full or no receiver is waiting to acquire some - /// data. Compared with `send_opt`, this function has two failure cases + /// data. Compared with `send`, this function has two failure cases /// instead of one (one for disconnection, one for a full buffer). /// /// See `SyncSender::send` for notes about guarantees of whether the /// receiver has received the data or not if this function is successful. - /// - /// # Panics - /// - /// This function cannot panic - #[unstable = "the return type of this function is candidate for \ - modification"] + #[stable] pub fn try_send(&self, t: T) -> Result<(), TrySendError<T>> { unsafe { (*self.inner.get()).try_send(t) } } @@ -787,34 +740,6 @@ impl<T: Send> Receiver<T> { Receiver { inner: UnsafeCell::new(inner) } } - /// Blocks waiting for a value on this receiver - /// - /// This function will block if necessary to wait for a corresponding send - /// on the channel from its paired `Sender` structure. This receiver will - /// be woken up when data is ready, and the data will be returned. - /// - /// # Panics - /// - /// Similar to channels, this method will trigger a task panic if the - /// other end of the channel has hung up (been deallocated). The purpose of - /// this is to propagate panics among tasks. - /// - /// If a panic is not desired, then there are two options: - /// - /// * If blocking is still desired, the `recv_opt` method will return `None` - /// when the other end hangs up - /// - /// * If blocking is not desired, then the `try_recv` method will attempt to - /// peek at a value on this receiver. - #[experimental = "this function is being considered candidate for removal \ - to adhere to the general guidelines of rust"] - pub fn recv(&self) -> T { - match self.recv_opt() { - Ok(t) => t, - Err(()) => panic!("receiving on a closed channel"), - } - } - /// Attempts to return a pending value on this receiver without blocking /// /// This method will never block the caller in order to wait for data to @@ -823,42 +748,46 @@ impl<T: Send> Receiver<T> { /// /// This is useful for a flavor of "optimistic check" before deciding to /// block on a receiver. - /// - /// # Panics - /// - /// This function cannot panic. - #[unstable = "the return type of this function may be altered"] + #[stable] pub fn try_recv(&self) -> Result<T, TryRecvError> { loop { let new_port = match *unsafe { self.inner() } { Flavor::Oneshot(ref p) => { match unsafe { (*p.get()).try_recv() } { Ok(t) => return Ok(t), - Err(oneshot::Empty) => return Err(Empty), - Err(oneshot::Disconnected) => return Err(Disconnected), + Err(oneshot::Empty) => return Err(TryRecvError::Empty), + Err(oneshot::Disconnected) => { + return Err(TryRecvError::Disconnected) + } Err(oneshot::Upgraded(rx)) => rx, } } Flavor::Stream(ref p) => { match unsafe { (*p.get()).try_recv() } { Ok(t) => return Ok(t), - Err(stream::Empty) => return Err(Empty), - Err(stream::Disconnected) => return Err(Disconnected), + Err(stream::Empty) => return Err(TryRecvError::Empty), + Err(stream::Disconnected) => { + return Err(TryRecvError::Disconnected) + } Err(stream::Upgraded(rx)) => rx, } } Flavor::Shared(ref p) => { match unsafe { (*p.get()).try_recv() } { Ok(t) => return Ok(t), - Err(shared::Empty) => return Err(Empty), - Err(shared::Disconnected) => return Err(Disconnected), + Err(shared::Empty) => return Err(TryRecvError::Empty), + Err(shared::Disconnected) => { + return Err(TryRecvError::Disconnected) + } } } Flavor::Sync(ref p) => { match unsafe { (*p.get()).try_recv() } { Ok(t) => return Ok(t), - Err(sync::Empty) => return Err(Empty), - Err(sync::Disconnected) => return Err(Disconnected), + Err(sync::Empty) => return Err(TryRecvError::Empty), + Err(sync::Disconnected) => { + return Err(TryRecvError::Disconnected) + } } } }; @@ -869,27 +798,26 @@ impl<T: Send> Receiver<T> { } } - /// Attempt to wait for a value on this receiver, but does not panic if the + /// Attempt to wait for a value on this receiver, returning an error if the /// corresponding channel has hung up. /// - /// This implementation of iterators for ports will always block if there is - /// not data available on the receiver, but it will not panic in the case - /// that the channel has been deallocated. + /// This function will always block the current thread if there is no data + /// available and it's possible for more data to be sent. Once a message is + /// sent to the corresponding `Sender`, then this receiver will wake up and + /// return that message. /// - /// In other words, this function has the same semantics as the `recv` - /// method except for the panic aspect. - /// - /// If the channel has hung up, then `Err` is returned. Otherwise `Ok` of - /// the value found on the receiver is returned. - #[unstable = "this function may be renamed to recv()"] - pub fn recv_opt(&self) -> Result<T, ()> { + /// If the corresponding `Sender` has disconnected, or it disconnects while + /// this call is blocking, this call will wake up and return `Err` to + /// indicate that no more messages can ever be received on this channel. + #[stable] + pub fn recv(&self) -> Result<T, RecvError> { loop { let new_port = match *unsafe { self.inner() } { Flavor::Oneshot(ref p) => { match unsafe { (*p.get()).recv() } { Ok(t) => return Ok(t), Err(oneshot::Empty) => return unreachable!(), - Err(oneshot::Disconnected) => return Err(()), + Err(oneshot::Disconnected) => return Err(RecvError), Err(oneshot::Upgraded(rx)) => rx, } } @@ -897,7 +825,7 @@ impl<T: Send> Receiver<T> { match unsafe { (*p.get()).recv() } { Ok(t) => return Ok(t), Err(stream::Empty) => return unreachable!(), - Err(stream::Disconnected) => return Err(()), + Err(stream::Disconnected) => return Err(RecvError), Err(stream::Upgraded(rx)) => rx, } } @@ -905,10 +833,12 @@ impl<T: Send> Receiver<T> { match unsafe { (*p.get()).recv() } { Ok(t) => return Ok(t), Err(shared::Empty) => return unreachable!(), - Err(shared::Disconnected) => return Err(()), + Err(shared::Disconnected) => return Err(RecvError), } } - Flavor::Sync(ref p) => return unsafe { (*p.get()).recv() } + Flavor::Sync(ref p) => return unsafe { + (*p.get()).recv().map_err(|()| RecvError) + } }; unsafe { mem::swap(self.inner_mut(), new_port.inner_mut()); @@ -918,9 +848,9 @@ impl<T: Send> Receiver<T> { /// Returns an iterator that will block waiting for messages, but never /// `panic!`. It will return `None` when the channel has hung up. - #[unstable] - pub fn iter<'a>(&'a self) -> Messages<'a, T> { - Messages { rx: self } + #[stable] + pub fn iter(&self) -> Iter<T> { + Iter { rx: self } } } @@ -1048,368 +978,425 @@ impl<T> RacyCell<T> { unsafe impl<T:Send> Send for RacyCell<T> { } -unsafe impl<T> kinds::Sync for RacyCell<T> { } // Oh dear +unsafe impl<T> Sync for RacyCell<T> { } // Oh dear + +impl<T> fmt::Show for SendError<T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + "sending on a closed channel".fmt(f) + } +} + +impl<T> fmt::Show for TrySendError<T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + TrySendError::Full(..) => { + "sending on a full channel".fmt(f) + } + TrySendError::Disconnected(..) => { + "sending on a closed channel".fmt(f) + } + } + } +} + +impl fmt::Show for RecvError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + "receiving on a closed channel".fmt(f) + } +} +impl fmt::Show for TryRecvError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + TryRecvError::Empty => { + "receiving on an empty channel".fmt(f) + } + TryRecvError::Disconnected => { + "receiving on a closed channel".fmt(f) + } + } + } +} #[cfg(test)] mod test { - use super::*; - use prelude::{spawn, range, Some, None, from_str, Clone, Str}; + use prelude::v1::*; + use os; + use super::*; + use thread::Thread; pub fn stress_factor() -> uint { match os::getenv("RUST_TEST_STRESS") { - Some(val) => from_str::<uint>(val.as_slice()).unwrap(), + Some(val) => val.parse().unwrap(), None => 1, } } - test! { fn smoke() { + #[test] + fn smoke() { let (tx, rx) = channel::<int>(); - tx.send(1); - assert_eq!(rx.recv(), 1); - } } + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); + } - test! { fn drop_full() { + #[test] + fn drop_full() { let (tx, _rx) = channel(); - tx.send(box 1i); - } } + tx.send(box 1i).unwrap(); + } - test! { fn drop_full_shared() { + #[test] + fn drop_full_shared() { let (tx, _rx) = channel(); drop(tx.clone()); drop(tx.clone()); - tx.send(box 1i); - } } + tx.send(box 1i).unwrap(); + } - test! { fn smoke_shared() { + #[test] + fn smoke_shared() { let (tx, rx) = channel::<int>(); - tx.send(1); - assert_eq!(rx.recv(), 1); + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); let tx = tx.clone(); - tx.send(1); - assert_eq!(rx.recv(), 1); - } } + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); + } - test! { fn smoke_threads() { + #[test] + fn smoke_threads() { let (tx, rx) = channel::<int>(); - spawn(move|| { - tx.send(1); + let _t = Thread::spawn(move|| { + tx.send(1).unwrap(); }); - assert_eq!(rx.recv(), 1); - } } + assert_eq!(rx.recv().unwrap(), 1); + } - test! { fn smoke_port_gone() { + #[test] + fn smoke_port_gone() { let (tx, rx) = channel::<int>(); drop(rx); - tx.send(1); - } #[should_fail] } + assert!(tx.send(1).is_err()); + } - test! { fn smoke_shared_port_gone() { + #[test] + fn smoke_shared_port_gone() { let (tx, rx) = channel::<int>(); drop(rx); - tx.send(1); - } #[should_fail] } + assert!(tx.send(1).is_err()) + } - test! { fn smoke_shared_port_gone2() { + #[test] + fn smoke_shared_port_gone2() { let (tx, rx) = channel::<int>(); drop(rx); let tx2 = tx.clone(); drop(tx); - tx2.send(1); - } #[should_fail] } + assert!(tx2.send(1).is_err()); + } - test! { fn port_gone_concurrent() { + #[test] + fn port_gone_concurrent() { let (tx, rx) = channel::<int>(); - spawn(move|| { - rx.recv(); + let _t = Thread::spawn(move|| { + rx.recv().unwrap(); }); - loop { tx.send(1) } - } #[should_fail] } + while tx.send(1).is_ok() {} + } - test! { fn port_gone_concurrent_shared() { + #[test] + fn port_gone_concurrent_shared() { let (tx, rx) = channel::<int>(); let tx2 = tx.clone(); - spawn(move|| { - rx.recv(); + let _t = Thread::spawn(move|| { + rx.recv().unwrap(); }); - loop { - tx.send(1); - tx2.send(1); - } - } #[should_fail] } + while tx.send(1).is_ok() && tx2.send(1).is_ok() {} + } - test! { fn smoke_chan_gone() { + #[test] + fn smoke_chan_gone() { let (tx, rx) = channel::<int>(); drop(tx); - rx.recv(); - } #[should_fail] } + assert!(rx.recv().is_err()); + } - test! { fn smoke_chan_gone_shared() { + #[test] + fn smoke_chan_gone_shared() { let (tx, rx) = channel::<()>(); let tx2 = tx.clone(); drop(tx); drop(tx2); - rx.recv(); - } #[should_fail] } + assert!(rx.recv().is_err()); + } - test! { fn chan_gone_concurrent() { + #[test] + fn chan_gone_concurrent() { let (tx, rx) = channel::<int>(); - spawn(move|| { - tx.send(1); - tx.send(1); + let _t = Thread::spawn(move|| { + tx.send(1).unwrap(); + tx.send(1).unwrap(); }); - loop { rx.recv(); } - } #[should_fail] } + while rx.recv().is_ok() {} + } - test! { fn stress() { + #[test] + fn stress() { let (tx, rx) = channel::<int>(); - spawn(move|| { - for _ in range(0u, 10000) { tx.send(1i); } + let t = Thread::spawn(move|| { + for _ in range(0u, 10000) { tx.send(1i).unwrap(); } }); for _ in range(0u, 10000) { - assert_eq!(rx.recv(), 1); + assert_eq!(rx.recv().unwrap(), 1); } - } } + t.join().ok().unwrap(); + } - test! { fn stress_shared() { + #[test] + fn stress_shared() { static AMT: uint = 10000; static NTHREADS: uint = 8; let (tx, rx) = channel::<int>(); - let (dtx, drx) = channel::<()>(); - spawn(move|| { + let t = Thread::spawn(move|| { for _ in range(0, AMT * NTHREADS) { - assert_eq!(rx.recv(), 1); + assert_eq!(rx.recv().unwrap(), 1); } match rx.try_recv() { Ok(..) => panic!(), _ => {} } - dtx.send(()); }); for _ in range(0, NTHREADS) { let tx = tx.clone(); - spawn(move|| { - for _ in range(0, AMT) { tx.send(1); } - }); + Thread::spawn(move|| { + for _ in range(0, AMT) { tx.send(1).unwrap(); } + }).detach(); } drop(tx); - drx.recv(); - } } + t.join().ok().unwrap(); + } #[test] fn send_from_outside_runtime() { let (tx1, rx1) = channel::<()>(); let (tx2, rx2) = channel::<int>(); - let (tx3, rx3) = channel::<()>(); - let tx4 = tx3.clone(); - spawn(move|| { - tx1.send(()); + let t1 = Thread::spawn(move|| { + tx1.send(()).unwrap(); for _ in range(0i, 40) { - assert_eq!(rx2.recv(), 1); + assert_eq!(rx2.recv().unwrap(), 1); } - tx3.send(()); }); - rx1.recv(); - spawn(move|| { + rx1.recv().unwrap(); + let t2 = Thread::spawn(move|| { for _ in range(0i, 40) { - tx2.send(1); + tx2.send(1).unwrap(); } - tx4.send(()); }); - rx3.recv(); - rx3.recv(); + t1.join().ok().unwrap(); + t2.join().ok().unwrap(); } #[test] fn recv_from_outside_runtime() { let (tx, rx) = channel::<int>(); - let (dtx, drx) = channel(); - spawn(move|| { + let t = Thread::spawn(move|| { for _ in range(0i, 40) { - assert_eq!(rx.recv(), 1); + assert_eq!(rx.recv().unwrap(), 1); } - dtx.send(()); }); for _ in range(0u, 40) { - tx.send(1); + tx.send(1).unwrap(); } - drx.recv(); + t.join().ok().unwrap(); } #[test] fn no_runtime() { let (tx1, rx1) = channel::<int>(); let (tx2, rx2) = channel::<int>(); - let (tx3, rx3) = channel::<()>(); - let tx4 = tx3.clone(); - spawn(move|| { - assert_eq!(rx1.recv(), 1); - tx2.send(2); - tx4.send(()); + let t1 = Thread::spawn(move|| { + assert_eq!(rx1.recv().unwrap(), 1); + tx2.send(2).unwrap(); }); - spawn(move|| { - tx1.send(1); - assert_eq!(rx2.recv(), 2); - tx3.send(()); + let t2 = Thread::spawn(move|| { + tx1.send(1).unwrap(); + assert_eq!(rx2.recv().unwrap(), 2); }); - rx3.recv(); - rx3.recv(); + t1.join().ok().unwrap(); + t2.join().ok().unwrap(); } - test! { fn oneshot_single_thread_close_port_first() { + #[test] + fn oneshot_single_thread_close_port_first() { // Simple test of closing without sending let (_tx, rx) = channel::<int>(); drop(rx); - } } + } - test! { fn oneshot_single_thread_close_chan_first() { + #[test] + fn oneshot_single_thread_close_chan_first() { // Simple test of closing without sending let (tx, _rx) = channel::<int>(); drop(tx); - } } + } - test! { fn oneshot_single_thread_send_port_close() { + #[test] + fn oneshot_single_thread_send_port_close() { // Testing that the sender cleans up the payload if receiver is closed let (tx, rx) = channel::<Box<int>>(); drop(rx); - tx.send(box 0); - } #[should_fail] } + assert!(tx.send(box 0).is_err()); + } - test! { fn oneshot_single_thread_recv_chan_close() { + #[test] + fn oneshot_single_thread_recv_chan_close() { // Receiving on a closed chan will panic let res = Thread::spawn(move|| { let (tx, rx) = channel::<int>(); drop(tx); - rx.recv(); + rx.recv().unwrap(); }).join(); // What is our res? assert!(res.is_err()); - } } + } - test! { fn oneshot_single_thread_send_then_recv() { + #[test] + fn oneshot_single_thread_send_then_recv() { let (tx, rx) = channel::<Box<int>>(); - tx.send(box 10); - assert!(rx.recv() == box 10); - } } + tx.send(box 10).unwrap(); + assert!(rx.recv().unwrap() == box 10); + } - test! { fn oneshot_single_thread_try_send_open() { + #[test] + fn oneshot_single_thread_try_send_open() { let (tx, rx) = channel::<int>(); - assert!(tx.send_opt(10).is_ok()); - assert!(rx.recv() == 10); - } } + assert!(tx.send(10).is_ok()); + assert!(rx.recv().unwrap() == 10); + } - test! { fn oneshot_single_thread_try_send_closed() { + #[test] + fn oneshot_single_thread_try_send_closed() { let (tx, rx) = channel::<int>(); drop(rx); - assert!(tx.send_opt(10).is_err()); - } } + assert!(tx.send(10).is_err()); + } - test! { fn oneshot_single_thread_try_recv_open() { + #[test] + fn oneshot_single_thread_try_recv_open() { let (tx, rx) = channel::<int>(); - tx.send(10); - assert!(rx.recv_opt() == Ok(10)); - } } + tx.send(10).unwrap(); + assert!(rx.recv() == Ok(10)); + } - test! { fn oneshot_single_thread_try_recv_closed() { + #[test] + fn oneshot_single_thread_try_recv_closed() { let (tx, rx) = channel::<int>(); drop(tx); - assert!(rx.recv_opt() == Err(())); - } } + assert!(rx.recv().is_err()); + } - test! { fn oneshot_single_thread_peek_data() { + #[test] + fn oneshot_single_thread_peek_data() { let (tx, rx) = channel::<int>(); - assert_eq!(rx.try_recv(), Err(Empty)); - tx.send(10); + assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); + tx.send(10).unwrap(); assert_eq!(rx.try_recv(), Ok(10)); - } } + } - test! { fn oneshot_single_thread_peek_close() { + #[test] + fn oneshot_single_thread_peek_close() { let (tx, rx) = channel::<int>(); drop(tx); - assert_eq!(rx.try_recv(), Err(Disconnected)); - assert_eq!(rx.try_recv(), Err(Disconnected)); - } } + assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); + assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); + } - test! { fn oneshot_single_thread_peek_open() { + #[test] + fn oneshot_single_thread_peek_open() { let (_tx, rx) = channel::<int>(); - assert_eq!(rx.try_recv(), Err(Empty)); - } } + assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); + } - test! { fn oneshot_multi_task_recv_then_send() { + #[test] + fn oneshot_multi_task_recv_then_send() { let (tx, rx) = channel::<Box<int>>(); - spawn(move|| { - assert!(rx.recv() == box 10); + let _t = Thread::spawn(move|| { + assert!(rx.recv().unwrap() == box 10); }); - tx.send(box 10); - } } + tx.send(box 10).unwrap(); + } - test! { fn oneshot_multi_task_recv_then_close() { + #[test] + fn oneshot_multi_task_recv_then_close() { let (tx, rx) = channel::<Box<int>>(); - spawn(move|| { + let _t = Thread::spawn(move|| { drop(tx); }); let res = Thread::spawn(move|| { - assert!(rx.recv() == box 10); + assert!(rx.recv().unwrap() == box 10); }).join(); assert!(res.is_err()); - } } + } - test! { fn oneshot_multi_thread_close_stress() { + #[test] + fn oneshot_multi_thread_close_stress() { for _ in range(0, stress_factor()) { let (tx, rx) = channel::<int>(); - spawn(move|| { + let _t = Thread::spawn(move|| { drop(rx); }); drop(tx); } - } } + } - test! { fn oneshot_multi_thread_send_close_stress() { + #[test] + fn oneshot_multi_thread_send_close_stress() { for _ in range(0, stress_factor()) { let (tx, rx) = channel::<int>(); - spawn(move|| { + let _t = Thread::spawn(move|| { drop(rx); }); let _ = Thread::spawn(move|| { - tx.send(1); + tx.send(1).unwrap(); }).join(); } - } } + } - test! { fn oneshot_multi_thread_recv_close_stress() { + #[test] + fn oneshot_multi_thread_recv_close_stress() { for _ in range(0, stress_factor()) { let (tx, rx) = channel::<int>(); - spawn(move|| { + Thread::spawn(move|| { let res = Thread::spawn(move|| { - rx.recv(); + rx.recv().unwrap(); }).join(); assert!(res.is_err()); - }); - spawn(move|| { - spawn(move|| { + }).detach(); + let _t = Thread::spawn(move|| { + Thread::spawn(move|| { drop(tx); - }); + }).detach(); }); } - } } + } - test! { fn oneshot_multi_thread_send_recv_stress() { + #[test] + fn oneshot_multi_thread_send_recv_stress() { for _ in range(0, stress_factor()) { let (tx, rx) = channel(); - spawn(move|| { - tx.send(box 10i); - }); - spawn(move|| { - assert!(rx.recv() == box 10i); + let _t = Thread::spawn(move|| { + tx.send(box 10i).unwrap(); }); + assert!(rx.recv().unwrap() == box 10i); } - } } + } - test! { fn stream_send_recv_stress() { + #[test] + fn stream_send_recv_stress() { for _ in range(0, stress_factor()) { let (tx, rx) = channel(); @@ -1419,69 +1406,73 @@ mod test { fn send(tx: Sender<Box<int>>, i: int) { if i == 10 { return } - spawn(move|| { - tx.send(box i); + Thread::spawn(move|| { + tx.send(box i).unwrap(); send(tx, i + 1); - }); + }).detach(); } fn recv(rx: Receiver<Box<int>>, i: int) { if i == 10 { return } - spawn(move|| { - assert!(rx.recv() == box i); + Thread::spawn(move|| { + assert!(rx.recv().unwrap() == box i); recv(rx, i + 1); - }); + }).detach(); } } - } } + } - test! { fn recv_a_lot() { + #[test] + fn recv_a_lot() { // Regression test that we don't run out of stack in scheduler context let (tx, rx) = channel(); - for _ in range(0i, 10000) { tx.send(()); } - for _ in range(0i, 10000) { rx.recv(); } - } } + for _ in range(0i, 10000) { tx.send(()).unwrap(); } + for _ in range(0i, 10000) { rx.recv().unwrap(); } + } - test! { fn shared_chan_stress() { + #[test] + fn shared_chan_stress() { let (tx, rx) = channel(); let total = stress_factor() + 100; for _ in range(0, total) { let tx = tx.clone(); - spawn(move|| { - tx.send(()); - }); + Thread::spawn(move|| { + tx.send(()).unwrap(); + }).detach(); } for _ in range(0, total) { - rx.recv(); + rx.recv().unwrap(); } - } } + } - test! { fn test_nested_recv_iter() { + #[test] + fn test_nested_recv_iter() { let (tx, rx) = channel::<int>(); let (total_tx, total_rx) = channel::<int>(); - spawn(move|| { + let _t = Thread::spawn(move|| { let mut acc = 0; for x in rx.iter() { acc += x; } - total_tx.send(acc); + total_tx.send(acc).unwrap(); }); - tx.send(3); - tx.send(1); - tx.send(2); + tx.send(3).unwrap(); + tx.send(1).unwrap(); + tx.send(2).unwrap(); drop(tx); - assert_eq!(total_rx.recv(), 6); - } } + assert_eq!(total_rx.recv().unwrap(), 6); + } - test! { fn test_recv_iter_break() { + #[test] + fn test_recv_iter_break() { let (tx, rx) = channel::<int>(); let (count_tx, count_rx) = channel(); - spawn(move|| { + let _t = Thread::spawn(move|| { let mut count = 0; for x in rx.iter() { if count >= 3 { @@ -1490,49 +1481,51 @@ mod test { count += x; } } - count_tx.send(count); + count_tx.send(count).unwrap(); }); - tx.send(2); - tx.send(2); - tx.send(2); - let _ = tx.send_opt(2); + tx.send(2).unwrap(); + tx.send(2).unwrap(); + tx.send(2).unwrap(); + let _ = tx.send(2); drop(tx); - assert_eq!(count_rx.recv(), 4); - } } + assert_eq!(count_rx.recv().unwrap(), 4); + } - test! { fn try_recv_states() { + #[test] + fn try_recv_states() { let (tx1, rx1) = channel::<int>(); let (tx2, rx2) = channel::<()>(); let (tx3, rx3) = channel::<()>(); - spawn(move|| { - rx2.recv(); - tx1.send(1); - tx3.send(()); - rx2.recv(); + let _t = Thread::spawn(move|| { + rx2.recv().unwrap(); + tx1.send(1).unwrap(); + tx3.send(()).unwrap(); + rx2.recv().unwrap(); drop(tx1); - tx3.send(()); + tx3.send(()).unwrap(); }); - assert_eq!(rx1.try_recv(), Err(Empty)); - tx2.send(()); - rx3.recv(); + assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); + tx2.send(()).unwrap(); + rx3.recv().unwrap(); assert_eq!(rx1.try_recv(), Ok(1)); - assert_eq!(rx1.try_recv(), Err(Empty)); - tx2.send(()); - rx3.recv(); - assert_eq!(rx1.try_recv(), Err(Disconnected)); - } } + assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); + tx2.send(()).unwrap(); + rx3.recv().unwrap(); + assert_eq!(rx1.try_recv(), Err(TryRecvError::Disconnected)); + } // This bug used to end up in a livelock inside of the Receiver destructor // because the internal state of the Shared packet was corrupted - test! { fn destroy_upgraded_shared_port_when_sender_still_active() { + #[test] + fn destroy_upgraded_shared_port_when_sender_still_active() { let (tx, rx) = channel(); let (tx2, rx2) = channel(); - spawn(move|| { - rx.recv(); // wait on a oneshot + let _t = Thread::spawn(move|| { + rx.recv().unwrap(); // wait on a oneshot drop(rx); // destroy a shared - tx2.send(()); + tx2.send(()).unwrap(); }); // make sure the other task has gone to sleep for _ in range(0u, 5000) { Thread::yield_now(); } @@ -1540,303 +1533,334 @@ mod test { // upgrade to a shared chan and send a message let t = tx.clone(); drop(tx); - t.send(()); + t.send(()).unwrap(); // wait for the child task to exit before we exit - rx2.recv(); - }} + rx2.recv().unwrap(); + } } #[cfg(test)] mod sync_tests { - use prelude::*; + use prelude::v1::*; + use os; + use thread::Thread; + use super::*; pub fn stress_factor() -> uint { match os::getenv("RUST_TEST_STRESS") { - Some(val) => from_str::<uint>(val.as_slice()).unwrap(), + Some(val) => val.parse().unwrap(), None => 1, } } - test! { fn smoke() { + #[test] + fn smoke() { let (tx, rx) = sync_channel::<int>(1); - tx.send(1); - assert_eq!(rx.recv(), 1); - } } + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); + } - test! { fn drop_full() { + #[test] + fn drop_full() { let (tx, _rx) = sync_channel(1); - tx.send(box 1i); - } } + tx.send(box 1i).unwrap(); + } - test! { fn smoke_shared() { + #[test] + fn smoke_shared() { let (tx, rx) = sync_channel::<int>(1); - tx.send(1); - assert_eq!(rx.recv(), 1); + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); let tx = tx.clone(); - tx.send(1); - assert_eq!(rx.recv(), 1); - } } + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); + } - test! { fn smoke_threads() { + #[test] + fn smoke_threads() { let (tx, rx) = sync_channel::<int>(0); - spawn(move|| { - tx.send(1); + let _t = Thread::spawn(move|| { + tx.send(1).unwrap(); }); - assert_eq!(rx.recv(), 1); - } } + assert_eq!(rx.recv().unwrap(), 1); + } - test! { fn smoke_port_gone() { + #[test] + fn smoke_port_gone() { let (tx, rx) = sync_channel::<int>(0); drop(rx); - tx.send(1); - } #[should_fail] } + assert!(tx.send(1).is_err()); + } - test! { fn smoke_shared_port_gone2() { + #[test] + fn smoke_shared_port_gone2() { let (tx, rx) = sync_channel::<int>(0); drop(rx); let tx2 = tx.clone(); drop(tx); - tx2.send(1); - } #[should_fail] } + assert!(tx2.send(1).is_err()); + } - test! { fn port_gone_concurrent() { + #[test] + fn port_gone_concurrent() { let (tx, rx) = sync_channel::<int>(0); - spawn(move|| { - rx.recv(); + let _t = Thread::spawn(move|| { + rx.recv().unwrap(); }); - loop { tx.send(1) } - } #[should_fail] } + while tx.send(1).is_ok() {} + } - test! { fn port_gone_concurrent_shared() { + #[test] + fn port_gone_concurrent_shared() { let (tx, rx) = sync_channel::<int>(0); let tx2 = tx.clone(); - spawn(move|| { - rx.recv(); + let _t = Thread::spawn(move|| { + rx.recv().unwrap(); }); - loop { - tx.send(1); - tx2.send(1); - } - } #[should_fail] } + while tx.send(1).is_ok() && tx2.send(1).is_ok() {} + } - test! { fn smoke_chan_gone() { + #[test] + fn smoke_chan_gone() { let (tx, rx) = sync_channel::<int>(0); drop(tx); - rx.recv(); - } #[should_fail] } + assert!(rx.recv().is_err()); + } - test! { fn smoke_chan_gone_shared() { + #[test] + fn smoke_chan_gone_shared() { let (tx, rx) = sync_channel::<()>(0); let tx2 = tx.clone(); drop(tx); drop(tx2); - rx.recv(); - } #[should_fail] } + assert!(rx.recv().is_err()); + } - test! { fn chan_gone_concurrent() { + #[test] + fn chan_gone_concurrent() { let (tx, rx) = sync_channel::<int>(0); - spawn(move|| { - tx.send(1); - tx.send(1); - }); - loop { rx.recv(); } - } #[should_fail] } + Thread::spawn(move|| { + tx.send(1).unwrap(); + tx.send(1).unwrap(); + }).detach(); + while rx.recv().is_ok() {} + } - test! { fn stress() { + #[test] + fn stress() { let (tx, rx) = sync_channel::<int>(0); - spawn(move|| { - for _ in range(0u, 10000) { tx.send(1); } - }); + Thread::spawn(move|| { + for _ in range(0u, 10000) { tx.send(1).unwrap(); } + }).detach(); for _ in range(0u, 10000) { - assert_eq!(rx.recv(), 1); + assert_eq!(rx.recv().unwrap(), 1); } - } } + } - test! { fn stress_shared() { + #[test] + fn stress_shared() { static AMT: uint = 1000; static NTHREADS: uint = 8; let (tx, rx) = sync_channel::<int>(0); let (dtx, drx) = sync_channel::<()>(0); - spawn(move|| { + Thread::spawn(move|| { for _ in range(0, AMT * NTHREADS) { - assert_eq!(rx.recv(), 1); + assert_eq!(rx.recv().unwrap(), 1); } match rx.try_recv() { Ok(..) => panic!(), _ => {} } - dtx.send(()); - }); + dtx.send(()).unwrap(); + }).detach(); for _ in range(0, NTHREADS) { let tx = tx.clone(); - spawn(move|| { - for _ in range(0, AMT) { tx.send(1); } - }); + Thread::spawn(move|| { + for _ in range(0, AMT) { tx.send(1).unwrap(); } + }).detach(); } drop(tx); - drx.recv(); - } } + drx.recv().unwrap(); + } - test! { fn oneshot_single_thread_close_port_first() { + #[test] + fn oneshot_single_thread_close_port_first() { // Simple test of closing without sending let (_tx, rx) = sync_channel::<int>(0); drop(rx); - } } + } - test! { fn oneshot_single_thread_close_chan_first() { + #[test] + fn oneshot_single_thread_close_chan_first() { // Simple test of closing without sending let (tx, _rx) = sync_channel::<int>(0); drop(tx); - } } + } - test! { fn oneshot_single_thread_send_port_close() { + #[test] + fn oneshot_single_thread_send_port_close() { // Testing that the sender cleans up the payload if receiver is closed let (tx, rx) = sync_channel::<Box<int>>(0); drop(rx); - tx.send(box 0); - } #[should_fail] } + assert!(tx.send(box 0).is_err()); + } - test! { fn oneshot_single_thread_recv_chan_close() { + #[test] + fn oneshot_single_thread_recv_chan_close() { // Receiving on a closed chan will panic let res = Thread::spawn(move|| { let (tx, rx) = sync_channel::<int>(0); drop(tx); - rx.recv(); + rx.recv().unwrap(); }).join(); // What is our res? assert!(res.is_err()); - } } + } - test! { fn oneshot_single_thread_send_then_recv() { + #[test] + fn oneshot_single_thread_send_then_recv() { let (tx, rx) = sync_channel::<Box<int>>(1); - tx.send(box 10); - assert!(rx.recv() == box 10); - } } + tx.send(box 10).unwrap(); + assert!(rx.recv().unwrap() == box 10); + } - test! { fn oneshot_single_thread_try_send_open() { + #[test] + fn oneshot_single_thread_try_send_open() { let (tx, rx) = sync_channel::<int>(1); assert_eq!(tx.try_send(10), Ok(())); - assert!(rx.recv() == 10); - } } + assert!(rx.recv().unwrap() == 10); + } - test! { fn oneshot_single_thread_try_send_closed() { + #[test] + fn oneshot_single_thread_try_send_closed() { let (tx, rx) = sync_channel::<int>(0); drop(rx); - assert_eq!(tx.try_send(10), Err(RecvDisconnected(10))); - } } + assert_eq!(tx.try_send(10), Err(TrySendError::Disconnected(10))); + } - test! { fn oneshot_single_thread_try_send_closed2() { + #[test] + fn oneshot_single_thread_try_send_closed2() { let (tx, _rx) = sync_channel::<int>(0); - assert_eq!(tx.try_send(10), Err(Full(10))); - } } + assert_eq!(tx.try_send(10), Err(TrySendError::Full(10))); + } - test! { fn oneshot_single_thread_try_recv_open() { + #[test] + fn oneshot_single_thread_try_recv_open() { let (tx, rx) = sync_channel::<int>(1); - tx.send(10); - assert!(rx.recv_opt() == Ok(10)); - } } + tx.send(10).unwrap(); + assert!(rx.recv() == Ok(10)); + } - test! { fn oneshot_single_thread_try_recv_closed() { + #[test] + fn oneshot_single_thread_try_recv_closed() { let (tx, rx) = sync_channel::<int>(0); drop(tx); - assert!(rx.recv_opt() == Err(())); - } } + assert!(rx.recv().is_err()); + } - test! { fn oneshot_single_thread_peek_data() { + #[test] + fn oneshot_single_thread_peek_data() { let (tx, rx) = sync_channel::<int>(1); - assert_eq!(rx.try_recv(), Err(Empty)); - tx.send(10); + assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); + tx.send(10).unwrap(); assert_eq!(rx.try_recv(), Ok(10)); - } } + } - test! { fn oneshot_single_thread_peek_close() { + #[test] + fn oneshot_single_thread_peek_close() { let (tx, rx) = sync_channel::<int>(0); drop(tx); - assert_eq!(rx.try_recv(), Err(Disconnected)); - assert_eq!(rx.try_recv(), Err(Disconnected)); - } } + assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); + assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); + } - test! { fn oneshot_single_thread_peek_open() { + #[test] + fn oneshot_single_thread_peek_open() { let (_tx, rx) = sync_channel::<int>(0); - assert_eq!(rx.try_recv(), Err(Empty)); - } } + assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); + } - test! { fn oneshot_multi_task_recv_then_send() { + #[test] + fn oneshot_multi_task_recv_then_send() { let (tx, rx) = sync_channel::<Box<int>>(0); - spawn(move|| { - assert!(rx.recv() == box 10); + let _t = Thread::spawn(move|| { + assert!(rx.recv().unwrap() == box 10); }); - tx.send(box 10); - } } + tx.send(box 10).unwrap(); + } - test! { fn oneshot_multi_task_recv_then_close() { + #[test] + fn oneshot_multi_task_recv_then_close() { let (tx, rx) = sync_channel::<Box<int>>(0); - spawn(move|| { + let _t = Thread::spawn(move|| { drop(tx); }); let res = Thread::spawn(move|| { - assert!(rx.recv() == box 10); + assert!(rx.recv().unwrap() == box 10); }).join(); assert!(res.is_err()); - } } + } - test! { fn oneshot_multi_thread_close_stress() { + #[test] + fn oneshot_multi_thread_close_stress() { for _ in range(0, stress_factor()) { let (tx, rx) = sync_channel::<int>(0); - spawn(move|| { + let _t = Thread::spawn(move|| { drop(rx); }); drop(tx); } - } } + } - test! { fn oneshot_multi_thread_send_close_stress() { + #[test] + fn oneshot_multi_thread_send_close_stress() { for _ in range(0, stress_factor()) { let (tx, rx) = sync_channel::<int>(0); - spawn(move|| { + let _t = Thread::spawn(move|| { drop(rx); }); let _ = Thread::spawn(move || { - tx.send(1); + tx.send(1).unwrap(); }).join(); } - } } + } - test! { fn oneshot_multi_thread_recv_close_stress() { + #[test] + fn oneshot_multi_thread_recv_close_stress() { for _ in range(0, stress_factor()) { let (tx, rx) = sync_channel::<int>(0); - spawn(move|| { + let _t = Thread::spawn(move|| { let res = Thread::spawn(move|| { - rx.recv(); + rx.recv().unwrap(); }).join(); assert!(res.is_err()); }); - spawn(move|| { - spawn(move|| { + let _t = Thread::spawn(move|| { + Thread::spawn(move|| { drop(tx); - }); + }).detach(); }); } - } } + } - test! { fn oneshot_multi_thread_send_recv_stress() { + #[test] + fn oneshot_multi_thread_send_recv_stress() { for _ in range(0, stress_factor()) { let (tx, rx) = sync_channel::<Box<int>>(0); - spawn(move|| { - tx.send(box 10i); - }); - spawn(move|| { - assert!(rx.recv() == box 10i); + let _t = Thread::spawn(move|| { + tx.send(box 10i).unwrap(); }); + assert!(rx.recv().unwrap() == box 10i); } - } } + } - test! { fn stream_send_recv_stress() { + #[test] + fn stream_send_recv_stress() { for _ in range(0, stress_factor()) { let (tx, rx) = sync_channel::<Box<int>>(0); @@ -1846,69 +1870,73 @@ mod sync_tests { fn send(tx: SyncSender<Box<int>>, i: int) { if i == 10 { return } - spawn(move|| { - tx.send(box i); + Thread::spawn(move|| { + tx.send(box i).unwrap(); send(tx, i + 1); - }); + }).detach(); } fn recv(rx: Receiver<Box<int>>, i: int) { if i == 10 { return } - spawn(move|| { - assert!(rx.recv() == box i); + Thread::spawn(move|| { + assert!(rx.recv().unwrap() == box i); recv(rx, i + 1); - }); + }).detach(); } } - } } + } - test! { fn recv_a_lot() { + #[test] + fn recv_a_lot() { // Regression test that we don't run out of stack in scheduler context let (tx, rx) = sync_channel(10000); - for _ in range(0u, 10000) { tx.send(()); } - for _ in range(0u, 10000) { rx.recv(); } - } } + for _ in range(0u, 10000) { tx.send(()).unwrap(); } + for _ in range(0u, 10000) { rx.recv().unwrap(); } + } - test! { fn shared_chan_stress() { + #[test] + fn shared_chan_stress() { let (tx, rx) = sync_channel(0); let total = stress_factor() + 100; for _ in range(0, total) { let tx = tx.clone(); - spawn(move|| { - tx.send(()); - }); + Thread::spawn(move|| { + tx.send(()).unwrap(); + }).detach(); } for _ in range(0, total) { - rx.recv(); + rx.recv().unwrap(); } - } } + } - test! { fn test_nested_recv_iter() { + #[test] + fn test_nested_recv_iter() { let (tx, rx) = sync_channel::<int>(0); let (total_tx, total_rx) = sync_channel::<int>(0); - spawn(move|| { + let _t = Thread::spawn(move|| { let mut acc = 0; for x in rx.iter() { acc += x; } - total_tx.send(acc); + total_tx.send(acc).unwrap(); }); - tx.send(3); - tx.send(1); - tx.send(2); + tx.send(3).unwrap(); + tx.send(1).unwrap(); + tx.send(2).unwrap(); drop(tx); - assert_eq!(total_rx.recv(), 6); - } } + assert_eq!(total_rx.recv().unwrap(), 6); + } - test! { fn test_recv_iter_break() { + #[test] + fn test_recv_iter_break() { let (tx, rx) = sync_channel::<int>(0); let (count_tx, count_rx) = sync_channel(0); - spawn(move|| { + let _t = Thread::spawn(move|| { let mut count = 0; for x in rx.iter() { if count >= 3 { @@ -1917,49 +1945,51 @@ mod sync_tests { count += x; } } - count_tx.send(count); + count_tx.send(count).unwrap(); }); - tx.send(2); - tx.send(2); - tx.send(2); + tx.send(2).unwrap(); + tx.send(2).unwrap(); + tx.send(2).unwrap(); let _ = tx.try_send(2); drop(tx); - assert_eq!(count_rx.recv(), 4); - } } + assert_eq!(count_rx.recv().unwrap(), 4); + } - test! { fn try_recv_states() { + #[test] + fn try_recv_states() { let (tx1, rx1) = sync_channel::<int>(1); let (tx2, rx2) = sync_channel::<()>(1); let (tx3, rx3) = sync_channel::<()>(1); - spawn(move|| { - rx2.recv(); - tx1.send(1); - tx3.send(()); - rx2.recv(); + let _t = Thread::spawn(move|| { + rx2.recv().unwrap(); + tx1.send(1).unwrap(); + tx3.send(()).unwrap(); + rx2.recv().unwrap(); drop(tx1); - tx3.send(()); + tx3.send(()).unwrap(); }); - assert_eq!(rx1.try_recv(), Err(Empty)); - tx2.send(()); - rx3.recv(); + assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); + tx2.send(()).unwrap(); + rx3.recv().unwrap(); assert_eq!(rx1.try_recv(), Ok(1)); - assert_eq!(rx1.try_recv(), Err(Empty)); - tx2.send(()); - rx3.recv(); - assert_eq!(rx1.try_recv(), Err(Disconnected)); - } } + assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); + tx2.send(()).unwrap(); + rx3.recv().unwrap(); + assert_eq!(rx1.try_recv(), Err(TryRecvError::Disconnected)); + } // This bug used to end up in a livelock inside of the Receiver destructor // because the internal state of the Shared packet was corrupted - test! { fn destroy_upgraded_shared_port_when_sender_still_active() { + #[test] + fn destroy_upgraded_shared_port_when_sender_still_active() { let (tx, rx) = sync_channel::<()>(0); let (tx2, rx2) = sync_channel::<()>(0); - spawn(move|| { - rx.recv(); // wait on a oneshot + let _t = Thread::spawn(move|| { + rx.recv().unwrap(); // wait on a oneshot drop(rx); // destroy a shared - tx2.send(()); + tx2.send(()).unwrap(); }); // make sure the other task has gone to sleep for _ in range(0u, 5000) { Thread::yield_now(); } @@ -1967,92 +1997,91 @@ mod sync_tests { // upgrade to a shared chan and send a message let t = tx.clone(); drop(tx); - t.send(()); + t.send(()).unwrap(); // wait for the child task to exit before we exit - rx2.recv(); - } } + rx2.recv().unwrap(); + } - test! { fn send_opt1() { + #[test] + fn send1() { let (tx, rx) = sync_channel::<int>(0); - spawn(move|| { rx.recv(); }); - assert_eq!(tx.send_opt(1), Ok(())); - } } + let _t = Thread::spawn(move|| { rx.recv().unwrap(); }); + assert_eq!(tx.send(1), Ok(())); + } - test! { fn send_opt2() { + #[test] + fn send2() { let (tx, rx) = sync_channel::<int>(0); - spawn(move|| { drop(rx); }); - assert_eq!(tx.send_opt(1), Err(1)); - } } + let _t = Thread::spawn(move|| { drop(rx); }); + assert!(tx.send(1).is_err()); + } - test! { fn send_opt3() { + #[test] + fn send3() { let (tx, rx) = sync_channel::<int>(1); - assert_eq!(tx.send_opt(1), Ok(())); - spawn(move|| { drop(rx); }); - assert_eq!(tx.send_opt(1), Err(1)); - } } + assert_eq!(tx.send(1), Ok(())); + let _t =Thread::spawn(move|| { drop(rx); }); + assert!(tx.send(1).is_err()); + } - test! { fn send_opt4() { + #[test] + fn send4() { let (tx, rx) = sync_channel::<int>(0); let tx2 = tx.clone(); let (done, donerx) = channel(); let done2 = done.clone(); - spawn(move|| { - assert_eq!(tx.send_opt(1), Err(1)); - done.send(()); + let _t = Thread::spawn(move|| { + assert!(tx.send(1).is_err()); + done.send(()).unwrap(); }); - spawn(move|| { - assert_eq!(tx2.send_opt(2), Err(2)); - done2.send(()); + let _t = Thread::spawn(move|| { + assert!(tx2.send(2).is_err()); + done2.send(()).unwrap(); }); drop(rx); - donerx.recv(); - donerx.recv(); - } } + donerx.recv().unwrap(); + donerx.recv().unwrap(); + } - test! { fn try_send1() { + #[test] + fn try_send1() { let (tx, _rx) = sync_channel::<int>(0); - assert_eq!(tx.try_send(1), Err(Full(1))); - } } + assert_eq!(tx.try_send(1), Err(TrySendError::Full(1))); + } - test! { fn try_send2() { + #[test] + fn try_send2() { let (tx, _rx) = sync_channel::<int>(1); assert_eq!(tx.try_send(1), Ok(())); - assert_eq!(tx.try_send(1), Err(Full(1))); - } } + assert_eq!(tx.try_send(1), Err(TrySendError::Full(1))); + } - test! { fn try_send3() { + #[test] + fn try_send3() { let (tx, rx) = sync_channel::<int>(1); assert_eq!(tx.try_send(1), Ok(())); drop(rx); - assert_eq!(tx.try_send(1), Err(RecvDisconnected(1))); - } } - - test! { fn try_send4() { - let (tx, rx) = sync_channel::<int>(0); - spawn(move|| { - for _ in range(0u, 1000) { Thread::yield_now(); } - assert_eq!(tx.try_send(1), Ok(())); - }); - assert_eq!(rx.recv(), 1); - } #[ignore(reason = "flaky on libnative")] } + assert_eq!(tx.try_send(1), Err(TrySendError::Disconnected(1))); + } - test! { fn issue_15761() { + #[test] + fn issue_15761() { fn repro() { let (tx1, rx1) = sync_channel::<()>(3); let (tx2, rx2) = sync_channel::<()>(3); - spawn(move|| { - rx1.recv(); + let _t = Thread::spawn(move|| { + rx1.recv().unwrap(); tx2.try_send(()).unwrap(); }); tx1.try_send(()).unwrap(); - rx2.recv(); + rx2.recv().unwrap(); } for _ in range(0u, 100) { repro() } - } } + } } diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index e21aa3ef7e9..4afd5bb63f4 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -41,7 +41,7 @@ use sys_common::rwlock as sys; /// ``` /// use std::sync::RwLock; /// -/// let lock = RwLock::new(5); +/// let lock = RwLock::new(5i); /// /// // many reader locks can be held at once /// { |
