about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-08-23 00:16:28 -0700
committerbors <bors@rust-lang.org>2013-08-23 00:16:28 -0700
commit5e5e2c71e403371ff8a5d5430e7696654214a438 (patch)
tree25ca443f4dd0b513202ddf00a4ad53515f8b184c /src/libstd
parent0688bde47f1288eec730a3e01dcbf825900db3c0 (diff)
parent0081961c57494162d9f2d19265175af95fbdd8d7 (diff)
downloadrust-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.rs6
-rw-r--r--src/libstd/macros.rs36
-rw-r--r--src/libstd/rt/comm.rs13
-rw-r--r--src/libstd/rt/mod.rs1
-rw-r--r--src/libstd/task/spawn.rs77
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;