about summary refs log tree commit diff
path: root/src/libcore
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-05-13 14:49:48 -0700
committerbors <bors@rust-lang.org>2013-05-13 14:49:48 -0700
commitad5bfd600d1611c9d1bb933a383d0db2fa0ee7bf (patch)
tree5f4639e6b344a37bb62b08d5440e441d5e957ece /src/libcore
parent3abc5b3ffb87b51931594f9ce953af648aad342e (diff)
parent369231beb4b29a16c27bcc2c4f9a5679b613ed19 (diff)
downloadrust-ad5bfd600d1611c9d1bb933a383d0db2fa0ee7bf.tar.gz
rust-ad5bfd600d1611c9d1bb933a383d0db2fa0ee7bf.zip
auto merge of #6387 : brson/rust/unstable, r=brson
r? @pcwalton

* Move `SharedMutableState`, `LittleLock`, and `Exclusive` from `core::unstable` to `core::unstable::sync`
* Modernize the `SharedMutableState` interface with methods
* Rename `SharedMutableState` to `UnsafeAtomicRcBox` to match `RcBox`.
Diffstat (limited to 'src/libcore')
-rw-r--r--src/libcore/comm.rs4
-rw-r--r--src/libcore/core.rc1
-rw-r--r--src/libcore/os.rs4
-rw-r--r--src/libcore/task/spawn.rs13
-rw-r--r--src/libcore/unstable.rs354
-rw-r--r--src/libcore/unstable/global.rs23
-rw-r--r--src/libcore/unstable/mod.rs78
-rw-r--r--src/libcore/unstable/sync.rs286
-rw-r--r--src/libcore/vec.rs5
9 files changed, 388 insertions, 380 deletions
diff --git a/src/libcore/comm.rs b/src/libcore/comm.rs
index b1f60ec4690..322584f8df1 100644
--- a/src/libcore/comm.rs
+++ b/src/libcore/comm.rs
@@ -19,8 +19,8 @@ use option::{Option, Some, None};
 use uint;
 use unstable;
 use vec;
-use unstable::Exclusive;
 use util::replace;
+use unstable::sync::{Exclusive, exclusive};
 
 use pipes::{recv, try_recv, wait_many, peek, PacketHeader};
 
