green: Fixing all tests from previous refactorings

This commit is contained in:
Alex Crichton
2013-12-13 19:33:28 -08:00
parent 1a6d920e3d
commit aad9fbf6b6
6 changed files with 351 additions and 282 deletions

View File

@@ -223,3 +223,61 @@ impl Drop for BasicPausable {
} }
} }
} }
#[cfg(test)]
mod test {
use std::task::TaskOpts;
use basic;
use PoolConfig;
use SchedPool;
fn pool() -> SchedPool {
SchedPool::new(PoolConfig {
threads: 1,
event_loop_factory: Some(basic::event_loop),
})
}
fn run(f: proc()) {
let mut pool = pool();
pool.spawn(TaskOpts::new(), f);
pool.shutdown();
}
#[test]
fn smoke() {
do run {}
}
#[test]
fn some_channels() {
do run {
let (p, c) = Chan::new();
do spawn {
c.send(());
}
p.recv();
}
}
#[test]
fn multi_thread() {
let mut pool = SchedPool::new(PoolConfig {
threads: 2,
event_loop_factory: Some(basic::event_loop),
});
for _ in range(0, 20) {
do pool.spawn(TaskOpts::new()) {
let (p, c) = Chan::new();
do spawn {
c.send(());
}
p.recv();
}
}
pool.shutdown();
}
}

View File

