use option::{Option, Some, None};
use prelude::*;
use rt::task::Task;
-use unstable::atomics::{AtomicUint, SeqCst};
+use unstable::atomics::{AtomicUint, Acquire, SeqCst};
use unstable::sync::{UnsafeAtomicRcBox, LittleLock};
use util;
}
}
+ #[inline]
+ pub fn killed(&self) -> bool {
+ // Called every context switch, so shouldn't report true if the task
+ // is unkillable with a kill signal pending.
+ let inner = unsafe { &*self.get() };
+ let flag = unsafe { &*inner.killed.get() };
+ // FIXME(#6598): can use relaxed ordering (i think)
+ flag.load(Acquire) == KILL_KILLED
+ }
+
pub fn notify_immediate_failure(&mut self) {
// A benign data race may happen here if there are failing sibling
// tasks that were also spawned-watched. The refcount's write barriers
self.unkillable = 0;
}
+ /// Fails if a kill signal was received.
+ #[inline]
+ pub fn check_killed(&self) {
+ match self.kill_handle {
+ Some(ref kill_handle) =>
+ // The task may be both unkillable and killed if it does some
+ // synchronization during unwinding or cleanup (for example,
+ // sending on a notify port). In that case failing won't help.
+ if self.unkillable == 0 && kill_handle.killed() {
+ fail!(KILLED_MSG);
+ },
+ // This may happen during task death (see comments in collect_failure).
+ None => rtassert!(self.unkillable > 0),
+ }
+ }
+
/// Enter a possibly-nested unkillable section of code.
/// All calls must be paired with a subsequent call to allow_kill.
#[inline]
// Running tasks may have asked us to do some cleanup
(*sched).run_cleanup_job();
+
+ // Must happen after running the cleanup job (of course).
+ // Might not be running in task context; if not, a later call to
+ // resume_task_immediately will take care of this.
+ (*sched).current_task.map(|t| t.death.check_killed());
}
}
// We could be executing in a different thread now
let sched = Local::unsafe_borrow::<Scheduler>();
(*sched).run_cleanup_job();
+
+ // As above, must happen after running the cleanup job.
+ (*sched).current_task.map(|t| t.death.check_killed());
}
}
// We could be executing in a different thread now
let sched = Local::unsafe_borrow::<Scheduler>();
(*sched).run_cleanup_job();
+
+ // As above, must happen after running the cleanup job.
+ (*sched).current_task.map(|t| t.death.check_killed());
}
}