diff options
| author | bors <bors@rust-lang.org> | 2013-08-23 00:16:28 -0700 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2013-08-23 00:16:28 -0700 |
| commit | 5e5e2c71e403371ff8a5d5430e7696654214a438 (patch) | |
| tree | 25ca443f4dd0b513202ddf00a4ad53515f8b184c /src/libstd | |
| parent | 0688bde47f1288eec730a3e01dcbf825900db3c0 (diff) | |
| parent | 0081961c57494162d9f2d19265175af95fbdd8d7 (diff) | |
| download | rust-5e5e2c71e403371ff8a5d5430e7696654214a438.tar.gz rust-5e5e2c71e403371ff8a5d5430e7696654214a438.zip | |
auto merge of #8677 : bblum/rust/scratch, r=alexcrichton
r anybody; there isn't anything complicated here
Diffstat (limited to 'src/libstd')
| -rw-r--r-- | src/libstd/cell.rs | 6 | ||||
| -rw-r--r-- | src/libstd/macros.rs | 36 | ||||
| -rw-r--r-- | src/libstd/rt/comm.rs | 13 | ||||
| -rw-r--r-- | src/libstd/rt/mod.rs | 1 | ||||
| -rw-r--r-- | src/libstd/task/spawn.rs | 77 |
5 files changed, 82 insertions, 51 deletions
diff --git a/src/libstd/cell.rs b/src/libstd/cell.rs index 5db855d5b3c..f9f5b66acb6 100644 --- a/src/libstd/cell.rs +++ b/src/libstd/cell.rs @@ -50,6 +50,12 @@ impl<T> Cell<T> { this.value.take_unwrap() } + /// Yields the value if the cell is full, or `None` if it is empty. + pub fn take_opt(&self) -> Option<T> { + let this = unsafe { transmute_mut(self) }; + this.value.take() + } + /// Returns the value, failing if the cell is full. pub fn put_back(&self, value: T) { let this = unsafe { transmute_mut(self) }; diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 89c7b294512..600d0bb133e 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -40,3 +40,39 @@ macro_rules! rtabort( } ) ) +macro_rules! assert_once_ever( + ($( $msg:expr),+) => ( { + // FIXME(#8472) extra function should not be needed to hide unsafe + fn assert_once_ever() { + unsafe { + static mut already_happened: int = 0; + // Double-check lock to avoid a swap in the common case. + if already_happened != 0 || + ::unstable::intrinsics::atomic_xchg_relaxed(&mut already_happened, 1) != 0 { + fail!(fmt!("assert_once_ever happened twice: %s", fmt!($($msg),+))); + } + } + } + assert_once_ever(); + } ) +) + +#[cfg(test)] +mod tests { + #[test] + fn test_assert_once_ever_ok() { + assert_once_ever!("help i'm stuck in an"); + assert_once_ever!("assertion error message"); + } + + #[test] #[ignore(cfg(windows))] #[should_fail] + fn test_assert_once_ever_fail() { + use task; + + fn f() { assert_once_ever!("if you're seeing this... good!") } + + // linked & watched, naturally + task::spawn(f); + task::spawn(f); + } +} diff --git a/src/libstd/rt/comm.rs b/src/libstd/rt/comm.rs index 5d55261a69d..8ef9c1332f9 100644 --- a/src/libstd/rt/comm.rs +++ b/src/libstd/rt/comm.rs @@ -499,13 +499,14 @@ impl<T> GenericPort<T> for Port<T> { } fn try_recv(&self) -> Option<T> { - let pone = self.next.take(); - match pone.try_recv() { - Some(StreamPayload { val, next }) => { - self.next.put_back(next); - Some(val) + do self.next.take_opt().map_move_default(None) |pone| { + match pone.try_recv() { + Some(StreamPayload { val, next }) => { + self.next.put_back(next); + Some(val) + } + None => None } - None => None } } } diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index db1bfdf1bf5..8b3e65b57ab 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -323,6 +323,7 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int { // task tree, shut down the schedulers and set the exit code. let handles = Cell::new(handles); let on_exit: ~fn(bool) = |exit_success| { + assert_once_ever!("last task exiting"); let mut handles = handles.take(); for handle in handles.mut_iter() { diff --git a/src/libstd/task/spawn.rs b/src/libstd/task/spawn.rs index 783d9c3e810..980141d29c3 100644 --- a/src/libstd/task/spawn.rs +++ b/src/libstd/task/spawn.rs @@ -446,8 +446,7 @@ fn taskgroup_key() -> local_data::Key<@@mut Taskgroup> { // Transitionary. struct RuntimeGlue; impl RuntimeGlue { - fn kill_task(handle: KillHandle) { - let mut handle = handle; + fn kill_task(mut handle: KillHandle) { do handle.kill().map_move |killed_task| { let killed_task = Cell::new(killed_task); do Local::borrow::<Scheduler, ()> |sched| { @@ -457,44 +456,38 @@ impl RuntimeGlue { } fn with_task_handle_and_failing(blk: &fn(&KillHandle, bool)) { - if in_green_task_context() { - unsafe { - // Can't use safe borrow, because the taskgroup destructor needs to - // access the scheduler again to send kill signals to other tasks. - let me = Local::unsafe_borrow::<Task>(); - blk((*me).death.kill_handle.get_ref(), (*me).unwinder.unwinding) - } - } else { - rtabort!("task dying in bad context") + rtassert!(in_green_task_context()); + unsafe { + // Can't use safe borrow, because the taskgroup destructor needs to + // access the scheduler again to send kill signals to other tasks. + let me = Local::unsafe_borrow::<Task>(); + blk((*me).death.kill_handle.get_ref(), (*me).unwinder.unwinding) } } fn with_my_taskgroup<U>(blk: &fn(&Taskgroup) -> U) -> U { - if in_green_task_context() { - unsafe { - // Can't use safe borrow, because creating new hashmaps for the - // tasksets requires an rng, which needs to borrow the sched. - let me = Local::unsafe_borrow::<Task>(); - blk(match (*me).taskgroup { - None => { - // First task in its (unlinked/unsupervised) taskgroup. - // Lazily initialize. - let mut members = TaskSet::new(); - let my_handle = (*me).death.kill_handle.get_ref().clone(); - members.insert(my_handle); - let tasks = Exclusive::new(Some(TaskGroupData { - members: members, - descendants: TaskSet::new(), - })); - let group = Taskgroup(tasks, AncestorList(None), None); - (*me).taskgroup = Some(group); - (*me).taskgroup.get_ref() - } - Some(ref group) => group, - }) - } - } else { - rtabort!("spawning in bad context") + rtassert!(in_green_task_context()); + unsafe { + // Can't use safe borrow, because creating new hashmaps for the + // tasksets requires an rng, which needs to borrow the sched. + let me = Local::unsafe_borrow::<Task>(); + blk(match (*me).taskgroup { + None => { + // First task in its (unlinked/unsupervised) taskgroup. + // Lazily initialize. + let mut members = TaskSet::new(); + let my_handle = (*me).death.kill_handle.get_ref().clone(); + members.insert(my_handle); + let tasks = Exclusive::new(Some(TaskGroupData { + members: members, + descendants: TaskSet::new(), + })); + let group = Taskgroup(tasks, AncestorList(None), None); + (*me).taskgroup = Some(group); + (*me).taskgroup.get_ref() + } + Some(ref group) => group, + }) } } } @@ -567,17 +560,11 @@ fn enlist_many(child: &KillHandle, child_arc: &TaskGroupArc, result } -pub fn spawn_raw(opts: TaskOpts, f: ~fn()) { - if in_green_task_context() { - spawn_raw_newsched(opts, f) - } else { - fail!("can't spawn from this context") - } -} - -fn spawn_raw_newsched(mut opts: TaskOpts, f: ~fn()) { +pub fn spawn_raw(mut opts: TaskOpts, f: ~fn()) { use rt::sched::*; + rtassert!(in_green_task_context()); + let child_data = Cell::new(gen_child_taskgroup(opts.linked, opts.supervised)); let indestructible = opts.indestructible; |
