about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2013-12-13 18:27:13 -0800
committerAlex Crichton <alex@alexcrichton.com>2013-12-24 19:59:53 -0800
commit8be66e212b37045b927138965a76abe3608325ca (patch)
tree854c2b53b85412f0abbb7f8b04b564a5532ef392 /src/libstd
parent14caf00c92b40e3f62094db54f325196c8a05d5a (diff)
downloadrust-8be66e212b37045b927138965a76abe3608325ca.tar.gz
rust-8be66e212b37045b927138965a76abe3608325ca.zip
std: Implement yields on receives for channels
This will prevent a deadlock when a task spins in a try_recv when using channel
communication routines is a clear location for a M:N scheduling to happen.
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/comm/mod.rs25
1 files changed, 20 insertions, 5 deletions
diff --git a/src/libstd/comm/mod.rs b/src/libstd/comm/mod.rs
index 76a9e5d17e1..7b464bc2f32 100644
--- a/src/libstd/comm/mod.rs
+++ b/src/libstd/comm/mod.rs
@@ -238,7 +238,6 @@ use rt::local::Local;
 use rt::task::{Task, BlockedTask};
 use rt::thread::Thread;
 use sync::atomics::{AtomicInt, AtomicBool, SeqCst, Relaxed};
-use task;
 use vec::{ImmutableVector, OwnedVector};
 
 use spsc = sync::spsc_queue;
@@ -346,6 +345,7 @@ struct Packet {
     selection_id: uint,
     select_next: *mut Packet,
     select_prev: *mut Packet,
+    recv_cnt: int,
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -367,6 +367,7 @@ impl Packet {
             selection_id: 0,
             select_next: 0 as *mut Packet,
             select_prev: 0 as *mut Packet,
+            recv_cnt: 0,
         }
     }
 
@@ -611,8 +612,9 @@ impl<T: Send> Chan<T> {
                 // the TLS overhead can be a bit much.
                 n => {
                     assert!(n >= 0);
-                    if can_resched && n > 0 && n % RESCHED_FREQ == 0 {
-                        task::deschedule();
+                    if n > 0 && n % RESCHED_FREQ == 0 {
+                        let task: ~Task = Local::take();
+                        task.maybe_yield();
                     }
                     true
                 }
@@ -704,8 +706,9 @@ impl<T: Send> SharedChan<T> {
                 DISCONNECTED => {} // oh well, we tried
                 -1 => { (*packet).wakeup(can_resched); }
                 n => {
-                    if can_resched && n > 0 && n % RESCHED_FREQ == 0 {
-                        task::deschedule();
+                    if n > 0 && n % RESCHED_FREQ == 0 {
+                        let task: ~Task = Local::take();
+                        task.maybe_yield();
                     }
                 }
             }
@@ -773,6 +776,18 @@ impl<T: Send> Port<T> {
         // This is a "best effort" situation, so if a queue is inconsistent just
         // don't worry about it.
         let this = unsafe { cast::transmute_mut(self) };
+
+        // See the comment about yielding on sends, but the same applies here.
+        // If a thread is spinning in try_recv we should try
+        unsafe {
+            let packet = this.queue.packet();
+            (*packet).recv_cnt += 1;
+            if (*packet).recv_cnt % RESCHED_FREQ == 0 {
+                let task: ~Task = Local::take();
+                task.maybe_yield();
+            }
+        }
+
         let ret = match this.queue {
             SPSC(ref mut queue) => queue.pop(),
             MPSC(ref mut queue) => match queue.pop() {