about summary refs log tree commit diff
path: root/src/libsync
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2014-07-17 17:23:38 -0700
committerAlex Crichton <alex@alexcrichton.com>2014-07-17 18:32:25 -0700
commit31eb00c022aba208921046cdec046f77a96ec98c (patch)
tree8f85973a73a7078c9bd276892854ea40c33eec76 /src/libsync
parente288fc6a996562c5e4aca46e22c1da46eb3d086b (diff)
downloadrust-31eb00c022aba208921046cdec046f77a96ec98c.tar.gz
rust-31eb00c022aba208921046cdec046f77a96ec98c.zip
sync: Ensure try_send() wakes up receivers
This branch of try_send() just forgot to wake up any receiver waiting for data.

Closes #15761
Diffstat (limited to 'src/libsync')
-rw-r--r--src/libsync/comm/mod.rs19
-rw-r--r--src/libsync/comm/sync.rs8
2 files changed, 26 insertions, 1 deletions
diff --git a/src/libsync/comm/mod.rs b/src/libsync/comm/mod.rs
index e9a303634fe..2aec3952125 100644
--- a/src/libsync/comm/mod.rs
+++ b/src/libsync/comm/mod.rs
@@ -2098,4 +2098,23 @@ mod sync_tests {
         });
         assert_eq!(rx.recv(), 1);
     } #[ignore(reason = "flaky on libnative")])
+
+    test!(fn issue_15761() {
+        fn repro() {
+            let (tx1, rx1) = sync_channel::<()>(3);
+            let (tx2, rx2) = sync_channel::<()>(3);
+
+            spawn(proc() {
+                rx1.recv();
+                tx2.try_send(()).unwrap();
+            });
+
+            tx1.try_send(()).unwrap();
+            rx2.recv();
+        }
+
+        for _ in range(0u, 100) {
+            repro()
+        }
+    })
 }
diff --git a/src/libsync/comm/sync.rs b/src/libsync/comm/sync.rs
index cc3c2197c13..1d5a7d6ed9f 100644
--- a/src/libsync/comm/sync.rs
+++ b/src/libsync/comm/sync.rs
@@ -218,9 +218,15 @@ impl<T: Send> Packet<T> {
             }
         } else {
             // If the buffer has some space and the capacity isn't 0, then we
-            // just enqueue the data for later retrieval.
+            // just enqueue the data for later retrieval, ensuring to wake up
+            // any blocked receiver if there is one.
             assert!(state.buf.size() < state.buf.cap());
             state.buf.enqueue(t);
+            match mem::replace(&mut state.blocker, NoneBlocked) {
+                BlockedReceiver(task) => wakeup(task, guard),
+                NoneBlocked => {}
+                BlockedSender(..) => unreachable!(),
+            }
             Ok(())
         }
     }