about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-02-20 03:11:48 -0800
committerbors <bors@rust-lang.org>2014-02-20 03:11:48 -0800
commit47b05278d0679802f271e3f73cb22979dfc229de (patch)
treea5b2e125d87e11968285c52a2c7ed37651e99b84 /src/libstd
parent25ba057fad54da946bb3d72925c9a93b0abe61ac (diff)
parent765a4e9fe35014eed3c7f60f8c7030ecb537871b (diff)
downloadrust-47b05278d0679802f271e3f73cb22979dfc229de.tar.gz
rust-47b05278d0679802f271e3f73cb22979dfc229de.zip
auto merge of #12397 : alexcrichton/rust/send-off-the-runtime, r=brson
The fairness yield mistakenly called `Local::take()` which meant that it would
only work if a local task was available. In theory sending on a channel (or calling try_recv) requires
no runtime because it never blocks, so there's no reason it shouldn't support
such a use case.

Closes #12391
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/comm/mod.rs59
1 files changed, 49 insertions, 10 deletions
diff --git a/src/libstd/comm/mod.rs b/src/libstd/comm/mod.rs
index 6fc0cb71c5c..145bee50a20 100644
--- a/src/libstd/comm/mod.rs
+++ b/src/libstd/comm/mod.rs
@@ -385,17 +385,17 @@ impl<T: Send> Chan<T> {
     pub fn try_send(&self, t: T) -> bool {
         // In order to prevent starvation of other tasks in situations where
         // a task sends repeatedly without ever receiving, we occassionally
-        // yield instead of doing a send immediately.  Only doing this if
-        // we're doing a rescheduling send, otherwise the caller is
-        // expecting not to context switch.
+        // yield instead of doing a send immediately.
         //
-        // Note that we don't unconditionally attempt to yield because the
-        // TLS overhead can be a bit much.
+        // Don't unconditionally attempt to yield because the TLS overhead can
+        // be a bit much, and also use `try_take` instead of `take` because
+        // there's no reason that this send shouldn't be usable off the
+        // runtime.
         let cnt = self.sends.get() + 1;
         self.sends.set(cnt);
         if cnt % (RESCHED_FREQ as uint) == 0 {
-            let task: ~Task = Local::take();
-            task.maybe_yield();
+            let task: Option<~Task> = Local::try_take();
+            task.map(|t| t.maybe_yield());
         }
 
         let (new_inner, ret) = match self.inner {
@@ -521,12 +521,13 @@ impl<T: Send> Port<T> {
     pub fn try_recv(&self) -> TryRecvResult<T> {
         // If a thread is spinning in try_recv, we should take the opportunity
         // to reschedule things occasionally. See notes above in scheduling on
-        // sends for why this doesn't always hit TLS.
+        // sends for why this doesn't always hit TLS, and also for why this uses
+        // `try_take` instead of `take`.
         let cnt = self.receives.get() + 1;
         self.receives.set(cnt);
         if cnt % (RESCHED_FREQ as uint) == 0 {
-            let task: ~Task = Local::take();
-            task.maybe_yield();
+            let task: Option<~Task> = Local::try_take();
+            task.map(|t| t.maybe_yield());
         }
 
         loop {
@@ -1203,4 +1204,42 @@ mod test {
         // wait for the child task to exit before we exit
         p1.recv();
     })
+
+    test!(fn sends_off_the_runtime() {
+        use rt::thread::Thread;
+
+        let (p, c) = Chan::new();
+        let t = Thread::start(proc() {
+            for _ in range(0, 1000) {
+                c.send(());
+            }
+        });
+        for _ in range(0, 1000) {
+            p.recv();
+        }
+        t.join();
+    })
+
+    test!(fn try_recvs_off_the_runtime() {
+        use rt::thread::Thread;
+
+        let (p, c) = Chan::new();
+        let (pdone, cdone) = Chan::new();
+        let t = Thread::start(proc() {
+            let mut hits = 0;
+            while hits < 10 {
+                match p.try_recv() {
+                    Data(()) => { hits += 1; }
+                    Empty => { Thread::yield_now(); }
+                    Disconnected => return,
+                }
+            }
+            cdone.send(());
+        });
+        for _ in range(0, 10) {
+            c.send(());
+        }
+        t.join();
+        pdone.recv();
+    })
 }