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.
This commit is contained in:
@@ -957,7 +957,7 @@ mod test {
|
|||||||
use std::rt::local::Local;
|
use std::rt::local::Local;
|
||||||
|
|
||||||
use basic;
|
use basic;
|
||||||
use sched::TaskFromFriend;
|
use sched::{TaskFromFriend, PinnedTask};
|
||||||
use task::{GreenTask, HomeSched};
|
use task::{GreenTask, HomeSched};
|
||||||
use PoolConfig;
|
use PoolConfig;
|
||||||
use SchedPool;
|
use SchedPool;
|
||||||
@@ -1406,4 +1406,75 @@ mod test {
|
|||||||
5.times(deschedule);
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -529,66 +529,6 @@ fn test_spawn_sched_childs_on_default_sched() {
|
|||||||
po.recv();
|
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)]
|
#[cfg(test)]
|
||||||
fn avoid_copying_the_body(spawnfn: |v: proc()|) {
|
fn avoid_copying_the_body(spawnfn: |v: proc()|) {
|
||||||
let (p, ch) = Chan::<uint>::new();
|
let (p, ch) = Chan::<uint>::new();
|
||||||
|
|||||||
Reference in New Issue
Block a user