about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2013-12-18 14:42:58 -0800
committerAlex Crichton <alex@alexcrichton.com>2013-12-24 19:59:55 -0800
commitb47ff23673559ee9a5b91221e0212fd6a57d9802 (patch)
tree2f9f3e7ea6791f3dcf7a6bea8c165f06a4565e20
parent7f483459045789d6bb44671269fd9aec73dbeb63 (diff)
downloadrust-b47ff23673559ee9a5b91221e0212fd6a57d9802.tar.gz
rust-b47ff23673559ee9a5b91221e0212fd6a57d9802.zip
green: Move a scheduler test inside libgreen
This test also had a race condition in using the cvar/lock, so I fixed that up
as well. The race originated from one half trying to destroy the lock when
another half was using it.
-rw-r--r--src/libgreen/sched.rs73
-rw-r--r--src/libstd/task.rs60
2 files changed, 72 insertions, 61 deletions
diff --git a/src/libgreen/sched.rs b/src/libgreen/sched.rs
index 9e26cd41cdd..95c4d8347d5 100644
--- a/src/libgreen/sched.rs
+++ b/src/libgreen/sched.rs
@@ -957,7 +957,7 @@ mod test {
     use std::rt::local::Local;
 
     use basic;
-    use sched::TaskFromFriend;
+    use sched::{TaskFromFriend, PinnedTask};
     use task::{GreenTask, HomeSched};
     use PoolConfig;
     use SchedPool;
@@ -1406,4 +1406,75 @@ mod test {
             5.times(deschedule);
         }
     }
+
+    #[test]
+    fn test_spawn_sched_blocking() {
+        use std::unstable::mutex::Mutex;
+
+        // Testing that a task in one scheduler can block in foreign code
+        // without affecting other schedulers
+        for _ in range(0, 20) {
+            let mut pool = pool();
+            let (start_po, start_ch) = Chan::new();
+            let (fin_po, fin_ch) = Chan::new();
+
+            let lock = unsafe { Mutex::new() };
+            let lock2 = unsafe { lock.clone() };
+
+            let mut handle = pool.spawn_sched();
+            handle.send(PinnedTask(pool.task(TaskOpts::new(), proc() {
+                let mut lock = lock2;
+                unsafe {
+                    lock.lock();
+
+                    start_ch.send(());
+                    lock.wait();   // block the scheduler thread
+                    lock.signal(); // let them know we have the lock
+                    lock.unlock();
+                }
+
+                fin_ch.send(());
+            })));
+            drop(handle);
+
+            let mut handle = pool.spawn_sched();
+            handle.send(TaskFromFriend(pool.task(TaskOpts::new(), proc() {
+                // Wait until the other task has its lock
+                start_po.recv();
+
+                fn pingpong(po: &Port<int>, ch: &Chan<int>) {
+                    let mut val = 20;
+                    while val > 0 {
+                        val = po.recv();
+                        ch.try_send(val - 1);
+                    }
+                }
+
+                let (setup_po, setup_ch) = Chan::new();
+                let (parent_po, parent_ch) = Chan::new();
+                do spawn {
+                    let (child_po, child_ch) = Chan::new();
+                    setup_ch.send(child_ch);
+                    pingpong(&child_po, &parent_ch);
+                };
+
+                let child_ch = setup_po.recv();
+                child_ch.send(20);
+                pingpong(&parent_po, &child_ch);
+                unsafe {
+                    let mut lock = lock;
+                    lock.lock();
+                    lock.signal();   // wakeup waiting scheduler
+                    lock.wait();     // wait for them to grab the lock
+                    lock.unlock();
+                    lock.destroy();  // now we're guaranteed they have no locks
+                }
+            })));
+            drop(handle);
+
+            fin_po.recv();
+            pool.shutdown();
+        }
+
+    }
 }
diff --git a/src/libstd/task.rs b/src/libstd/task.rs
index 836390fb416..2f0f9bf64af 100644
--- a/src/libstd/task.rs
+++ b/src/libstd/task.rs
@@ -529,66 +529,6 @@ fn test_spawn_sched_childs_on_default_sched() {
     po.recv();
 }
 
-#[test]
-fn test_spawn_sched_blocking() {
-    use unstable::mutex::Mutex;
-    use num::Times;
-
-    unsafe {
-
-        // Testing that a task in one scheduler can block in foreign code
-        // without affecting other schedulers
-        20u.times(|| {
-            let (start_po, start_ch) = Chan::new();
-            let (fin_po, fin_ch) = Chan::new();
-
-            let mut lock = Mutex::new();
-            let lock2 = lock.clone();
-
-            do spawn {
-                let mut lock = lock2;
-                lock.lock();
-
-                start_ch.send(());
-
-                // Block the scheduler thread
-                lock.wait();
-                lock.unlock();
-
-                fin_ch.send(());
-            };
-
-            // Wait until the other task has its lock
-            start_po.recv();
-
-            fn pingpong(po: &Port<int>, ch: &Chan<int>) {
-                let mut val = 20;
-                while val > 0 {
-                    val = po.recv();
-                    ch.try_send(val - 1);
-                }
-            }
-
-            let (setup_po, setup_ch) = Chan::new();
-            let (parent_po, parent_ch) = Chan::new();
-            do spawn {
-                let (child_po, child_ch) = Chan::new();
-                setup_ch.send(child_ch);
-                pingpong(&child_po, &parent_ch);
-            };
-
-            let child_ch = setup_po.recv();
-            child_ch.send(20);
-            pingpong(&parent_po, &child_ch);
-            lock.lock();
-            lock.signal();
-            lock.unlock();
-            fin_po.recv();
-            lock.destroy();
-        })
-    }
-}
-
 #[cfg(test)]
 fn avoid_copying_the_body(spawnfn: |v: proc()|) {
     let (p, ch) = Chan::<uint>::new();