@@ -58,8 +58,6 @@ pub mod sleeper_list;
pub mod stack; pub mod stack;
pub mod task; pub mod task;
#[cfg(test)] mod tests;
#[cfg(stage0)] #[cfg(stage0)]
#[lang = "start"] #[lang = "start"]
pub fn lang_start(main: *u8, argc: int, argv: **u8) -> int { pub fn lang_start(main: *u8, argc: int, argv: **u8) -> int {

View File

@@ -951,21 +951,47 @@ fn new_sched_rng() -> XorShiftRng {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use borrow::to_uint; use std::task::TaskOpts;
use rt::deque::BufferPool; use std::rt::Runtime;
use rt::basic; use std::rt::task::Task;
use rt::sched::{Scheduler}; use std::rt::local::Local;
use rt::task::{GreenTask, Sched};
use rt::thread::Thread; use basic;
use rt::util; use sched::TaskFromFriend;
use task::TaskResult; use task::{GreenTask, HomeSched};
use unstable::run_in_bare_thread; use PoolConfig;
use SchedPool;
fn pool() -> SchedPool {
SchedPool::new(PoolConfig {
threads: 1,
event_loop_factory: Some(basic::event_loop),
})
}
fn run(f: proc()) {
let mut pool = pool();
pool.spawn(TaskOpts::new(), f);
pool.shutdown();
}
fn sched_id() -> uint {
let mut task = Local::borrow(None::<Task>);
match task.get().maybe_take_runtime::<GreenTask>() {
Some(green) => {
let ret = green.sched.get_ref().sched_id();
task.get().put_runtime(green as ~Runtime);
return ret;
}
None => fail!()
}
}
#[test] #[test]
fn trivial_run_in_newsched_task_test() { fn trivial_run_in_newsched_task_test() {
let mut task_ran = false; let mut task_ran = false;
let task_ran_ptr: *mut bool = &mut task_ran; let task_ran_ptr: *mut bool = &mut task_ran;
do run_in_newsched_task || { do run {
unsafe { *task_ran_ptr = true }; unsafe { *task_ran_ptr = true };
rtdebug!("executed from the new scheduler") rtdebug!("executed from the new scheduler")
} }
@@ -977,9 +1003,11 @@ mod test {
let total = 10; let total = 10;
let mut task_run_count = 0; let mut task_run_count = 0;
let task_run_count_ptr: *mut uint = &mut task_run_count; let task_run_count_ptr: *mut uint = &mut task_run_count;
do run_in_newsched_task || { // with only one thread this is safe to run in without worries of
// contention.
do run {
for _ in range(0u, total) { for _ in range(0u, total) {
do spawntask || { do spawn || {
unsafe { *task_run_count_ptr = *task_run_count_ptr + 1}; unsafe { *task_run_count_ptr = *task_run_count_ptr + 1};
} }
} }
@@ -991,12 +1019,12 @@ mod test {
fn multiple_task_nested_test() { fn multiple_task_nested_test() {
let mut task_run_count = 0; let mut task_run_count = 0;
let task_run_count_ptr: *mut uint = &mut task_run_count; let task_run_count_ptr: *mut uint = &mut task_run_count;
do run_in_newsched_task || { do run {
do spawntask || { do spawn {
unsafe { *task_run_count_ptr = *task_run_count_ptr + 1 }; unsafe { *task_run_count_ptr = *task_run_count_ptr + 1 };
do spawntask || { do spawn {
unsafe { *task_run_count_ptr = *task_run_count_ptr + 1 }; unsafe { *task_run_count_ptr = *task_run_count_ptr + 1 };
do spawntask || { do spawn {
unsafe { *task_run_count_ptr = *task_run_count_ptr + 1 }; unsafe { *task_run_count_ptr = *task_run_count_ptr + 1 };
} }
} }
@@ -1005,52 +1033,33 @@ mod test {
assert!(task_run_count == 3); assert!(task_run_count == 3);
} }
// Confirm that a sched_id actually is the uint form of the
// pointer to the scheduler struct.
#[test]
fn simple_sched_id_test() {
do run_in_bare_thread {
let sched = ~new_test_uv_sched();
assert!(to_uint(sched) == sched.sched_id());
}
}
// Compare two scheduler ids that are different, this should never
// fail but may catch a mistake someday.
#[test]
fn compare_sched_id_test() {
do run_in_bare_thread {
let sched_one = ~new_test_uv_sched();
let sched_two = ~new_test_uv_sched();
assert!(sched_one.sched_id() != sched_two.sched_id());
}
}
// A very simple test that confirms that a task executing on the // A very simple test that confirms that a task executing on the
// home scheduler notices that it is home. // home scheduler notices that it is home.
#[test] #[test]
fn test_home_sched() { fn test_home_sched() {
do run_in_bare_thread { let mut pool = pool();
let mut task_ran = false;
let task_ran_ptr: *mut bool = &mut task_ran;
let mut sched = ~new_test_uv_sched(); let (dport, dchan) = Chan::new();
let sched_handle = sched.make_handle(); {
let (port, chan) = Chan::new();
let mut handle1 = pool.spawn_sched();
let mut handle2 = pool.spawn_sched();
let mut task = ~do GreenTask::new_root_homed(&mut sched.stack_pool, None, handle1.send(TaskFromFriend(do pool.task(TaskOpts::new()) {
Sched(sched_handle)) { chan.send(sched_id());
unsafe { *task_ran_ptr = true }; }));
assert!(GreenTask::on_appropriate_sched()); let sched1_id = port.recv();
let mut task = do pool.task(TaskOpts::new()) {
assert_eq!(sched_id(), sched1_id);
dchan.send(());
}; };
task.give_home(HomeSched(handle1));
let on_exit: proc(TaskResult) = proc(exit_status) { handle2.send(TaskFromFriend(task));
rtassert!(exit_status.is_ok())
};
task.death.on_exit = Some(on_exit);
sched.bootstrap(task);
} }
dport.recv();
pool.shutdown();
} }
// An advanced test that checks all four possible states that a // An advanced test that checks all four possible states that a
@@ -1058,12 +1067,13 @@ mod test {
#[test] #[test]
fn test_schedule_home_states() { fn test_schedule_home_states() {
use rt::sleeper_list::SleeperList; use sleeper_list::SleeperList;
use rt::sched::Shutdown; use super::{Shutdown, Scheduler, SchedHandle};
use borrow; use std::unstable::run_in_bare_thread;
use std::rt::thread::Thread;
use std::sync::deque::BufferPool;
do run_in_bare_thread { do run_in_bare_thread {
let sleepers = SleeperList::new(); let sleepers = SleeperList::new();
let mut pool = BufferPool::new(); let mut pool = BufferPool::new();
let (normal_worker, normal_stealer) = pool.deque(); let (normal_worker, normal_stealer) = pool.deque();
@@ -1072,15 +1082,18 @@ mod test {
// Our normal scheduler // Our normal scheduler
let mut normal_sched = ~Scheduler::new( let mut normal_sched = ~Scheduler::new(
1,
basic::event_loop(), basic::event_loop(),
normal_worker, normal_worker,
queues.clone(), queues.clone(),
sleepers.clone()); sleepers.clone());
let normal_handle = normal_sched.make_handle(); let normal_handle = normal_sched.make_handle();
let friend_handle = normal_sched.make_handle();
// Our special scheduler // Our special scheduler
let mut special_sched = ~Scheduler::new_special( let mut special_sched = ~Scheduler::new_special(
1,
basic::event_loop(), basic::event_loop(),
special_worker, special_worker,
queues.clone(), queues.clone(),
@@ -1099,35 +1112,61 @@ mod test {
// 3) task not homed, sched requeues // 3) task not homed, sched requeues
// 4) task not home, send home // 4) task not home, send home
let task1 = ~do GreenTask::new_root_homed(&mut special_sched.stack_pool, None, // Grab both the scheduler and the task from TLS and check if the
Sched(t1_handle)) || { // task is executing on an appropriate scheduler.
rtassert!(GreenTask::on_appropriate_sched()); fn on_appropriate_sched() -> bool {
use task::{TypeGreen, TypeSched, HomeSched};
let task = GreenTask::convert(Local::take());
let sched_id = task.sched.get_ref().sched_id();
let run_any = task.sched.get_ref().run_anything;
let ret = match task.task_type {
TypeGreen(Some(AnySched)) => {
run_any
}
TypeGreen(Some(HomeSched(SchedHandle {
sched_id: ref id,
..
}))) => {
*id == sched_id
}
TypeGreen(None) => { fail!("task without home"); }
TypeSched => { fail!("expected green task"); }
}; };
rtdebug!("task1 id: **{}**", borrow::to_uint(task1)); task.put();
ret
}
let task2 = ~do GreenTask::new_root(&mut normal_sched.stack_pool, None) { let task1 = do GreenTask::new_homed(&mut special_sched.stack_pool,
rtassert!(GreenTask::on_appropriate_sched()); None, HomeSched(t1_handle)) {
rtassert!(on_appropriate_sched());
}; };
let task3 = ~do GreenTask::new_root(&mut normal_sched.stack_pool, None) { let task2 = do GreenTask::new(&mut normal_sched.stack_pool, None) {
rtassert!(GreenTask::on_appropriate_sched()); rtassert!(on_appropriate_sched());
}; };
let task4 = ~do GreenTask::new_root_homed(&mut special_sched.stack_pool, None, let task3 = do GreenTask::new(&mut normal_sched.stack_pool, None) {
Sched(t4_handle)) { rtassert!(on_appropriate_sched());
rtassert!(GreenTask::on_appropriate_sched()); };
let task4 = do GreenTask::new_homed(&mut special_sched.stack_pool,
None, HomeSched(t4_handle)) {
rtassert!(on_appropriate_sched());
}; };
rtdebug!("task4 id: **{}**", borrow::to_uint(task4));
// Signal from the special task that we are done. // Signal from the special task that we are done.
let (port, chan) = Chan::<()>::new(); let (port, chan) = Chan::<()>::new();
let normal_task = ~do GreenTask::new_root(&mut normal_sched.stack_pool, None) { fn run(next: ~GreenTask) {
rtdebug!("*about to submit task2*"); let mut task = GreenTask::convert(Local::take());
Scheduler::run_task(task2); let sched = task.sched.take_unwrap();
rtdebug!("*about to submit task4*"); sched.run_task(task, next)
Scheduler::run_task(task4); }
rtdebug!("*normal_task done*");
let normal_task = do GreenTask::new(&mut normal_sched.stack_pool,
None) {
run(task2);
run(task4);
port.recv(); port.recv();
let mut nh = normal_handle; let mut nh = normal_handle;
nh.send(Shutdown); nh.send(Shutdown);
@@ -1135,29 +1174,23 @@ mod test {
sh.send(Shutdown); sh.send(Shutdown);
}; };
rtdebug!("normal task: {}", borrow::to_uint(normal_task));
let special_task = ~do GreenTask::new_root(&mut special_sched.stack_pool, None) { let special_task = do GreenTask::new(&mut special_sched.stack_pool,
rtdebug!("*about to submit task1*"); None) {
Scheduler::run_task(task1); run(task1);
rtdebug!("*about to submit task3*"); run(task3);
Scheduler::run_task(task3);
rtdebug!("*done with special_task*");
chan.send(()); chan.send(());
}; };
rtdebug!("special task: {}", borrow::to_uint(special_task));
let normal_sched = normal_sched; let normal_sched = normal_sched;
let normal_thread = do Thread::start { let normal_thread = do Thread::start {
normal_sched.bootstrap(normal_task); normal_sched.bootstrap(normal_task);
rtdebug!("finished with normal_thread");
}; };
let special_sched = special_sched; let special_sched = special_sched;
let special_thread = do Thread::start { let special_thread = do Thread::start {
special_sched.bootstrap(special_task); special_sched.bootstrap(special_task);
rtdebug!("finished with special_sched");
}; };
normal_thread.join(); normal_thread.join();
@@ -1165,109 +1198,82 @@ mod test {
} }
} }
#[test] //#[test]
fn test_stress_schedule_task_states() { //fn test_stress_schedule_task_states() {
if util::limit_thread_creation_due_to_osx_and_valgrind() { return; } // if util::limit_thread_creation_due_to_osx_and_valgrind() { return; }
let n = stress_factor() * 120; // let n = stress_factor() * 120;
for _ in range(0, n as int) { // for _ in range(0, n as int) {
test_schedule_home_states(); // test_schedule_home_states();
} // }
} //}
#[test] #[test]
fn test_io_callback() { fn test_io_callback() {
use io::timer; use std::io::timer;
// This is a regression test that when there are no schedulable tasks let mut pool = SchedPool::new(PoolConfig {
// in the work queue, but we are performing I/O, that once we do put threads: 2,
// something in the work queue again the scheduler picks it up and doesn't event_loop_factory: None,
// exit before emptying the work queue });
do run_in_uv_task {
do spawntask { // This is a regression test that when there are no schedulable tasks in
// the work queue, but we are performing I/O, that once we do put
// something in the work queue again the scheduler picks it up and
// doesn't exit before emptying the work queue
do pool.spawn(TaskOpts::new()) {
do spawn {
timer::sleep(10); timer::sleep(10);
} }
} }
pool.shutdown();
} }
#[test] #[test]
fn handle() { fn wakeup_across_scheds() {
do run_in_bare_thread { let (port1, chan1) = Chan::new();
let (port, chan) = Chan::new(); let (port2, chan2) = Chan::new();
let thread_one = do Thread::start { let mut pool1 = pool();
let chan = chan; let mut pool2 = pool();
do run_in_newsched_task_core {
chan.send(());
}
};
let thread_two = do Thread::start { do pool1.spawn(TaskOpts::new()) {
let port = port; let id = sched_id();
do run_in_newsched_task_core { chan1.send(());
port.recv(); port2.recv();
assert_eq!(id, sched_id());
} }
};
thread_two.join(); do pool2.spawn(TaskOpts::new()) {
thread_one.join(); let id = sched_id();
port1.recv();
assert_eq!(id, sched_id());
chan2.send(());
} }
pool1.shutdown();
pool2.shutdown();
} }
// A regression test that the final message is always handled. // A regression test that the final message is always handled.
// Used to deadlock because Shutdown was never recvd. // Used to deadlock because Shutdown was never recvd.
#[test] #[test]
fn no_missed_messages() { fn no_missed_messages() {
use rt::sleeper_list::SleeperList; let mut pool = pool();
use rt::stack::StackPool;
use rt::sched::{Shutdown, TaskFromFriend};
do run_in_bare_thread { let task = pool.task(TaskOpts::new(), proc()());
stress_factor().times(|| { pool.spawn_sched().send(TaskFromFriend(task));
let sleepers = SleeperList::new();
let mut pool = BufferPool::new();
let (worker, stealer) = pool.deque();
let mut sched = ~Scheduler::new( pool.shutdown();
basic::event_loop(),
worker,
~[stealer],
sleepers.clone());
let mut handle = sched.make_handle();
let sched = sched;
let thread = do Thread::start {
let mut sched = sched;
let bootstrap_task =
~GreenTask::new_root(&mut sched.stack_pool,
None,
proc()());
sched.bootstrap(bootstrap_task);
};
let mut stack_pool = StackPool::new();
let task = ~GreenTask::new_root(&mut stack_pool, None, proc()());
handle.send(TaskFromFriend(task));
handle.send(Shutdown);
drop(handle);
thread.join();
})
}
} }
#[test] #[test]
fn multithreading() { fn multithreading() {
use num::Times; do run {
use vec::OwnedVector;
use container::Container;
do run_in_mt_newsched_task {
let mut ports = ~[]; let mut ports = ~[];
10.times(|| { 10.times(|| {
let (port, chan) = Chan::new(); let (port, chan) = Chan::new();
do spawntask_later { do spawn {
chan.send(()); chan.send(());
} }
ports.push(port); ports.push(port);
@@ -1281,7 +1287,7 @@ mod test {
#[test] #[test]
fn thread_ring() { fn thread_ring() {
do run_in_mt_newsched_task { do run {
let (end_port, end_chan) = Chan::new(); let (end_port, end_chan) = Chan::new();
let n_tasks = 10; let n_tasks = 10;
@@ -1294,14 +1300,14 @@ mod test {
let (next_p, ch) = Chan::new(); let (next_p, ch) = Chan::new();
let imm_i = i; let imm_i = i;
let imm_p = p; let imm_p = p;
do spawntask_random { do spawn {
roundtrip(imm_i, n_tasks, &imm_p, &ch); roundtrip(imm_i, n_tasks, &imm_p, &ch);
}; };
p = next_p; p = next_p;
i += 1; i += 1;
} }
let p = p; let p = p;
do spawntask_random { do spawn {
roundtrip(1, n_tasks, &p, &ch1); roundtrip(1, n_tasks, &p, &ch1);
} }
@@ -1332,11 +1338,9 @@ mod test {
#[test] #[test]
fn start_closure_dtor() { fn start_closure_dtor() {
use ops::Drop;
// Regression test that the `start` task entrypoint can // Regression test that the `start` task entrypoint can
// contain dtors that use task resources // contain dtors that use task resources
do run_in_newsched_task { do run {
struct S { field: () } struct S { field: () }
impl Drop for S { impl Drop for S {
@@ -1347,7 +1351,7 @@ mod test {
let s = S { field: () }; let s = S { field: () };
do spawntask { do spawn {
let _ss = &s; let _ss = &s;
} }
} }
@@ -1357,31 +1361,33 @@ mod test {
#[ignore] #[ignore]
#[test] #[test]
fn dont_starve_1() { fn dont_starve_1() {
stress_factor().times(|| { let mut pool = SchedPool::new(PoolConfig {
do run_in_mt_newsched_task { threads: 2, // this must be > 1
event_loop_factory: Some(basic::event_loop),
});
do pool.spawn(TaskOpts::new()) {
let (port, chan) = Chan::new(); let (port, chan) = Chan::new();
// This task should not be able to starve the sender; // This task should not be able to starve the sender;
// The sender should get stolen to another thread. // The sender should get stolen to another thread.
do spawntask { do spawn {
while port.try_recv().is_none() { } while port.try_recv().is_none() { }
} }
chan.send(()); chan.send(());
} }
}) pool.shutdown();
} }
#[test] #[test]
fn dont_starve_2() { fn dont_starve_2() {
stress_factor().times(|| { do run {
do run_in_newsched_task {
let (port, chan) = Chan::new(); let (port, chan) = Chan::new();
let (_port2, chan2) = Chan::new(); let (_port2, chan2) = Chan::new();
// This task should not be able to starve the other task. // This task should not be able to starve the other task.
// The sends should eventually yield. // The sends should eventually yield.
do spawntask { do spawn {
while port.try_recv().is_none() { while port.try_recv().is_none() {
chan2.send(()); chan2.send(());
} }
@@ -1389,20 +1395,15 @@ mod test {
chan.send(()); chan.send(());
} }
})
} }
// Regression test for a logic bug that would cause single-threaded schedulers // Regression test for a logic bug that would cause single-threaded
// to sleep forever after yielding and stealing another task. // schedulers to sleep forever after yielding and stealing another task.
#[test] #[test]
fn single_threaded_yield() { fn single_threaded_yield() {
use task::{spawn, spawn_sched, SingleThreaded, deschedule}; use std::task::deschedule;
use num::Times; do run {
5.times(deschedule);
do spawn_sched(SingleThreaded) { }
5.times(|| { deschedule(); })
}
do spawn { }
do spawn { }
} }
} }

View File

@@ -346,7 +346,7 @@ impl Runtime for GreenTask {
} }
} }
fn reawaken(mut ~self, to_wake: ~Task, can_resched: bool) { fn reawaken(mut ~self, to_wake: ~Task) {
self.put_task(to_wake); self.put_task(to_wake);
assert!(self.sched.is_none()); assert!(self.sched.is_none());
@@ -371,21 +371,16 @@ impl Runtime for GreenTask {
let mut running_task: ~Task = Local::take(); let mut running_task: ~Task = Local::take();
match running_task.maybe_take_runtime::<GreenTask>() { match running_task.maybe_take_runtime::<GreenTask>() {
Some(mut running_green_task) => { Some(mut running_green_task) => {
let mut sched = running_green_task.sched.take_unwrap();
if sched.pool_id == self.pool_id {
running_green_task.put_task(running_task); running_green_task.put_task(running_task);
if can_resched { let sched = running_green_task.sched.take_unwrap();
if sched.pool_id == self.pool_id {
sched.run_task(running_green_task, self); sched.run_task(running_green_task, self);
} else {
sched.enqueue_task(self);
running_green_task.put_with_sched(sched);
}
} else { } else {
self.reawaken_remotely(); self.reawaken_remotely();
// put that thing back where it came from! // put that thing back where it came from!
running_task.put_runtime(running_green_task as ~Runtime); running_green_task.put_with_sched(sched);
Local::put(running_task);
} }
} }
None => { None => {
@@ -427,94 +422,110 @@ impl Drop for GreenTask {
} }
#[cfg(test)] #[cfg(test)]
mod test { mod tests {
use std::rt::Runtime;
use std::rt::local::Local;
use std::rt::task::Task;
use std::task;
use std::task::TaskOpts;
#[test] use super::super::{PoolConfig, SchedPool};
fn local_heap() { use super::GreenTask;
do run_in_newsched_task() {
let a = @5; fn spawn_opts(opts: TaskOpts, f: proc()) {
let b = a; let mut pool = SchedPool::new(PoolConfig {
assert!(*a == 5); threads: 1,
assert!(*b == 5); event_loop_factory: None,
} });
pool.spawn(opts, f);
pool.shutdown();
} }
#[test] #[test]
fn tls() { fn smoke() {
use std::local_data; let (p, c) = Chan::new();
do run_in_newsched_task() { do spawn_opts(TaskOpts::new()) {
local_data_key!(key: @~str) c.send(());
local_data::set(key, @~"data");
assert!(*local_data::get(key, |k| k.map(|k| *k)).unwrap() == ~"data");
local_data_key!(key2: @~str)
local_data::set(key2, @~"data");
assert!(*local_data::get(key2, |k| k.map(|k| *k)).unwrap() == ~"data");
} }
p.recv();
} }
#[test] #[test]
fn unwind() { fn smoke_fail() {
do run_in_newsched_task() { let (p, c) = Chan::<()>::new();
let result = spawntask_try(proc()()); do spawn_opts(TaskOpts::new()) {
rtdebug!("trying first assert"); let _c = c;
assert!(result.is_ok()); fail!()
let result = spawntask_try(proc() fail!());
rtdebug!("trying second assert");
assert!(result.is_err());
} }
assert_eq!(p.recv_opt(), None);
} }
#[test] #[test]
fn rng() { fn smoke_opts() {
do run_in_uv_task() { let mut opts = TaskOpts::new();
use std::rand::{rng, Rng}; opts.name = Some(SendStrStatic("test"));
let mut r = rng(); opts.stack_size = Some(20 * 4096);
let _ = r.next_u32(); let (p, c) = Chan::new();
} opts.notify_chan = Some(c);
spawn_opts(opts, proc() {});
assert!(p.recv().is_ok());
} }
#[test] #[test]
fn logging() { fn smoke_opts_fail() {
do run_in_uv_task() { let mut opts = TaskOpts::new();
info!("here i am. logging in a newsched task"); let (p, c) = Chan::new();
} opts.notify_chan = Some(c);
spawn_opts(opts, proc() { fail!() });
assert!(p.recv().is_err());
} }
#[test] #[test]
fn comm_stream() { fn yield_test() {
do run_in_newsched_task() { let (p, c) = Chan::new();
let (port, chan) = Chan::new(); do spawn_opts(TaskOpts::new()) {
chan.send(10); 10.times(task::deschedule);
assert!(port.recv() == 10); c.send(());
} }
p.recv();
} }
#[test] #[test]
fn comm_shared_chan() { fn spawn_children() {
do run_in_newsched_task() { let (p, c) = Chan::new();
let (port, chan) = SharedChan::new(); do spawn_opts(TaskOpts::new()) {
chan.send(10); let (p, c2) = Chan::new();
assert!(port.recv() == 10); do spawn {
let (p, c3) = Chan::new();
do spawn {
c3.send(());
} }
p.recv();
c2.send(());
}
p.recv();
c.send(());
}
p.recv();
} }
//#[test]
//fn heap_cycles() {
// use std::option::{Option, Some, None};
// do run_in_newsched_task {
// struct List {
// next: Option<@mut List>,
// }
// let a = @mut List { next: None };
// let b = @mut List { next: Some(a) };
// a.next = Some(b);
// }
//}
#[test] #[test]
#[should_fail] fn spawn_inherits() {
fn test_begin_unwind() { begin_unwind("cause", file!(), line!()) } let (p, c) = Chan::new();
do spawn_opts(TaskOpts::new()) {
let c = c;
do spawn {
let mut task: ~Task = Local::take();
match task.maybe_take_runtime::<GreenTask>() {
Some(ops) => {
task.put_runtime(ops as ~Runtime);
}
None => fail!(),
}
Local::put(task);
c.send(());
}
}
p.recv();
}
} }

View File

@@ -227,6 +227,7 @@ mod tests {
use std::rt::local::Local; use std::rt::local::Local;
use std::rt::task::Task; use std::rt::task::Task;
use std::task; use std::task;
use std::task::TaskOpts;
use super::{spawn, spawn_opts, Ops}; use super::{spawn, spawn_opts, Ops};
#[test] #[test]

View File

@@ -207,9 +207,9 @@ mod test {
let port = timer.period(1); let port = timer.period(1);
port.recv(); port.recv();
port.recv(); port.recv();
let port = timer.period(1); let port2 = timer.period(1);
port.recv(); port2.recv();
port.recv(); port2.recv();
} }
#[test] #[test]