about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2014-03-09 23:20:05 -0700
committerAlex Crichton <alex@alexcrichton.com>2014-03-12 13:39:47 -0700
commit80f92f5c5fedadd131842977c0b9b21806f3902f (patch)
tree4775273a78be8b003119b31a57b6415c96f0eefa /src/libstd
parent3316a0e6b2ad9352bab58e7c046ef3d212411d82 (diff)
downloadrust-80f92f5c5fedadd131842977c0b9b21806f3902f.tar.gz
rust-80f92f5c5fedadd131842977c0b9b21806f3902f.zip
std: Relax an assertion in oneshot selection
The assertion was erroneously ensuring that there was no data on the port when
the port had selection aborted on it. This assertion was written in error
because it's possible for data to be waiting on a port, even after it was
disconnected. When aborting selection, if we see that there's data on the port,
then we return true that data is available on the port.

Closes #12802
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/comm/oneshot.rs19
-rw-r--r--src/libstd/comm/select.rs52
2 files changed, 64 insertions, 7 deletions
diff --git a/src/libstd/comm/oneshot.rs b/src/libstd/comm/oneshot.rs
index 9deccfeb875..0f78c1971bc 100644
--- a/src/libstd/comm/oneshot.rs
+++ b/src/libstd/comm/oneshot.rs
@@ -339,14 +339,19 @@ impl<T: Send> Packet<T> {
             DATA => Ok(true),
 
             // If the other end has hung up, then we have complete ownership
-            // of the port. We need to check to see if there was an upgrade
-            // requested, and if so, the other end needs to have its selection
-            // aborted.
+            // of the port. First, check if there was data waiting for us. This
+            // is possible if the other end sent something and then hung up.
+            //
+            // We then need to check to see if there was an upgrade requested,
+            // and if so, the upgraded port needs to have its selection aborted.
             DISCONNECTED => {
-                assert!(self.data.is_none());
-                match mem::replace(&mut self.upgrade, SendUsed) {
-                    GoUp(port) => Err(port),
-                    _ => Ok(true),
+                if self.data.is_some() {
+                    Ok(true)
+                } else {
+                    match mem::replace(&mut self.upgrade, SendUsed) {
+                        GoUp(port) => Err(port),
+                        _ => Ok(true),
+                    }
                 }
             }
 
diff --git a/src/libstd/comm/select.rs b/src/libstd/comm/select.rs
index 75e7265705a..3c6828fc14f 100644
--- a/src/libstd/comm/select.rs
+++ b/src/libstd/comm/select.rs
@@ -597,4 +597,56 @@ mod test {
         unsafe { h.add(); }
         assert_eq!(s.wait2(false), h.id);
     })
+
+    test!(fn oneshot_data_waiting() {
+        let (p, c) = Chan::new();
+        let (p2, c2) = Chan::new();
+        spawn(proc() {
+            select! {
+                () = p.recv() => {}
+            }
+            c2.send(());
+        });
+
+        for _ in range(0, 100) { task::deschedule() }
+        c.send(());
+        p2.recv();
+    })
+
+    test!(fn stream_data_waiting() {
+        let (p, c) = Chan::new();
+        let (p2, c2) = Chan::new();
+        c.send(());
+        c.send(());
+        p.recv();
+        p.recv();
+        spawn(proc() {
+            select! {
+                () = p.recv() => {}
+            }
+            c2.send(());
+        });
+
+        for _ in range(0, 100) { task::deschedule() }
+        c.send(());
+        p2.recv();
+    })
+
+    test!(fn shared_data_waiting() {
+        let (p, c) = Chan::new();
+        let (p2, c2) = Chan::new();
+        drop(c.clone());
+        c.send(());
+        p.recv();
+        spawn(proc() {
+            select! {
+                () = p.recv() => {}
+            }
+            c2.send(());
+        });
+
+        for _ in range(0, 100) { task::deschedule() }
+        c.send(());
+        p2.recv();
+    })
 }