diff options
| author | bors <bors@rust-lang.org> | 2014-02-15 23:36:26 -0800 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2014-02-15 23:36:26 -0800 |
| commit | b36340b6269e1b54fb4aa3ff49a90262fb2d953c (patch) | |
| tree | 9004b3c068063762803d4c5e1d786e3b3340ee4c | |
| parent | 5d4fd50af3c16ffe43c8035b929374e13bb76793 (diff) | |
| parent | bea7862d9470c33b7b3e21a552a991e3b948aa29 (diff) | |
| download | rust-b36340b6269e1b54fb4aa3ff49a90262fb2d953c.tar.gz rust-b36340b6269e1b54fb4aa3ff49a90262fb2d953c.zip | |
auto merge of #12302 : alexcrichton/rust/issue-12295, r=brson
The previous code erroneously assumed that 'steals > cnt' was always true, but that was a false assumption. The code was altered to decrement steals to a minimum of 0 instead of taking all of cnt into account. I didn't include the exact test from #12295 because it could run for quite awhile, and instead set the threshold for MAX_STEALS to much lower during testing. I found that this triggered the old bug quite frequently when running without this fix. Closes #12295
| -rw-r--r-- | src/libstd/comm/shared.rs | 10 | ||||
| -rw-r--r-- | src/libstd/comm/stream.rs | 25 | ||||
| -rw-r--r-- | src/libstd/num/f32.rs | 1 | ||||
| -rw-r--r-- | src/libstd/num/f64.rs | 1 | ||||
| -rw-r--r-- | src/libstd/task.rs | 1 |
5 files changed, 28 insertions, 10 deletions
diff --git a/src/libstd/comm/shared.rs b/src/libstd/comm/shared.rs index 031ce991ba4..832cdca12f0 100644 --- a/src/libstd/comm/shared.rs +++ b/src/libstd/comm/shared.rs @@ -18,6 +18,7 @@ /// module. You'll also note that the implementation of the shared and stream /// channels are quite similar, and this is no coincidence! +use cmp; use int; use iter::Iterator; use kinds::Send; @@ -35,6 +36,9 @@ use mpsc = sync::mpsc_queue; static DISCONNECTED: int = int::MIN; static FUDGE: int = 1024; +#[cfg(test)] +static MAX_STEALS: int = 5; +#[cfg(not(test))] static MAX_STEALS: int = 1 << 20; pub struct Packet<T> { @@ -307,7 +311,11 @@ impl<T: Send> Packet<T> { DISCONNECTED => { self.cnt.store(DISCONNECTED, atomics::SeqCst); } - n => { self.steals -= n; } + n => { + let m = cmp::min(n, self.steals); + self.steals -= m; + self.cnt.fetch_add(n - m, atomics::SeqCst); + } } assert!(self.steals >= 0); } diff --git a/src/libstd/comm/stream.rs b/src/libstd/comm/stream.rs index 9c972a3771c..f1988dbbeed 100644 --- a/src/libstd/comm/stream.rs +++ b/src/libstd/comm/stream.rs @@ -17,6 +17,7 @@ /// High level implementation details can be found in the comment of the parent /// module. +use cmp; use comm::Port; use int; use iter::Iterator; @@ -32,6 +33,9 @@ use sync::atomics; use vec::OwnedVector; static DISCONNECTED: int = int::MIN; +#[cfg(test)] +static MAX_STEALS: int = 5; +#[cfg(not(test))] static MAX_STEALS: int = 1 << 20; pub struct Packet<T> { @@ -198,11 +202,16 @@ impl<T: Send> Packet<T> { pub fn try_recv(&mut self) -> Result<T, Failure<T>> { match self.queue.pop() { // If we stole some data, record to that effect (this will be - // factored into cnt later on). Note that we don't allow steals to - // grow without bound in order to prevent eventual overflow of - // either steals or cnt as an overflow would have catastrophic - // results. Also note that we don't unconditionally set steals to 0 - // because it can be true that steals > cnt. + // factored into cnt later on). + // + // Note that we don't allow steals to grow without bound in order to + // prevent eventual overflow of either steals or cnt as an overflow + // would have catastrophic results. Sometimes, steals > cnt, but + // other times cnt > steals, so we don't know the relation between + // steals and cnt. This code path is executed only rarely, so we do + // a pretty slow operation, of swapping 0 into cnt, taking steals + // down as much as possible (without going negative), and then + // adding back in whatever we couldn't factor into steals. Some(data) => { self.steals += 1; if self.steals > MAX_STEALS { @@ -210,7 +219,11 @@ impl<T: Send> Packet<T> { DISCONNECTED => { self.cnt.store(DISCONNECTED, atomics::SeqCst); } - n => { self.steals -= n; } + n => { + let m = cmp::min(n, self.steals); + self.steals -= m; + self.cnt.fetch_add(n - m, atomics::SeqCst); + } } assert!(self.steals >= 0); } diff --git a/src/libstd/num/f32.rs b/src/libstd/num/f32.rs index 9951405fa0c..f418be262ed 100644 --- a/src/libstd/num/f32.rs +++ b/src/libstd/num/f32.rs @@ -867,7 +867,6 @@ impl num::FromStrRadix for f32 { #[cfg(test)] mod tests { use f32::*; - use prelude::*; use num::*; use num; diff --git a/src/libstd/num/f64.rs b/src/libstd/num/f64.rs index 643dcc5bd4b..1b1aaf68470 100644 --- a/src/libstd/num/f64.rs +++ b/src/libstd/num/f64.rs @@ -869,7 +869,6 @@ impl num::FromStrRadix for f64 { #[cfg(test)] mod tests { use f64::*; - use prelude::*; use num::*; use num; diff --git a/src/libstd/task.rs b/src/libstd/task.rs index 1065d3b3941..ceccd918140 100644 --- a/src/libstd/task.rs +++ b/src/libstd/task.rs @@ -65,7 +65,6 @@ use rt::task::Task; use str::{Str, SendStr, IntoMaybeOwned}; #[cfg(test)] use any::{AnyOwnExt, AnyRefExt}; -#[cfg(test)] use ptr; #[cfg(test)] use result; /// Indicates the manner in which a task exited. |
