X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Flibstd%2Frt%2Ftask.rs;h=b4ead4252ca4158a461da8d94dea3b36a10f82bc;hb=f78293c274be2a23889f20942d75e9e45352a336;hp=91e285b1061edf5a94f2e6b240477d990b747889;hpb=3893716390f2c4857b7e8b1705a6344f96b85bb6;p=rust.git diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs index 91e285b1061..b4ead4252ca 100644 --- a/src/libstd/rt/task.rs +++ b/src/libstd/rt/task.rs @@ -15,10 +15,13 @@ use any::AnyOwnExt; use borrow; +use cast; use cleanup; +use clone::Clone; use io::Writer; -use libc::{c_char, size_t}; +use iter::{Iterator, Take}; use local_data; +use logging::Logger; use ops::Drop; use option::{Option, Some, None}; use prelude::drop; @@ -28,20 +31,13 @@ use rt::borrowck; use rt::local::Local; use rt::local_heap::LocalHeap; -use rt::logging::StdErrLogger; use rt::rtio::LocalIo; use rt::unwind::Unwinder; use send_str::SendStr; use sync::arc::UnsafeArc; -use sync::atomics::{AtomicUint, SeqCst, INIT_ATOMIC_UINT}; +use sync::atomics::{AtomicUint, SeqCst}; use task::{TaskResult, TaskOpts}; use unstable::finally::Finally; -use unstable::mutex::{Mutex, MUTEX_INIT}; - -#[cfg(stage0)] pub use rt::unwind::begin_unwind; - -static mut TASK_COUNT: AtomicUint = INIT_ATOMIC_UINT; -static mut TASK_LOCK: Mutex = MUTEX_INIT; // The Task struct represents all state associated with a rust // task. There are at this point two primary "subtypes" of task, @@ -60,8 +56,9 @@ pub struct Task { // Dynamic borrowck debugging info borrow_list: Option<~[BorrowRecord]>, - logger: Option, - stdout_handle: Option<~Writer>, + logger: Option<~Logger>, + stdout: Option<~Writer>, + stderr: Option<~Writer>, priv imp: Option<~Runtime>, } @@ -99,7 +96,8 @@ pub fn new() -> Task { name: None, borrow_list: None, logger: None, - stdout_handle: None, + stdout: None, + stderr: None, imp: None, } } @@ -121,7 +119,6 @@ pub fn run(~self, f: ||) -> ~Task { *cast::transmute::<&~Task, &*mut Task>(&self) }; Local::put(self); - unsafe { TASK_COUNT.fetch_add(1, SeqCst); } // The only try/catch block in the world. Attempt to run the task's // client-specified code and catch any failures. @@ -129,13 +126,21 @@ pub fn run(~self, f: ||) -> ~Task { // Run the task main function, then do some cleanup. f.finally(|| { - fn flush(w: Option<~Writer>) { - match w { - Some(mut w) => { w.flush(); } - None => {} - } + fn close_outputs() { + let mut task = Local::borrow(None::); + let logger = task.get().logger.take(); + let stderr = task.get().stderr.take(); + let stdout = task.get().stdout.take(); + drop(task); + drop(logger); // loggers are responsible for flushing + match stdout { Some(mut w) => w.flush(), None => {} } + match stderr { Some(mut w) => w.flush(), None => {} } } + // First, flush/destroy the user stdout/logger because these + // destructors can run arbitrary code. + close_outputs(); + // First, destroy task-local storage. This may run user dtors. // // FIXME #8302: Dear diary. I'm so tired and confused. @@ -156,23 +161,23 @@ fn flush(w: Option<~Writer>) { // annihilated invoke TLS. Sadly these two operations seemed to // be intertwined, and miraculously work for now... let mut task = Local::borrow(None::); - let storage = task.get().storage.take(); + let storage_map = { + let task = task.get(); + let LocalStorage(ref mut optmap) = task.storage; + optmap.take() + }; drop(task); - drop(storage); + drop(storage_map); // Destroy remaining boxes. Also may run user dtors. unsafe { cleanup::annihilate(); } - // 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. - let mut task = Local::borrow(None::); - let stdout = task.get().stdout_handle.take(); - let logger = task.get().logger.take(); - drop(task); - - flush(stdout); - drop(logger); + // Finally, just in case user dtors printed/logged during TLS + // cleanup and annihilation, re-destroy stdout and the logger. + // Note that these will have been initialized with a + // runtime-provided type which we have control over what the + // destructor does. + close_outputs(); }) }; @@ -181,15 +186,13 @@ fn flush(w: Option<~Writer>) { // Cleanup the dynamic borrowck debugging info borrowck::clear_task_borrow_list(); - // TODO: dox + // Here we must unsafely borrow the task in order to not remove it from + // TLS. When collecting failure, we may attempt to send on a channel (or + // just run aribitrary code), so we must be sure to still have a local + // task in TLS. unsafe { let me: *mut Task = Local::unsafe_borrow(); (*me).death.collect_failure((*me).unwinder.result()); - if TASK_COUNT.fetch_sub(1, SeqCst) == 1 { - TASK_LOCK.lock(); - TASK_LOCK.signal(); - TASK_LOCK.unlock(); - } } let mut me: ~Task = Local::take(); me.destroyed = true; @@ -282,6 +285,13 @@ pub fn maybe_yield(mut ~self) { pub fn local_io<'a>(&'a mut self) -> Option> { self.imp.get_mut_ref().local_io() } + + /// Returns the stack bounds for this task in (lo, hi) format. The stack + /// bounds may not be known for all tasks, so the return value may be + /// `None`. + pub fn stack_bounds(&self) -> (uint, uint) { + self.imp.get_ref().stack_bounds() + } } impl Drop for Task { @@ -386,14 +396,6 @@ fn drop(&mut self) { } } -pub unsafe fn wait_for_completion() { - TASK_LOCK.lock(); - while TASK_COUNT.load(SeqCst) > 0 { - TASK_LOCK.wait(); - } - TASK_LOCK.unlock(); -} - #[cfg(test)] mod test { use super::*; @@ -457,21 +459,28 @@ fn comm_shared_chan() { #[test] fn heap_cycles() { + use cell::RefCell; use option::{Option, Some, None}; struct List { - next: Option<@mut List>, + next: Option<@RefCell>, } - let a = @mut List { next: None }; - let b = @mut List { next: Some(a) }; + let a = @RefCell::new(List { next: None }); + let b = @RefCell::new(List { next: Some(a) }); - a.next = Some(b); + { + let mut a = a.borrow_mut(); + a.get().next = Some(b); + } } #[test] #[should_fail] - fn test_begin_unwind() { begin_unwind("cause", file!(), line!()) } + fn test_begin_unwind() { + use rt::unwind::begin_unwind; + begin_unwind("cause", file!(), line!()) + } // Task blocking tests