2013-04-21 18:28:17 -05:00
|
|
|
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
|
|
|
//! Language-level runtime services that should reasonably expected
|
|
|
|
//! to be available 'everywhere'. Local heaps, GC, unwinding,
|
|
|
|
//! local storage, and logging. Even a 'freestanding' Rust would likely want
|
|
|
|
//! to implement this.
|
|
|
|
|
2013-12-12 20:01:59 -06:00
|
|
|
use any::AnyOwnExt;
|
2013-06-02 18:16:40 -05:00
|
|
|
use borrow;
|
2013-06-22 03:09:06 -05:00
|
|
|
use cleanup;
|
2013-12-05 20:19:06 -06:00
|
|
|
use io::Writer;
|
2013-12-15 19:17:07 -06:00
|
|
|
use libc::{c_char, size_t};
|
2013-10-11 16:20:34 -05:00
|
|
|
use local_data;
|
2013-12-12 20:01:59 -06:00
|
|
|
use ops::Drop;
|
2013-06-14 01:31:19 -05:00
|
|
|
use option::{Option, Some, None};
|
2013-12-12 20:01:59 -06:00
|
|
|
use prelude::drop;
|
|
|
|
use result::{Result, Ok, Err};
|
|
|
|
use rt::Runtime;
|
2013-08-11 20:54:23 -05:00
|
|
|
use rt::borrowck::BorrowRecord;
|
2013-10-11 16:20:34 -05:00
|
|
|
use rt::borrowck;
|
2013-05-19 17:45:39 -05:00
|
|
|
use rt::local::Local;
|
2013-12-12 20:01:59 -06:00
|
|
|
use rt::local_heap::LocalHeap;
|
2013-05-07 17:57:15 -05:00
|
|
|
use rt::logging::StdErrLogger;
|
2013-12-12 20:01:59 -06:00
|
|
|
use rt::rtio::LocalIo;
|
2013-12-15 19:17:07 -06:00
|
|
|
use rt::unwind::Unwinder;
|
2013-10-05 14:01:58 -05:00
|
|
|
use send_str::SendStr;
|
2013-12-12 20:01:59 -06:00
|
|
|
use sync::arc::UnsafeArc;
|
|
|
|
use sync::atomics::{AtomicUint, SeqCst};
|
|
|
|
use task::{TaskResult, TaskOpts};
|
2013-10-11 16:20:34 -05:00
|
|
|
use unstable::finally::Finally;
|
2013-12-12 20:01:59 -06:00
|
|
|
|
|
|
|
#[cfg(stage0)] pub use rt::unwind::begin_unwind;
|
2013-04-21 18:28:17 -05:00
|
|
|
|
2013-07-19 16:25:05 -05:00
|
|
|
// The Task struct represents all state associated with a rust
|
|
|
|
// task. There are at this point two primary "subtypes" of task,
|
|
|
|
// however instead of using a subtype we just have a "task_type" field
|
|
|
|
// in the struct. This contains a pointer to another struct that holds
|
|
|
|
// the type-specific state.
|
|
|
|
|
2013-05-19 03:04:01 -05:00
|
|
|
pub struct Task {
|
2013-10-20 00:51:30 -05:00
|
|
|
heap: LocalHeap,
|
2013-12-12 20:01:59 -06:00
|
|
|
gc: GarbageCollector,
|
2013-10-20 00:51:30 -05:00
|
|
|
storage: LocalStorage,
|
|
|
|
unwinder: Unwinder,
|
|
|
|
death: Death,
|
|
|
|
destroyed: bool,
|
|
|
|
name: Option<SendStr>,
|
2013-08-11 20:54:23 -05:00
|
|
|
// Dynamic borrowck debugging info
|
2013-10-24 19:30:36 -05:00
|
|
|
borrow_list: Option<~[BorrowRecord]>,
|
2013-12-12 20:01:59 -06:00
|
|
|
|
|
|
|
logger: Option<StdErrLogger>,
|
2013-10-24 19:30:36 -05:00
|
|
|
stdout_handle: Option<~Writer>,
|
2013-12-04 21:51:29 -06:00
|
|
|
|
2013-12-12 20:01:59 -06:00
|
|
|
priv imp: Option<~Runtime>,
|
2013-07-19 16:25:05 -05:00
|
|
|
}
|
|
|
|
|
2013-12-12 20:01:59 -06:00
|
|
|
pub struct GarbageCollector;
|
|
|
|
pub struct LocalStorage(Option<local_data::Map>);
|
2013-06-26 18:41:00 -05:00
|
|
|
|
2013-12-12 20:01:59 -06:00
|
|
|
/// A handle to a blocked task. Usually this means having the ~Task pointer by
|
|
|
|
/// ownership, but if the task is killable, a killer can steal it at any time.
|
|
|
|
pub enum BlockedTask {
|
|
|
|
Owned(~Task),
|
|
|
|
Shared(UnsafeArc<AtomicUint>),
|
2013-06-26 18:41:00 -05:00
|
|
|
}
|
|
|
|
|
2013-12-12 20:01:59 -06:00
|
|
|
/// Per-task state related to task death, killing, failure, etc.
|
|
|
|
pub struct Death {
|
|
|
|
// Action to be done with the exit code. If set, also makes the task wait
|
|
|
|
// until all its watched children exit before collecting the status.
|
|
|
|
on_exit: Option<proc(TaskResult)>,
|
2013-04-21 18:28:17 -05:00
|
|
|
}
|
|
|
|
|
2013-12-12 20:01:59 -06:00
|
|
|
pub struct BlockedTaskIterator {
|
|
|
|
priv inner: UnsafeArc<AtomicUint>,
|
|
|
|
}
|
2013-04-22 19:15:31 -05:00
|
|
|
|
2013-05-19 03:04:01 -05:00
|
|
|
impl Task {
|
2013-12-12 20:01:59 -06:00
|
|
|
pub fn new() -> Task {
|
2013-05-19 03:04:01 -05:00
|
|
|
Task {
|
2013-04-21 21:03:52 -05:00
|
|
|
heap: LocalHeap::new(),
|
2013-04-21 18:28:17 -05:00
|
|
|
gc: GarbageCollector,
|
2013-08-10 22:06:39 -05:00
|
|
|
storage: LocalStorage(None),
|
2013-12-12 20:01:59 -06:00
|
|
|
unwinder: Unwinder::new(),
|
2013-07-01 22:24:24 -05:00
|
|
|
death: Death::new(),
|
2013-06-26 18:41:00 -05:00
|
|
|
destroyed: false,
|
2013-07-30 18:20:59 -05:00
|
|
|
name: None,
|
2013-10-24 19:30:36 -05:00
|
|
|
borrow_list: None,
|
2013-11-05 13:29:45 -06:00
|
|
|
logger: None,
|
2013-10-24 19:30:36 -05:00
|
|
|
stdout_handle: None,
|
2013-12-12 20:01:59 -06:00
|
|
|
imp: None,
|
2013-04-21 18:28:17 -05:00
|
|
|
}
|
|
|
|
}
|
2013-04-22 14:54:03 -05:00
|
|
|
|
2013-12-12 20:01:59 -06:00
|
|
|
/// Executes the given closure as if it's running inside this task. The task
|
|
|
|
/// is consumed upon entry, and the destroyed task is returned from this
|
|
|
|
/// function in order for the caller to free. This function is guaranteed to
|
|
|
|
/// not unwind because the closure specified is run inside of a `rust_try`
|
|
|
|
/// block. (this is the only try/catch block in the world).
|
|
|
|
///
|
|
|
|
/// This function is *not* meant to be abused as a "try/catch" block. This
|
|
|
|
/// is meant to be used at the absolute boundaries of a task's lifetime, and
|
|
|
|
/// only for that purpose.
|
|
|
|
pub fn run(~self, f: ||) -> ~Task {
|
|
|
|
// Need to put ourselves into TLS, but also need access to the unwinder.
|
|
|
|
// Unsafely get a handle to the task so we can continue to use it after
|
|
|
|
// putting it in tls (so we can invoke the unwinder).
|
|
|
|
let handle: *mut Task = unsafe {
|
|
|
|
*cast::transmute::<&~Task, &*mut Task>(&self)
|
|
|
|
};
|
|
|
|
Local::put(self);
|
2013-04-22 19:15:31 -05:00
|
|
|
|
2013-08-03 16:43:16 -05:00
|
|
|
// The only try/catch block in the world. Attempt to run the task's
|
|
|
|
// client-specified code and catch any failures.
|
2013-12-12 20:01:59 -06:00
|
|
|
let try_block = || {
|
2013-06-26 18:41:00 -05:00
|
|
|
|
2013-08-03 16:43:16 -05:00
|
|
|
// Run the task main function, then do some cleanup.
|
2013-11-20 16:17:12 -06:00
|
|
|
f.finally(|| {
|
2013-12-12 20:01:59 -06:00
|
|
|
fn flush(w: Option<~Writer>) {
|
|
|
|
match w {
|
|
|
|
Some(mut w) => { w.flush(); }
|
|
|
|
None => {}
|
|
|
|
}
|
|
|
|
}
|
2013-10-24 19:30:36 -05:00
|
|
|
|
2013-08-10 22:06:39 -05:00
|
|
|
// First, destroy task-local storage. This may run user dtors.
|
|
|
|
//
|
2013-08-05 02:32:46 -05:00
|
|
|
// FIXME #8302: Dear diary. I'm so tired and confused.
|
|
|
|
// There's some interaction in rustc between the box
|
|
|
|
// annihilator and the TLS dtor by which TLS is
|
|
|
|
// accessed from annihilated box dtors *after* TLS is
|
|
|
|
// destroyed. Somehow setting TLS back to null, as the
|
|
|
|
// old runtime did, makes this work, but I don't currently
|
|
|
|
// understand how. I would expect that, if the annihilator
|
|
|
|
// reinvokes TLS while TLS is uninitialized, that
|
|
|
|
// TLS would be reinitialized but never destroyed,
|
|
|
|
// but somehow this works. I have no idea what's going
|
|
|
|
// on but this seems to make things magically work. FML.
|
2013-08-10 22:06:39 -05:00
|
|
|
//
|
|
|
|
// (added after initial comment) A possible interaction here is
|
|
|
|
// that the destructors for the objects in TLS themselves invoke
|
|
|
|
// TLS, or possibly some destructors for those objects being
|
|
|
|
// annihilated invoke TLS. Sadly these two operations seemed to
|
|
|
|
// be intertwined, and miraculously work for now...
|
2013-12-12 20:01:59 -06:00
|
|
|
let mut task = Local::borrow(None::<Task>);
|
|
|
|
let storage = task.get().storage.take();
|
|
|
|
drop(task);
|
|
|
|
drop(storage);
|
2013-08-05 02:32:46 -05:00
|
|
|
|
2013-08-03 16:43:16 -05:00
|
|
|
// Destroy remaining boxes. Also may run user dtors.
|
|
|
|
unsafe { cleanup::annihilate(); }
|
2013-10-24 19:30:36 -05:00
|
|
|
|
|
|
|
// Finally flush and destroy any output handles which the task
|
|
|
|
// owns. There are no boxes here, and no user destructors should
|
|
|
|
// run after this any more.
|
2013-12-12 20:01:59 -06:00
|
|
|
let mut task = Local::borrow(None::<Task>);
|
|
|
|
let stdout = task.get().stdout_handle.take();
|
|
|
|
let logger = task.get().logger.take();
|
|
|
|
drop(task);
|
|
|
|
|
|
|
|
flush(stdout);
|
|
|
|
drop(logger);
|
2013-11-20 16:17:12 -06:00
|
|
|
})
|
2013-12-12 20:01:59 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
unsafe { (*handle).unwinder.try(try_block); }
|
2013-06-22 03:09:06 -05:00
|
|
|
|
2013-08-11 20:54:23 -05:00
|
|
|
// Cleanup the dynamic borrowck debugging info
|
|
|
|
borrowck::clear_task_borrow_list();
|
|
|
|
|
2013-12-12 20:01:59 -06:00
|
|
|
let mut me: ~Task = Local::take();
|
|
|
|
me.death.collect_failure(me.unwinder.result());
|
|
|
|
me.destroyed = true;
|
|
|
|
return me;
|
2013-04-22 14:54:03 -05:00
|
|
|
}
|
2013-06-26 18:41:00 -05:00
|
|
|
|
2013-12-12 20:01:59 -06:00
|
|
|
/// Inserts a runtime object into this task, transferring ownership to the
|
|
|
|
/// task. It is illegal to replace a previous runtime object in this task
|
|
|
|
/// with this argument.
|
|
|
|
pub fn put_runtime(&mut self, ops: ~Runtime) {
|
|
|
|
assert!(self.imp.is_none());
|
|
|
|
self.imp = Some(ops);
|
|
|
|
}
|
2013-06-26 18:41:00 -05:00
|
|
|
|
2013-12-12 20:01:59 -06:00
|
|
|
/// Attempts to extract the runtime as a specific type. If the runtime does
|
|
|
|
/// not have the provided type, then the runtime is not removed. If the
|
|
|
|
/// runtime does have the specified type, then it is removed and returned
|
|
|
|
/// (transfer of ownership).
|
|
|
|
///
|
|
|
|
/// It is recommended to only use this method when *absolutely necessary*.
|
|
|
|
/// This function may not be available in the future.
|
|
|
|
pub fn maybe_take_runtime<T: 'static>(&mut self) -> Option<~T> {
|
|
|
|
// This is a terrible, terrible function. The general idea here is to
|
|
|
|
// take the runtime, cast it to ~Any, check if it has the right type,
|
|
|
|
// and then re-cast it back if necessary. The method of doing this is
|
|
|
|
// pretty sketchy and involves shuffling vtables of trait objects
|
|
|
|
// around, but it gets the job done.
|
|
|
|
//
|
|
|
|
// XXX: This function is a serious code smell and should be avoided at
|
|
|
|
// all costs. I have yet to think of a method to avoid this
|
|
|
|
// function, and I would be saddened if more usage of the function
|
|
|
|
// crops up.
|
|
|
|
unsafe {
|
|
|
|
let imp = self.imp.take_unwrap();
|
|
|
|
let &(vtable, _): &(uint, uint) = cast::transmute(&imp);
|
|
|
|
match imp.wrap().move::<T>() {
|
|
|
|
Ok(t) => Some(t),
|
|
|
|
Err(t) => {
|
|
|
|
let (_, obj): (uint, uint) = cast::transmute(t);
|
|
|
|
let obj: ~Runtime = cast::transmute((vtable, obj));
|
|
|
|
self.put_runtime(obj);
|
|
|
|
None
|
|
|
|
}
|
2013-06-26 18:41:00 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-12 20:01:59 -06:00
|
|
|
/// Spawns a sibling to this task. The newly spawned task is configured with
|
|
|
|
/// the `opts` structure and will run `f` as the body of its code.
|
|
|
|
pub fn spawn_sibling(mut ~self, opts: TaskOpts, f: proc()) {
|
|
|
|
let ops = self.imp.take_unwrap();
|
|
|
|
ops.spawn_sibling(self, opts, f)
|
2013-06-26 18:41:00 -05:00
|
|
|
}
|
|
|
|
|
2013-12-12 20:01:59 -06:00
|
|
|
/// Deschedules the current task, invoking `f` `amt` times. It is not
|
|
|
|
/// recommended to use this function directly, but rather communication
|
|
|
|
/// primitives in `std::comm` should be used.
|
|
|
|
pub fn deschedule(mut ~self, amt: uint,
|
|
|
|
f: |BlockedTask| -> Result<(), BlockedTask>) {
|
|
|
|
let ops = self.imp.take_unwrap();
|
|
|
|
ops.deschedule(amt, self, f)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Wakes up a previously blocked task, optionally specifiying whether the
|
|
|
|
/// current task can accept a change in scheduling. This function can only
|
|
|
|
/// be called on tasks that were previously blocked in `deschedule`.
|
|
|
|
pub fn reawaken(mut ~self, can_resched: bool) {
|
|
|
|
let ops = self.imp.take_unwrap();
|
|
|
|
ops.reawaken(self, can_resched);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Yields control of this task to another task. This function will
|
|
|
|
/// eventually return, but possibly not immediately. This is used as an
|
|
|
|
/// opportunity to allow other tasks a chance to run.
|
|
|
|
pub fn yield_now(mut ~self) {
|
|
|
|
let ops = self.imp.take_unwrap();
|
|
|
|
ops.yield_now(self);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Similar to `yield_now`, except that this function may immediately return
|
|
|
|
/// without yielding (depending on what the runtime decides to do).
|
|
|
|
pub fn maybe_yield(mut ~self) {
|
|
|
|
let ops = self.imp.take_unwrap();
|
|
|
|
ops.maybe_yield(self);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Acquires a handle to the I/O factory that this task contains, normally
|
|
|
|
/// stored in the task's runtime. This factory may not always be available,
|
|
|
|
/// which is why the return type is `Option`
|
|
|
|
pub fn local_io<'a>(&'a mut self) -> Option<LocalIo<'a>> {
|
|
|
|
self.imp.get_mut_ref().local_io()
|
2013-06-26 18:41:00 -05:00
|
|
|
}
|
2013-04-22 14:54:03 -05:00
|
|
|
}
|
|
|
|
|
2013-05-19 03:04:01 -05:00
|
|
|
impl Drop for Task {
|
2013-09-16 20:18:07 -05:00
|
|
|
fn drop(&mut self) {
|
2013-09-27 19:02:31 -05:00
|
|
|
rtdebug!("called drop for a task: {}", borrow::to_uint(self));
|
2013-10-24 19:30:36 -05:00
|
|
|
rtassert!(self.destroyed);
|
2013-07-19 16:25:05 -05:00
|
|
|
}
|
2013-04-21 18:28:17 -05:00
|
|
|
}
|
|
|
|
|
2013-12-12 20:01:59 -06:00
|
|
|
impl Iterator<BlockedTask> for BlockedTaskIterator {
|
|
|
|
fn next(&mut self) -> Option<BlockedTask> {
|
|
|
|
Some(Shared(self.inner.clone()))
|
2013-06-26 18:41:00 -05:00
|
|
|
}
|
2013-12-12 20:01:59 -06:00
|
|
|
}
|
2013-06-26 18:41:00 -05:00
|
|
|
|
2013-12-12 20:01:59 -06:00
|
|
|
impl BlockedTask {
|
|
|
|
/// Returns Some if the task was successfully woken; None if already killed.
|
|
|
|
pub fn wake(self) -> Option<~Task> {
|
|
|
|
match self {
|
|
|
|
Owned(task) => Some(task),
|
|
|
|
Shared(arc) => unsafe {
|
|
|
|
match (*arc.get()).swap(0, SeqCst) {
|
|
|
|
0 => None,
|
|
|
|
n => Some(cast::transmute(n)),
|
|
|
|
}
|
|
|
|
}
|
2013-07-19 16:25:05 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-12 20:01:59 -06:00
|
|
|
// This assertion has two flavours because the wake involves an atomic op.
|
|
|
|
// In the faster version, destructors will fail dramatically instead.
|
|
|
|
#[cfg(not(test))] pub fn trash(self) { }
|
|
|
|
#[cfg(test)] pub fn trash(self) { assert!(self.wake().is_none()); }
|
2013-06-26 18:41:00 -05:00
|
|
|
|
2013-12-12 20:01:59 -06:00
|
|
|
/// Create a blocked task, unless the task was already killed.
|
|
|
|
pub fn block(task: ~Task) -> BlockedTask {
|
|
|
|
Owned(task)
|
|
|
|
}
|
2013-07-19 16:25:05 -05:00
|
|
|
|
2013-12-12 20:01:59 -06:00
|
|
|
/// Converts one blocked task handle to a list of many handles to the same.
|
|
|
|
pub fn make_selectable(self, num_handles: uint) -> Take<BlockedTaskIterator>
|
|
|
|
{
|
|
|
|
let arc = match self {
|
|
|
|
Owned(task) => {
|
|
|
|
let flag = unsafe { AtomicUint::new(cast::transmute(task)) };
|
|
|
|
UnsafeArc::new(flag)
|
2013-06-26 18:41:00 -05:00
|
|
|
}
|
2013-12-12 20:01:59 -06:00
|
|
|
Shared(arc) => arc.clone(),
|
2013-06-26 18:41:00 -05:00
|
|
|
};
|
2013-12-12 20:01:59 -06:00
|
|
|
BlockedTaskIterator{ inner: arc }.take(num_handles)
|
2013-06-26 18:41:00 -05:00
|
|
|
}
|
|
|
|
|
2013-12-12 20:01:59 -06:00
|
|
|
/// Convert to an unsafe uint value. Useful for storing in a pipe's state
|
|
|
|
/// flag.
|
|
|
|
#[inline]
|
|
|
|
pub unsafe fn cast_to_uint(self) -> uint {
|
2013-06-26 18:41:00 -05:00
|
|
|
match self {
|
2013-12-12 20:01:59 -06:00
|
|
|
Owned(task) => {
|
|
|
|
let blocked_task_ptr: uint = cast::transmute(task);
|
|
|
|
rtassert!(blocked_task_ptr & 0x1 == 0);
|
|
|
|
blocked_task_ptr
|
|
|
|
}
|
|
|
|
Shared(arc) => {
|
|
|
|
let blocked_task_ptr: uint = cast::transmute(~arc);
|
|
|
|
rtassert!(blocked_task_ptr & 0x1 == 0);
|
|
|
|
blocked_task_ptr | 0x1
|
2013-06-26 18:41:00 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-12 20:01:59 -06:00
|
|
|
/// Convert from an unsafe uint value. Useful for retrieving a pipe's state
|
|
|
|
/// flag.
|
|
|
|
#[inline]
|
|
|
|
pub unsafe fn cast_from_uint(blocked_task_ptr: uint) -> BlockedTask {
|
|
|
|
if blocked_task_ptr & 0x1 == 0 {
|
|
|
|
Owned(cast::transmute(blocked_task_ptr))
|
2013-10-17 03:40:33 -05:00
|
|
|
} else {
|
2013-12-12 20:01:59 -06:00
|
|
|
let ptr: ~UnsafeArc<AtomicUint> =
|
|
|
|
cast::transmute(blocked_task_ptr & !1);
|
|
|
|
Shared(*ptr)
|
2013-10-17 03:40:33 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-12 20:01:59 -06:00
|
|
|
impl Death {
|
|
|
|
pub fn new() -> Death {
|
|
|
|
Death { on_exit: None, }
|
|
|
|
}
|
2013-10-11 16:20:34 -05:00
|
|
|
|
2013-12-12 20:01:59 -06:00
|
|
|
/// Collect failure exit codes from children and propagate them to a parent.
|
|
|
|
pub fn collect_failure(&mut self, result: TaskResult) {
|
|
|
|
match self.on_exit.take() {
|
|
|
|
Some(f) => f(result),
|
|
|
|
None => {}
|
2013-10-11 16:20:34 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-12 20:01:59 -06:00
|
|
|
impl Drop for Death {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
// make this type noncopyable
|
2013-10-09 12:34:27 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-21 21:03:52 -05:00
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
2013-10-27 14:12:40 -05:00
|
|
|
use super::*;
|
2013-04-21 21:03:52 -05:00
|
|
|
use rt::test::*;
|
2013-12-05 20:19:06 -06:00
|
|
|
use prelude::*;
|
2013-04-21 21:03:52 -05:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn local_heap() {
|
|
|
|
do run_in_newsched_task() {
|
|
|
|
let a = @5;
|
|
|
|
let b = a;
|
|
|
|
assert!(*a == 5);
|
|
|
|
assert!(*b == 5);
|
|
|
|
}
|
|
|
|
}
|
2013-04-22 14:54:03 -05:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn tls() {
|
2013-07-11 00:14:40 -05:00
|
|
|
use local_data;
|
2013-04-22 14:54:03 -05:00
|
|
|
do run_in_newsched_task() {
|
2013-09-17 01:34:40 -05:00
|
|
|
local_data_key!(key: @~str)
|
2013-07-12 03:38:44 -05:00
|
|
|
local_data::set(key, @~"data");
|
2013-09-20 01:08:47 -05:00
|
|
|
assert!(*local_data::get(key, |k| k.map(|k| *k)).unwrap() == ~"data");
|
2013-09-17 01:34:40 -05:00
|
|
|
local_data_key!(key2: @~str)
|
2013-07-12 03:38:44 -05:00
|
|
|
local_data::set(key2, @~"data");
|
2013-09-20 01:08:47 -05:00
|
|
|
assert!(*local_data::get(key2, |k| k.map(|k| *k)).unwrap() == ~"data");
|
2013-04-22 14:54:03 -05:00
|
|
|
}
|
|
|
|
}
|
2013-04-22 19:15:31 -05:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn unwind() {
|
|
|
|
do run_in_newsched_task() {
|
2013-11-22 01:36:52 -06:00
|
|
|
let result = spawntask_try(proc()());
|
2013-06-26 18:41:00 -05:00
|
|
|
rtdebug!("trying first assert");
|
2013-04-22 19:15:31 -05:00
|
|
|
assert!(result.is_ok());
|
2013-11-22 01:36:52 -06:00
|
|
|
let result = spawntask_try(proc() fail!());
|
2013-06-26 18:41:00 -05:00
|
|
|
rtdebug!("trying second assert");
|
2013-04-22 19:15:31 -05:00
|
|
|
assert!(result.is_err());
|
|
|
|
}
|
|
|
|
}
|
2013-05-06 20:24:37 -05:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn rng() {
|
2013-10-22 17:00:37 -05:00
|
|
|
do run_in_uv_task() {
|
2013-05-06 20:24:37 -05:00
|
|
|
use rand::{rng, Rng};
|
2013-05-08 14:26:34 -05:00
|
|
|
let mut r = rng();
|
2013-09-21 07:06:50 -05:00
|
|
|
let _ = r.next_u32();
|
2013-05-06 20:24:37 -05:00
|
|
|
}
|
|
|
|
}
|
2013-04-27 20:57:15 -05:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn logging() {
|
2013-10-22 17:00:37 -05:00
|
|
|
do run_in_uv_task() {
|
2013-10-21 15:08:31 -05:00
|
|
|
info!("here i am. logging in a newsched task");
|
2013-04-27 20:57:15 -05:00
|
|
|
}
|
|
|
|
}
|
2013-05-17 01:12:22 -05:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn comm_stream() {
|
|
|
|
do run_in_newsched_task() {
|
2013-12-05 20:19:06 -06:00
|
|
|
let (port, chan) = Chan::new();
|
2013-05-17 01:12:22 -05:00
|
|
|
chan.send(10);
|
|
|
|
assert!(port.recv() == 10);
|
|
|
|
}
|
|
|
|
}
|
2013-06-14 01:31:19 -05:00
|
|
|
|
2013-06-20 20:26:56 -05:00
|
|
|
#[test]
|
|
|
|
fn comm_shared_chan() {
|
|
|
|
do run_in_newsched_task() {
|
2013-12-05 20:19:06 -06:00
|
|
|
let (port, chan) = SharedChan::new();
|
2013-06-20 20:26:56 -05:00
|
|
|
chan.send(10);
|
|
|
|
assert!(port.recv() == 10);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-22 03:09:06 -05:00
|
|
|
#[test]
|
|
|
|
fn heap_cycles() {
|
|
|
|
use 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);
|
|
|
|
}
|
|
|
|
}
|
2013-10-27 14:12:40 -05:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_fail]
|
|
|
|
fn test_begin_unwind() { begin_unwind("cause", file!(), line!()) }
|
2013-12-12 20:01:59 -06:00
|
|
|
|
|
|
|
// Task blocking tests
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn block_and_wake() {
|
|
|
|
do with_test_task |task| {
|
|
|
|
BlockedTask::block(task).wake().unwrap()
|
|
|
|
}
|
|
|
|
}
|
2013-05-08 14:26:34 -05:00
|
|
|
}
|