diff options
| author | Marvin Löbel <loebel.marvin@gmail.com> | 2013-10-11 23:20:34 +0200 |
|---|---|---|
| committer | Marvin Löbel <loebel.marvin@gmail.com> | 2013-10-28 08:50:32 +0100 |
| commit | fa8e71a8257f4226ab532d4bf268d3ecbfa98eb4 (patch) | |
| tree | 0b8051814dd8a5ef08e663c172e2b456065d625d /src/libstd/rt/kill.rs | |
| parent | cb5b21eba713ff3888b2741db4c9e7d841cfde02 (diff) | |
| download | rust-fa8e71a8257f4226ab532d4bf268d3ecbfa98eb4.tar.gz rust-fa8e71a8257f4226ab532d4bf268d3ecbfa98eb4.zip | |
Allow fail messages to be caught, and introduce the Any trait
Some code cleanup, sorting of import blocks Removed std::unstable::UnsafeArc's use of Either Added run-fail tests for the new FailWithCause impls Changed future_result and try to return Result<(), ~Any>. - Internally, there is an enum of possible fail messages passend around. - In case of linked failure or a string message, the ~Any gets lazyly allocated in future_results recv method. - For that, future result now returns a wrapper around a Port. - Moved and renamed task::TaskResult into rt::task::UnwindResult and made it an internal enum. - Introduced a replacement typedef `type TaskResult = Result<(), ~Any>`.
Diffstat (limited to 'src/libstd/rt/kill.rs')
| -rw-r--r-- | src/libstd/rt/kill.rs | 34 |
1 files changed, 23 insertions, 11 deletions
diff --git a/src/libstd/rt/kill.rs b/src/libstd/rt/kill.rs index 19f17ca966d..edf6ffb820b 100644 --- a/src/libstd/rt/kill.rs +++ b/src/libstd/rt/kill.rs @@ -152,14 +152,15 @@ There are two known issues with the current scheme for exit code propagation. use cast; use cell::Cell; -use either::{Either, Left, Right}; use option::{Option, Some, None}; use prelude::*; use rt::task::Task; +use rt::task::UnwindReasonLinked; +use rt::task::{UnwindResult, Failure}; use task::spawn::Taskgroup; use to_bytes::IterBytes; use unstable::atomics::{AtomicUint, Relaxed}; -use unstable::sync::{UnsafeArc, LittleLock}; +use unstable::sync::{UnsafeArc, UnsafeArcSelf, UnsafeArcT, LittleLock}; use util; static KILLED_MSG: &'static str = "killed by linked failure"; @@ -222,7 +223,7 @@ pub struct Death { priv watching_parent: Option<KillHandle>, // 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<~fn(bool)>, + on_exit: Option<~fn(UnwindResult)>, // nesting level counter for task::unkillable calls (0 == killable). priv unkillable: int, // nesting level counter for unstable::atomically calls (0 == can deschedule). @@ -478,7 +479,7 @@ impl KillHandle { match self.try_unwrap() { // Couldn't unwrap; children still alive. Reparent entire handle as // our own tombstone, to be unwrapped later. - Left(this) => { + UnsafeArcSelf(this) => { let this = Cell::new(this); // :( do add_lazy_tombstone(parent) |other_tombstones| { let this = Cell::new(this.take()); // :( @@ -494,14 +495,16 @@ impl KillHandle { } } } + // Whether or not all children exited, one or more already failed. - Right(KillHandleInner { any_child_failed: true, _ }) => { + UnsafeArcT(KillHandleInner { any_child_failed: true, _ }) => { parent.notify_immediate_failure(); } + // All children exited, but some left behind tombstones that we // don't want to wait on now. Give them to our parent. - Right(KillHandleInner { any_child_failed: false, - child_tombstones: Some(f), _ }) => { + UnsafeArcT(KillHandleInner { any_child_failed: false, + child_tombstones: Some(f), _ }) => { let f = Cell::new(f); // :( do add_lazy_tombstone(parent) |other_tombstones| { let f = Cell::new(f.take()); // :( @@ -513,9 +516,10 @@ impl KillHandle { } } } + // All children exited, none failed. Nothing to do! - Right(KillHandleInner { any_child_failed: false, - child_tombstones: None, _ }) => { } + UnsafeArcT(KillHandleInner { any_child_failed: false, + child_tombstones: None, _ }) => { } } // NB: Takes a pthread mutex -- 'blk' not allowed to reschedule. @@ -562,7 +566,7 @@ impl Death { } /// Collect failure exit codes from children and propagate them to a parent. - pub fn collect_failure(&mut self, mut success: bool, group: Option<Taskgroup>) { + pub fn collect_failure(&mut self, result: UnwindResult, group: Option<Taskgroup>) { // This may run after the task has already failed, so even though the // task appears to need to be killed, the scheduler should not fail us // when we block to unwrap. @@ -576,19 +580,27 @@ impl Death { // FIXME(#8192): Doesn't work with "let _ = ..." { use util; util::ignore(group); } + let mut success = result.is_success(); + let mut result = Cell::new(result); + // Step 1. Decide if we need to collect child failures synchronously. do self.on_exit.take().map |on_exit| { if success { // We succeeded, but our children might not. Need to wait for them. let mut inner = self.kill_handle.take_unwrap().unwrap(); + if inner.any_child_failed { success = false; } else { // Lockless access to tombstones protected by unwrap barrier. success = inner.child_tombstones.take().map_default(true, |f| f()); } + + if !success { + result = Cell::new(Failure(UnwindReasonLinked)); + } } - on_exit(success); + on_exit(result.take()); }; // Step 2. Possibly alert possibly-watching parent to failure status. |