@@ -304,7 +304,7 @@ pub struct SharedChan<T> {
 impl<T: Owned> SharedChan<T> {
     /// Converts a `chan` into a `shared_chan`.
     pub fn new(c: Chan<T>) -> SharedChan<T> {
-        SharedChan { ch: unstable::exclusive(c) }
+        SharedChan { ch: exclusive(c) }
     }
 }
 
diff --git a/src/libcore/core.rc b/src/libcore/core.rc
index d029fbc07f6..0b4c0cf8069 100644
--- a/src/libcore/core.rc
+++ b/src/libcore/core.rc
@@ -238,6 +238,7 @@ pub mod util;
 /* Unsupported interfaces */
 
 // Private APIs
+#[path = "unstable/mod.rs"]
 pub mod unstable;
 
 /* For internal use, not exported */
diff --git a/src/libcore/os.rs b/src/libcore/os.rs
index d983377245c..3e87f4f8dbb 100644
--- a/src/libcore/os.rs
+++ b/src/libcore/os.rs
@@ -152,7 +152,7 @@ FIXME #4726: It would probably be appropriate to make this a real global
 */
 fn with_env_lock<T>(f: &fn() -> T) -> T {
     use unstable::global::global_data_clone_create;
-    use unstable::{Exclusive, exclusive};
+    use unstable::sync::{Exclusive, exclusive};
 
     struct SharedValue(());
     type ValueMutex = Exclusive<SharedValue>;
@@ -855,7 +855,7 @@ pub fn change_dir(p: &Path) -> bool {
 /// is otherwise unsuccessful.
 pub fn change_dir_locked(p: &Path, action: &fn()) -> bool {
     use unstable::global::global_data_clone_create;
-    use unstable::{Exclusive, exclusive};
+    use unstable::sync::{Exclusive, exclusive};
 
     fn key(_: Exclusive<()>) { }
 
diff --git a/src/libcore/task/spawn.rs b/src/libcore/task/spawn.rs
index 327b7a988aa..545f1ac8ada 100644
--- a/src/libcore/task/spawn.rs
+++ b/src/libcore/task/spawn.rs
@@ -90,6 +90,7 @@ use task::{ExistingScheduler, SchedulerHandle};
 use task::unkillable;
 use uint;
 use util;
+use unstable::sync::{Exclusive, exclusive};
 
 #[cfg(test)] use task::default_task_opts;
 
@@ -128,7 +129,7 @@ struct TaskGroupData {
     // tasks in this group.
     descendants: TaskSet,
 }
-type TaskGroupArc = unstable::Exclusive<Option<TaskGroupData>>;
+type TaskGroupArc = Exclusive<Option<TaskGroupData>>;
 
 type TaskGroupInner<'self> = &'self mut Option<TaskGroupData>;
 
@@ -158,7 +159,7 @@ struct AncestorNode {
     ancestors:      AncestorList,
 }
 
-struct AncestorList(Option<unstable::Exclusive<AncestorNode>>);
+struct AncestorList(Option<Exclusive<AncestorNode>>);
 
 // Accessors for taskgroup arcs and ancestor arcs that wrap the unsafety.
 #[inline(always)]
@@ -167,7 +168,7 @@ fn access_group<U>(x: &TaskGroupArc, blk: &fn(TaskGroupInner) -> U) -> U {
 }
 
 #[inline(always)]
-fn access_ancestors<U>(x: &unstable::Exclusive<AncestorNode>,
+fn access_ancestors<U>(x: &Exclusive<AncestorNode>,
                        blk: &fn(x: &mut AncestorNode) -> U) -> U {
     x.with(blk)
 }
@@ -479,7 +480,7 @@ fn gen_child_taskgroup(linked: bool, supervised: bool)
                     // here.
                     let mut members = new_taskset();
                     taskset_insert(&mut members, spawner);
-                    let tasks = unstable::exclusive(Some(TaskGroupData {
+                    let tasks = exclusive(Some(TaskGroupData {
                         members: members,
                         descendants: new_taskset(),
                     }));
@@ -508,7 +509,7 @@ fn gen_child_taskgroup(linked: bool, supervised: bool)
             (g, a, spawner_group.is_main)
         } else {
             // Child is in a separate group from spawner.
-            let g = unstable::exclusive(Some(TaskGroupData {
+            let g = exclusive(Some(TaskGroupData {
                 members:     new_taskset(),
                 descendants: new_taskset(),
             }));
@@ -528,7 +529,7 @@ fn gen_child_taskgroup(linked: bool, supervised: bool)
                     };
                 assert!(new_generation < uint::max_value);
                 // Build a new node in the ancestor list.
-                AncestorList(Some(unstable::exclusive(AncestorNode {
+                AncestorList(Some(exclusive(AncestorNode {
                     generation: new_generation,
                     parent_group: Some(spawner_group.tasks.clone()),
                     ancestors: old_ancestors,
diff --git a/src/libcore/unstable.rs b/src/libcore/unstable.rs
deleted file mode 100644
index 25e4d07b01d..00000000000
--- a/src/libcore/unstable.rs
+++ /dev/null
@@ -1,354 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#[doc(hidden)];
-
-use cast;
-use libc;
-use comm::{GenericChan, GenericPort};
-use prelude::*;
-use task;
-use task::atomically;
-use self::finally::Finally;
-
-#[path = "unstable/at_exit.rs"]
-pub mod at_exit;
-#[path = "unstable/global.rs"]
-pub mod global;
-#[path = "unstable/finally.rs"]
-pub mod finally;
-#[path = "unstable/weak_task.rs"]
-pub mod weak_task;
-#[path = "unstable/exchange_alloc.rs"]
-pub mod exchange_alloc;
-#[path = "unstable/intrinsics.rs"]
-pub mod intrinsics;
-#[path = "unstable/simd.rs"]
-pub mod simd;
-#[path = "unstable/extfmt.rs"]
-pub mod extfmt;
-#[path = "unstable/lang.rs"]
-#[cfg(not(test))]
-pub mod lang;
-
-mod rustrt {
-    use unstable::{raw_thread, rust_little_lock};
-
-    pub extern {
-        pub unsafe fn rust_create_little_lock() -> rust_little_lock;
-        pub unsafe fn rust_destroy_little_lock(lock: rust_little_lock);
-        pub unsafe fn rust_lock_little_lock(lock: rust_little_lock);
-        pub unsafe fn rust_unlock_little_lock(lock: rust_little_lock);
-
-        pub unsafe fn rust_raw_thread_start(f: &(&fn())) -> *raw_thread;
-        pub unsafe fn rust_raw_thread_join_delete(thread: *raw_thread);
-    }
-}
-
-#[allow(non_camel_case_types)] // runtime type
-pub type raw_thread = libc::c_void;
-
-/**
-
-Start a new thread outside of the current runtime context and wait
-for it to terminate.
-
-The executing thread has no access to a task pointer and will be using
-a normal large stack.
-*/
-pub fn run_in_bare_thread(f: ~fn()) {
-    let (port, chan) = comm::stream();
-    // FIXME #4525: Unfortunate that this creates an extra scheduler but it's
-    // necessary since rust_raw_thread_join_delete is blocking
-    do task::spawn_sched(task::SingleThreaded) {
-        unsafe {
-            let closure: &fn() = || {
-                f()
-            };
-            let thread = rustrt::rust_raw_thread_start(&closure);
-            rustrt::rust_raw_thread_join_delete(thread);
-            chan.send(());
-        }
-    }
-    port.recv();
-}
-
-#[test]
-fn test_run_in_bare_thread() {
-    let i = 100;
-    do run_in_bare_thread {
-        assert!(i == 100);
-    }
-}
-
-#[test]
-fn test_run_in_bare_thread_exchange() {
-    // Does the exchange heap work without the runtime?
-    let i = ~100;
-    do run_in_bare_thread {
-        assert!(i == ~100);
-    }
-}
-
-fn compare_and_swap(address: &mut int, oldval: int, newval: int) -> bool {
-    unsafe {
-        let old = intrinsics::atomic_cxchg(address, oldval, newval);
-        old == oldval
-    }
-}
-
-/****************************************************************************
- * Shared state & exclusive ARC
- ****************************************************************************/
-
-struct ArcData<T> {
-    count:     libc::intptr_t,
-    // FIXME(#3224) should be able to make this non-option to save memory
-    data:      Option<T>,
-}
-
-struct ArcDestruct<T> {
-    data: *libc::c_void,
-}
-
-#[unsafe_destructor]
-impl<T> Drop for ArcDestruct<T>{
-    fn finalize(&self) {
-        unsafe {
-            do task::unkillable {
-                let mut data: ~ArcData<T> = cast::transmute(self.data);
-                let new_count =
-                    intrinsics::atomic_xsub(&mut data.count, 1) - 1;
-                assert!(new_count >= 0);
-                if new_count == 0 {
-                    // drop glue takes over.
-                } else {
-                    cast::forget(data);
-                }
-            }
-        }
-    }
-}
-
-fn ArcDestruct<T>(data: *libc::c_void) -> ArcDestruct<T> {
-    ArcDestruct {
-        data: data
-    }
-}
-
-/**
- * COMPLETELY UNSAFE. Used as a primitive for the safe versions in std::arc.
- *
- * Data races between tasks can result in crashes and, with sufficient
- * cleverness, arbitrary type coercion.
- */
-pub type SharedMutableState<T> = ArcDestruct<T>;
-
-pub unsafe fn shared_mutable_state<T:Owned>(data: T) ->
-        SharedMutableState<T> {
-    let data = ~ArcData { count: 1, data: Some(data) };
-    let ptr = cast::transmute(data);
-    ArcDestruct(ptr)
-}
-
-#[inline(always)]
-pub unsafe fn get_shared_mutable_state<T:Owned>(
-    rc: *SharedMutableState<T>) -> *mut T
-{
-    let ptr: ~ArcData<T> = cast::transmute((*rc).data);
-    assert!(ptr.count > 0);
-    let r = cast::transmute(ptr.data.get_ref());
-    cast::forget(ptr);
-    return r;
-}
-#[inline(always)]
-pub unsafe fn get_shared_immutable_state<'a,T:Owned>(
-        rc: &'a SharedMutableState<T>) -> &'a T {
-    let ptr: ~ArcData<T> = cast::transmute((*rc).data);
-    assert!(ptr.count > 0);
-    // Cast us back into the correct region
-    let r = cast::transmute_region(ptr.data.get_ref());
-    cast::forget(ptr);
-    return r;
-}
-
-pub unsafe fn clone_shared_mutable_state<T:Owned>(rc: &SharedMutableState<T>)
-        -> SharedMutableState<T> {
-    let mut ptr: ~ArcData<T> = cast::transmute((*rc).data);
-    let new_count = intrinsics::atomic_xadd(&mut ptr.count, 1) + 1;
-    assert!(new_count >= 2);
-    cast::forget(ptr);
-    ArcDestruct((*rc).data)
-}
-
-impl<T:Owned> Clone for SharedMutableState<T> {
-    fn clone(&self) -> SharedMutableState<T> {
-        unsafe {
-            clone_shared_mutable_state(self)
-        }
-    }
-}
-
-/****************************************************************************/
-
-#[allow(non_camel_case_types)] // runtime type
-pub type rust_little_lock = *libc::c_void;
-
-struct LittleLock {
-    l: rust_little_lock,
-}
-
-impl Drop for LittleLock {
-    fn finalize(&self) {
-        unsafe {
-            rustrt::rust_destroy_little_lock(self.l);
-        }
-    }
-}
-
-fn LittleLock() -> LittleLock {
-    unsafe {
-        LittleLock {
-            l: rustrt::rust_create_little_lock()
-        }
-    }
-}
-
-pub impl LittleLock {
-    #[inline(always)]
-    unsafe fn lock<T>(&self, f: &fn() -> T) -> T {
-        do atomically {
-            rustrt::rust_lock_little_lock(self.l);
-            do (|| {
-                f()
-            }).finally {
-                rustrt::rust_unlock_little_lock(self.l);
-            }
-        }
-    }
-}
-
-struct ExData<T> {
-    lock: LittleLock,
-    failed: bool,
-    data: T,
-}
-
-/**
- * An arc over mutable data that is protected by a lock. For library use only.
- */
-pub struct Exclusive<T> {
-    x: SharedMutableState<ExData<T>>
-}
-
-pub fn exclusive<T:Owned>(user_data: T) -> Exclusive<T> {
-    let data = ExData {
-        lock: LittleLock(),
-        failed: false,
-        data: user_data
-    };
-    Exclusive {
-        x: unsafe {
-            shared_mutable_state(data)
-        }
-    }
-}
-
-impl<T:Owned> Clone for Exclusive<T> {
-    // Duplicate an exclusive ARC, as std::arc::clone.
-    fn clone(&self) -> Exclusive<T> {
-        Exclusive { x: unsafe { clone_shared_mutable_state(&self.x) } }
-    }
-}
-
-pub impl<T:Owned> Exclusive<T> {
-    // Exactly like std::arc::mutex_arc,access(), but with the little_lock
-    // instead of a proper mutex. Same reason for being unsafe.
-    //
-    // Currently, scheduling operations (i.e., yielding, receiving on a pipe,
-    // accessing the provided condition variable) are prohibited while inside
-    // the exclusive. Supporting that is a work in progress.
-    #[inline(always)]
-    unsafe fn with<U>(&self, f: &fn(x: &mut T) -> U) -> U {
-        let rec = get_shared_mutable_state(&self.x);
-        do (*rec).lock.lock {
-            if (*rec).failed {
-                fail!(
-                    ~"Poisoned exclusive - another task failed inside!");
-            }
-            (*rec).failed = true;
-            let result = f(&mut (*rec).data);
-            (*rec).failed = false;
-            result
-        }
-    }
-
-    #[inline(always)]
-    unsafe fn with_imm<U>(&self, f: &fn(x: &T) -> U) -> U {
-        do self.with |x| {
-            f(cast::transmute_immut(x))
-        }
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use comm;
-    use super::exclusive;
-    use task;
-    use uint;
-
-    #[test]
-    fn exclusive_arc() {
-        let mut futures = ~[];
-
-        let num_tasks = 10;
-        let count = 10;
-
-        let total = exclusive(~0);
-
-        for uint::range(0, num_tasks) |_i| {
-            let total = total.clone();
-            let (port, chan) = comm::stream();
-            futures.push(port);
-
-            do task::spawn || {
-                for uint::range(0, count) |_i| {
-                    do total.with |count| {
-                        **count += 1;
-                    }
-                }
-                chan.send(());
-            }
-        };
-
-        for futures.each |f| { f.recv() }
-
-        do total.with |total| {
-            assert!(**total == num_tasks * count)
-        };
-    }
-
-    #[test] #[should_fail] #[ignore(cfg(windows))]
-    fn exclusive_poison() {
-        // Tests that if one task fails inside of an exclusive, subsequent
-        // accesses will also fail.
-        let x = exclusive(1);
-        let x2 = x.clone();
-        do task::try || {
-            do x2.with |one| {
-                assert!(*one == 2);
-            }
-        };
-        do x.with |one| {
-            assert!(*one == 1);
-        }
-    }
-}
diff --git a/src/libcore/unstable/global.rs b/src/libcore/unstable/global.rs
index eac686e28d1..2d6698fb96a 100644
--- a/src/libcore/unstable/global.rs
+++ b/src/libcore/unstable/global.rs
@@ -31,14 +31,13 @@ use kinds::Owned;
 use libc::{c_void};
 use option::{Option, Some, None};
 use ops::Drop;
-use unstable::{Exclusive, exclusive};
+use unstable::sync::{Exclusive, exclusive};
 use unstable::at_exit::at_exit;
 use unstable::intrinsics::atomic_cxchg;
 use hashmap::HashMap;
 use sys::Closure;
 
-#[cfg(test)] use unstable::{SharedMutableState, shared_mutable_state};
-#[cfg(test)] use unstable::get_shared_immutable_state;
+#[cfg(test)] use unstable::sync::{UnsafeAtomicRcBox};
 #[cfg(test)] use task::spawn;
 #[cfg(test)] use uint;
 
@@ -234,18 +233,16 @@ extern {
 
 #[test]
 fn test_clone_rc() {
-    type MyType = SharedMutableState<int>;
-
-    fn key(_v: SharedMutableState<int>) { }
+    fn key(_v: UnsafeAtomicRcBox<int>) { }
 
     for uint::range(0, 100) |_| {
         do spawn {
             unsafe {
                 let val = do global_data_clone_create(key) {
-                    ~shared_mutable_state(10)
+                    ~UnsafeAtomicRcBox::new(10)
                 };
 
-                assert!(get_shared_immutable_state(&val) == &10);
+                assert!(val.get() == &10);
             }
         }
     }
@@ -253,16 +250,14 @@ fn test_clone_rc() {
 
 #[test]
 fn test_modify() {
-    type MyType = SharedMutableState<int>;
-
-    fn key(_v: SharedMutableState<int>) { }
+    fn key(_v: UnsafeAtomicRcBox<int>) { }
 
     unsafe {
         do global_data_modify(key) |v| {
             match v {
                 None => {
                     unsafe {
-                        Some(~shared_mutable_state(10))
+                        Some(~UnsafeAtomicRcBox::new(10))
                     }
                 }
                 _ => fail!()
@@ -272,7 +267,7 @@ fn test_modify() {
         do global_data_modify(key) |v| {
             match v {
                 Some(sms) => {
-                    let v = get_shared_immutable_state(sms);
+                    let v = sms.get();
                     assert!(*v == 10);
                     None
                 },
@@ -284,7 +279,7 @@ fn test_modify() {
             match v {
                 None => {
                     unsafe {
-                        Some(~shared_mutable_state(10))
+                        Some(~UnsafeAtomicRcBox::new(10))
                     }
                 }
                 _ => fail!()
diff --git a/src/libcore/unstable/mod.rs b/src/libcore/unstable/mod.rs
new file mode 100644
index 00000000000..bef7a7f87d3
--- /dev/null
+++ b/src/libcore/unstable/mod.rs
@@ -0,0 +1,78 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[doc(hidden)];
+
+use libc;
+use comm::{GenericChan, GenericPort};
+use prelude::*;
+use task;
+
+pub mod at_exit;
+pub mod global;
+pub mod finally;
+pub mod weak_task;
+pub mod exchange_alloc;
+pub mod intrinsics;
+pub mod simd;
+pub mod extfmt;
+#[cfg(not(test))]
+pub mod lang;
+pub mod sync;
+
+/**
+
+Start a new thread outside of the current runtime context and wait
+for it to terminate.
+
+The executing thread has no access to a task pointer and will be using
+a normal large stack.
+*/
+pub fn run_in_bare_thread(f: ~fn()) {
+    let (port, chan) = comm::stream();
+    // FIXME #4525: Unfortunate that this creates an extra scheduler but it's
+    // necessary since rust_raw_thread_join_delete is blocking
+    do task::spawn_sched(task::SingleThreaded) {
+        unsafe {
+            let closure: &fn() = || {
+                f()
+            };
+            let thread = rust_raw_thread_start(&closure);
+            rust_raw_thread_join_delete(thread);
+            chan.send(());
+        }
+    }
+    port.recv();
+}
+
+#[test]
+fn test_run_in_bare_thread() {
+    let i = 100;
+    do run_in_bare_thread {
+        assert!(i == 100);
+    }
+}
+
+#[test]
+fn test_run_in_bare_thread_exchange() {
+    // Does the exchange heap work without the runtime?
+    let i = ~100;
+    do run_in_bare_thread {
+        assert!(i == ~100);
+    }
+}
+
+#[allow(non_camel_case_types)] // runtime type
+pub type raw_thread = libc::c_void;
+
+extern {
+    fn rust_raw_thread_start(f: &(&fn())) -> *raw_thread;
+    fn rust_raw_thread_join_delete(thread: *raw_thread);
+}
diff --git a/src/libcore/unstable/sync.rs b/src/libcore/unstable/sync.rs
new file mode 100644
index 00000000000..e22046f04f9
--- /dev/null
+++ b/src/libcore/unstable/sync.rs
@@ -0,0 +1,286 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use cast;
+use libc;
+use option::*;
+use task;
+use task::atomically;
+use unstable::finally::Finally;
+use unstable::intrinsics;
+use ops::Drop;
+use clone::Clone;
+use kinds::Owned;
+
+/// An atomically reference counted pointer.
+///
+/// Enforces no shared-memory safety.
+pub struct UnsafeAtomicRcBox<T> {
+    data: *mut libc::c_void,
+}
+
+struct AtomicRcBoxData<T> {
+    count: int,
+    data: Option<T>,
+}
+
+impl<T: Owned> UnsafeAtomicRcBox<T> {
+    pub fn new(data: T) -> UnsafeAtomicRcBox<T> {
+        unsafe {
+            let data = ~AtomicRcBoxData { count: 1, data: Some(data) };
+            let ptr = cast::transmute(data);
+            return UnsafeAtomicRcBox { data: ptr };
+        }
+    }
+
+    #[inline(always)]
+    #[cfg(stage0)]
+    pub unsafe fn get(&self) -> *mut T
+    {
+        let mut data: ~AtomicRcBoxData<T> = cast::transmute(self.data);
+        assert!(data.count > 0);
+        let r: *mut T = cast::transmute(data.data.get_mut_ref());
+        cast::forget(data);
+        return r;
+    }
+
+    #[inline(always)]
+    #[cfg(not(stage0))]
+    pub unsafe fn get(&self) -> *mut T
+    {
+        let mut data: ~AtomicRcBoxData<T> = cast::transmute(self.data);
+        assert!(data.count > 0);
+        let r: *mut T = data.data.get_mut_ref();
+        cast::forget(data);
+        return r;
+    }
+
+    #[inline(always)]
+    #[cfg(stage0)]
+    pub unsafe fn get_immut(&self) -> *T
+    {
+        let mut data: ~AtomicRcBoxData<T> = cast::transmute(self.data);
+        assert!(data.count > 0);
+        let r: *T = cast::transmute(data.data.get_mut_ref());
+        cast::forget(data);
+        return r;
+    }
+
+    #[inline(always)]
+    #[cfg(not(stage0))]
+    pub unsafe fn get_immut(&self) -> *T
+    {
+        let mut data: ~AtomicRcBoxData<T> = cast::transmute(self.data);
+        assert!(data.count > 0);
+        let r: *T = cast::transmute_immut(data.data.get_mut_ref());
+        cast::forget(data);
+        return r;
+    }
+}
+
+impl<T: Owned> Clone for UnsafeAtomicRcBox<T> {
+    fn clone(&self) -> UnsafeAtomicRcBox<T> {
+        unsafe {
+            let mut data: ~AtomicRcBoxData<T> = cast::transmute(self.data);
+            let new_count = intrinsics::atomic_xadd(&mut data.count, 1) + 1;
+            assert!(new_count >= 2);
+            cast::forget(data);
+            return UnsafeAtomicRcBox { data: self.data };
+        }
+    }
+}
+
+#[unsafe_destructor]
+impl<T> Drop for UnsafeAtomicRcBox<T>{
+    fn finalize(&self) {
+        unsafe {
+            do task::unkillable {
+                let mut data: ~AtomicRcBoxData<T> = cast::transmute(self.data);
+                let new_count = intrinsics::atomic_xsub(&mut data.count, 1) - 1;
+                assert!(new_count >= 0);
+                if new_count == 0 {
+                    // drop glue takes over.
+                } else {
+                    cast::forget(data);
+                }
+            }
+        }
+    }
+}
+
+
+/****************************************************************************/
+
+#[allow(non_camel_case_types)] // runtime type
+pub type rust_little_lock = *libc::c_void;
+
+struct LittleLock {
+    l: rust_little_lock,
+}
+
+impl Drop for LittleLock {
+    fn finalize(&self) {
+        unsafe {
+            rust_destroy_little_lock(self.l);
+        }
+    }
+}
+
+fn LittleLock() -> LittleLock {
+    unsafe {
+        LittleLock {
+            l: rust_create_little_lock()
+        }
+    }
+}
+
+pub impl LittleLock {
+    #[inline(always)]
+    unsafe fn lock<T>(&self, f: &fn() -> T) -> T {
+        do atomically {
+            rust_lock_little_lock(self.l);
+            do (|| {
+                f()
+            }).finally {
+                rust_unlock_little_lock(self.l);
+            }
+        }
+    }
+}
+
+struct ExData<T> {
+    lock: LittleLock,
+    failed: bool,
+    data: T,
+}
+
+/**
+ * An arc over mutable data that is protected by a lock. For library use only.
+ */
+pub struct Exclusive<T> {
+    x: UnsafeAtomicRcBox<ExData<T>>
+}
+
+pub fn exclusive<T:Owned>(user_data: T) -> Exclusive<T> {
+    let data = ExData {
+        lock: LittleLock(),
+        failed: false,
+        data: user_data
+    };
+    Exclusive {
+        x: UnsafeAtomicRcBox::new(data)
+    }
+}
+
+impl<T:Owned> Clone for Exclusive<T> {
+    // Duplicate an exclusive ARC, as std::arc::clone.
+    fn clone(&self) -> Exclusive<T> {
+        Exclusive { x: self.x.clone() }
+    }
+}
+
+pub impl<T:Owned> Exclusive<T> {
+    // Exactly like std::arc::mutex_arc,access(), but with the little_lock
+    // instead of a proper mutex. Same reason for being unsafe.
+    //
+    // Currently, scheduling operations (i.e., yielding, receiving on a pipe,
+    // accessing the provided condition variable) are prohibited while inside
+    // the exclusive. Supporting that is a work in progress.
+    #[inline(always)]
+    unsafe fn with<U>(&self, f: &fn(x: &mut T) -> U) -> U {
+        let rec = self.x.get();
+        do (*rec).lock.lock {
+            if (*rec).failed {
+                fail!(
+                    ~"Poisoned exclusive - another task failed inside!");
+            }
+            (*rec).failed = true;
+            let result = f(&mut (*rec).data);
+            (*rec).failed = false;
+            result
+        }
+    }
+
+    #[inline(always)]
+    unsafe fn with_imm<U>(&self, f: &fn(x: &T) -> U) -> U {
+        do self.with |x| {
+            f(cast::transmute_immut(x))
+        }
+    }
+}
+
+fn compare_and_swap(address: &mut int, oldval: int, newval: int) -> bool {
+    unsafe {
+        let old = intrinsics::atomic_cxchg(address, oldval, newval);
+        old == oldval
+    }
+}
+
+extern {
+    fn rust_create_little_lock() -> rust_little_lock;
+    fn rust_destroy_little_lock(lock: rust_little_lock);
+    fn rust_lock_little_lock(lock: rust_little_lock);
+    fn rust_unlock_little_lock(lock: rust_little_lock);
+}
+
+#[cfg(test)]
+mod tests {
+    use comm;
+    use super::exclusive;
+    use task;
+    use uint;
+
+    #[test]
+    fn exclusive_arc() {
+        let mut futures = ~[];
+
+        let num_tasks = 10;
+        let count = 10;
+
+        let total = exclusive(~0);
+
+        for uint::range(0, num_tasks) |_i| {
+            let total = total.clone();
+            let (port, chan) = comm::stream();
+            futures.push(port);
+
+            do task::spawn || {
+                for uint::range(0, count) |_i| {
+                    do total.with |count| {
+                        **count += 1;
+                    }
+                }
+                chan.send(());
+            }
+        };
+
+        for futures.each |f| { f.recv() }
+
+        do total.with |total| {
+            assert!(**total == num_tasks * count)
+        };
+    }
+
+    #[test] #[should_fail] #[ignore(cfg(windows))]
+    fn exclusive_poison() {
+        // Tests that if one task fails inside of an exclusive, subsequent
+        // accesses will also fail.
+        let x = exclusive(1);
+        let x2 = x.clone();
+        do task::try || {
+            do x2.with |one| {
+                assert!(*one == 2);
+            }
+        };
+        do x.with |one| {
+            assert!(*one == 1);
+        }
+    }
+}
diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs
index 604f0297b64..e56144ebc0a 100644
--- a/src/libcore/vec.rs
+++ b/src/libcore/vec.rs
@@ -3298,8 +3298,9 @@ mod tests {
     #[test]
     fn test_swap_remove_noncopyable() {
         // Tests that we don't accidentally run destructors twice.
-        let mut v = ~[::unstable::exclusive(()), ::unstable::exclusive(()),
-                      ::unstable::exclusive(())];
+        let mut v = ~[::unstable::sync::exclusive(()),
+                      ::unstable::sync::exclusive(()),
+                      ::unstable::sync::exclusive(())];
         let mut _e = v.swap_remove(0);
         assert!(v.len() == 2);
         _e = v.swap_remove(1);