about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-02-15 23:36:26 -0800
committerbors <bors@rust-lang.org>2014-02-15 23:36:26 -0800
commitb36340b6269e1b54fb4aa3ff49a90262fb2d953c (patch)
tree9004b3c068063762803d4c5e1d786e3b3340ee4c
parent5d4fd50af3c16ffe43c8035b929374e13bb76793 (diff)
parentbea7862d9470c33b7b3e21a552a991e3b948aa29 (diff)
downloadrust-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.rs10
-rw-r--r--src/libstd/comm/stream.rs25
-rw-r--r--src/libstd/num/f32.rs1
-rw-r--r--src/libstd/num/f64.rs1
-rw-r--r--src/libstd/task.rs1
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.