about summary refs log tree commit diff
path: root/src/libsync
diff options
context:
space:
mode:
Diffstat (limited to 'src/libsync')
-rw-r--r--src/libsync/arc.rs387
-rw-r--r--src/libsync/lib.rs5
-rw-r--r--src/libsync/lock.rs2
-rw-r--r--src/libsync/raw.rs2
4 files changed, 5 insertions, 391 deletions
diff --git a/src/libsync/arc.rs b/src/libsync/arc.rs
deleted file mode 100644
index 26d7e04fe1d..00000000000
--- a/src/libsync/arc.rs
+++ /dev/null
@@ -1,387 +0,0 @@
-// Copyright 2012-2014 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.
-
-/*!
- * Concurrency-enabled mechanisms for sharing mutable and/or immutable state
- * between tasks.
- */
-
-use std::mem;
-use std::ptr;
-use std::rt::heap::deallocate;
-use std::sync::atomics;
-use std::mem::{min_align_of, size_of};
-
-/// An atomically reference counted wrapper for shared state.
-///
-/// # Example
-///
-/// In this example, a large vector of floats is shared between several tasks.
-/// With simple pipes, without `Arc`, a copy would have to be made for each
-/// task.
-///
-/// ```rust
-/// use sync::Arc;
-///
-/// fn main() {
-///     let numbers = Vec::from_fn(100, |i| i as f32);
-///     let shared_numbers = Arc::new(numbers);
-///
-///     for _ in range(0, 10) {
-///         let child_numbers = shared_numbers.clone();
-///
-///         spawn(proc() {
-///             let local_numbers = child_numbers.as_slice();
-///
-///             // Work with the local numbers
-///         });
-///     }
-/// }
-/// ```
-#[unsafe_no_drop_flag]
-pub struct Arc<T> {
-    x: *mut ArcInner<T>,
-}
-
-/// A weak pointer to an `Arc`.
-///
-/// Weak pointers will not keep the data inside of the `Arc` alive, and can be
-/// used to break cycles between `Arc` pointers.
-#[unsafe_no_drop_flag]
-pub struct Weak<T> {
-    x: *mut ArcInner<T>,
-}
-
-struct ArcInner<T> {
-    strong: atomics::AtomicUint,
-    weak: atomics::AtomicUint,
-    data: T,
-}
-
-impl<T: Share + Send> Arc<T> {
-    /// Create an atomically reference counted wrapper.
-    #[inline]
-    pub fn new(data: T) -> Arc<T> {
-        // Start the weak pointer count as 1 which is the weak pointer that's
-        // held by all the strong pointers (kinda), see std/rc.rs for more info
-        let x = box ArcInner {
-            strong: atomics::AtomicUint::new(1),
-            weak: atomics::AtomicUint::new(1),
-            data: data,
-        };
-        Arc { x: unsafe { mem::transmute(x) } }
-    }
-
-    #[inline]
-    fn inner<'a>(&'a self) -> &'a ArcInner<T> {
-        // This unsafety is ok because while this arc is alive we're guaranteed
-        // that the inner pointer is valid. Furthermore, we know that the
-        // `ArcInner` structure itself is `Share` because the inner data is
-        // `Share` as well, so we're ok loaning out an immutable pointer to
-        // these contents.
-        unsafe { &*self.x }
-    }
-
-    /// Downgrades a strong pointer to a weak pointer
-    ///
-    /// Weak pointers will not keep the data alive. Once all strong references
-    /// to the underlying data have been dropped, the data itself will be
-    /// destroyed.
-    pub fn downgrade(&self) -> Weak<T> {
-        // See the clone() impl for why this is relaxed
-        self.inner().weak.fetch_add(1, atomics::Relaxed);
-        Weak { x: self.x }
-    }
-}
-
-impl<T: Share + Send> Clone for Arc<T> {
-    /// Duplicate an atomically reference counted wrapper.
-    ///
-    /// The resulting two `Arc` objects will point to the same underlying data
-    /// object. However, one of the `Arc` objects can be sent to another task,
-    /// allowing them to share the underlying data.
-    #[inline]
-    fn clone(&self) -> Arc<T> {
-        // Using a relaxed ordering is alright here, as knowledge of the
-        // original reference prevents other threads from erroneously deleting
-        // the object.
-        //
-        // As explained in the [Boost documentation][1], Increasing the
-        // reference counter can always be done with memory_order_relaxed: New
-        // references to an object can only be formed from an existing
-        // reference, and passing an existing reference from one thread to
-        // another must already provide any required synchronization.
-        //
-        // [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html)
-        self.inner().strong.fetch_add(1, atomics::Relaxed);
-        Arc { x: self.x }
-    }
-}
-
-impl<T: Send + Share> Deref<T> for Arc<T> {
-    #[inline]
-    fn deref<'a>(&'a self) -> &'a T {
-        &self.inner().data
-    }
-}
-
-impl<T: Send + Share + Clone> Arc<T> {
-    /// Acquires a mutable pointer to the inner contents by guaranteeing that
-    /// the reference count is one (no sharing is possible).
-    ///
-    /// This is also referred to as a copy-on-write operation because the inner
-    /// data is cloned if the reference count is greater than one.
-    #[inline]
-    #[experimental]
-    pub fn make_unique<'a>(&'a mut self) -> &'a mut T {
-        if self.inner().strong.load(atomics::SeqCst) != 1 {
-            *self = Arc::new(self.deref().clone())
-        }
-        // This unsafety is ok because we're guaranteed that the pointer
-        // returned is the *only* pointer that will ever be returned to T. Our
-        // reference count is guaranteed to be 1 at this point, and we required
-        // the Arc itself to be `mut`, so we're returning the only possible
-        // reference to the inner data.
-        unsafe { mem::transmute::<&_, &mut _>(self.deref()) }
-    }
-}
-
-#[unsafe_destructor]
-impl<T: Share + Send> Drop for Arc<T> {
-    fn drop(&mut self) {
-        // This structure has #[unsafe_no_drop_flag], so this drop glue may run
-        // more than once (but it is guaranteed to be zeroed after the first if
-        // it's run more than once)
-        if self.x.is_null() { return }
-
-        // Because `fetch_sub` is already atomic, we do not need to synchronize
-        // with other threads unless we are going to delete the object. This
-        // same logic applies to the below `fetch_sub` to the `weak` count.
-        if self.inner().strong.fetch_sub(1, atomics::Release) != 1 { return }
-
-        // This fence is needed to prevent reordering of use of the data and
-        // deletion of the data. Because it is marked `Release`, the
-        // decreasing of the reference count sychronizes with this `Acquire`
-        // fence. This means that use of the data happens before decreasing
-        // the refernce count, which happens before this fence, which
-        // happens before the deletion of the data.
-        //
-        // As explained in the [Boost documentation][1],
-        //
-        // It is important to enforce any possible access to the object in
-        // one thread (through an existing reference) to *happen before*
-        // deleting the object in a different thread. This is achieved by a
-        // "release" operation after dropping a reference (any access to the
-        // object through this reference must obviously happened before),
-        // and an "acquire" operation before deleting the object.
-        //
-        // [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html)
-        atomics::fence(atomics::Acquire);
-
-        // Destroy the data at this time, even though we may not free the box
-        // allocation itself (there may still be weak pointers lying around).
-        unsafe { drop(ptr::read(&self.inner().data)); }
-
-        if self.inner().weak.fetch_sub(1, atomics::Release) == 1 {
-            atomics::fence(atomics::Acquire);
-            unsafe { deallocate(self.x as *mut u8, size_of::<ArcInner<T>>(),
-                                min_align_of::<ArcInner<T>>()) }
-        }
-    }
-}
-
-impl<T: Share + Send> Weak<T> {
-    /// Attempts to upgrade this weak reference to a strong reference.
-    ///
-    /// This method will fail to upgrade this reference if the strong reference
-    /// count has already reached 0, but if there are still other active strong
-    /// references this function will return a new strong reference to the data
-    pub fn upgrade(&self) -> Option<Arc<T>> {
-        // We use a CAS loop to increment the strong count instead of a
-        // fetch_add because once the count hits 0 is must never be above 0.
-        let inner = self.inner();
-        loop {
-            let n = inner.strong.load(atomics::SeqCst);
-            if n == 0 { return None }
-            let old = inner.strong.compare_and_swap(n, n + 1, atomics::SeqCst);
-            if old == n { return Some(Arc { x: self.x }) }
-        }
-    }
-
-    #[inline]
-    fn inner<'a>(&'a self) -> &'a ArcInner<T> {
-        // See comments above for why this is "safe"
-        unsafe { &*self.x }
-    }
-}
-
-impl<T: Share + Send> Clone for Weak<T> {
-    #[inline]
-    fn clone(&self) -> Weak<T> {
-        // See comments in Arc::clone() for why this is relaxed
-        self.inner().weak.fetch_add(1, atomics::Relaxed);
-        Weak { x: self.x }
-    }
-}
-
-#[unsafe_destructor]
-impl<T: Share + Send> Drop for Weak<T> {
-    fn drop(&mut self) {
-        // see comments above for why this check is here
-        if self.x.is_null() { return }
-
-        // If we find out that we were the last weak pointer, then its time to
-        // deallocate the data entirely. See the discussion in Arc::drop() about
-        // the memory orderings
-        if self.inner().weak.fetch_sub(1, atomics::Release) == 1 {
-            atomics::fence(atomics::Acquire);
-            unsafe { deallocate(self.x as *mut u8, size_of::<ArcInner<T>>(),
-                                min_align_of::<ArcInner<T>>()) }
-        }
-    }
-}
-
-#[cfg(test)]
-#[allow(experimental)]
-mod tests {
-    use super::{Arc, Weak};
-    use std::sync::atomics;
-    use std::task;
-    use Mutex;
-
-    struct Canary(*mut atomics::AtomicUint);
-
-    impl Drop for Canary
-    {
-        fn drop(&mut self) {
-            unsafe {
-                match *self {
-                    Canary(c) => {
-                        (*c).fetch_add(1, atomics::SeqCst);
-                    }
-                }
-            }
-        }
-    }
-
-    #[test]
-    fn manually_share_arc() {
-        let v = vec!(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
-        let arc_v = Arc::new(v);
-
-        let (tx, rx) = channel();
-
-        task::spawn(proc() {
-            let arc_v: Arc<Vec<int>> = rx.recv();
-            assert_eq!(*arc_v.get(3), 4);
-        });
-
-        tx.send(arc_v.clone());
-
-        assert_eq!(*arc_v.get(2), 3);
-        assert_eq!(*arc_v.get(4), 5);
-
-        info!("{:?}", arc_v);
-    }
-
-    #[test]
-    fn test_cowarc_clone_make_unique() {
-        let mut cow0 = Arc::new(75u);
-        let mut cow1 = cow0.clone();
-        let mut cow2 = cow1.clone();
-
-        assert!(75 == *cow0.make_unique());
-        assert!(75 == *cow1.make_unique());
-        assert!(75 == *cow2.make_unique());
-
-        *cow0.make_unique() += 1;
-        *cow1.make_unique() += 2;
-        *cow2.make_unique() += 3;
-
-        assert!(76 == *cow0);
-        assert!(77 == *cow1);
-        assert!(78 == *cow2);
-
-        // none should point to the same backing memory
-        assert!(*cow0 != *cow1);
-        assert!(*cow0 != *cow2);
-        assert!(*cow1 != *cow2);
-    }
-
-    #[test]
-    fn test_cowarc_clone_unique2() {
-        let mut cow0 = Arc::new(75u);
-        let cow1 = cow0.clone();
-        let cow2 = cow1.clone();
-
-        assert!(75 == *cow0);
-        assert!(75 == *cow1);
-        assert!(75 == *cow2);
-
-        *cow0.make_unique() += 1;
-
-        assert!(76 == *cow0);
-        assert!(75 == *cow1);
-        assert!(75 == *cow2);
-
-        // cow1 and cow2 should share the same contents
-        // cow0 should have a unique reference
-        assert!(*cow0 != *cow1);
-        assert!(*cow0 != *cow2);
-        assert!(*cow1 == *cow2);
-    }
-
-    #[test]
-    fn test_live() {
-        let x = Arc::new(5);
-        let y = x.downgrade();
-        assert!(y.upgrade().is_some());
-    }
-
-    #[test]
-    fn test_dead() {
-        let x = Arc::new(5);
-        let y = x.downgrade();
-        drop(x);
-        assert!(y.upgrade().is_none());
-    }
-
-    #[test]
-    fn weak_self_cyclic() {
-        struct Cycle {
-            x: Mutex<Option<Weak<Cycle>>>
-        }
-
-        let a = Arc::new(Cycle { x: Mutex::new(None) });
-        let b = a.clone().downgrade();
-        *a.deref().x.lock().deref_mut() = Some(b);
-
-        // hopefully we don't double-free (or leak)...
-    }
-
-    #[test]
-    fn drop_arc() {
-        let mut canary = atomics::AtomicUint::new(0);
-        let x = Arc::new(Canary(&mut canary as *mut atomics::AtomicUint));
-        drop(x);
-        assert!(canary.load(atomics::Acquire) == 1);
-    }
-
-    #[test]
-    fn drop_arc_weak() {
-        let mut canary = atomics::AtomicUint::new(0);
-        let arc = Arc::new(Canary(&mut canary as *mut atomics::AtomicUint));
-        let arc_weak = arc.downgrade();
-        assert!(canary.load(atomics::Acquire) == 0);
-        drop(arc);
-        assert!(canary.load(atomics::Acquire) == 1);
-        drop(arc_weak);
-    }
-}
diff --git a/src/libsync/lib.rs b/src/libsync/lib.rs
index e5d506301e3..3396425928e 100644
--- a/src/libsync/lib.rs
+++ b/src/libsync/lib.rs
@@ -27,17 +27,18 @@
 #[cfg(test)]
 #[phase(syntax, link)] extern crate log;
 
+extern crate alloc;
+
 pub use comm::{DuplexStream, duplex};
 pub use task_pool::TaskPool;
 pub use future::Future;
-pub use arc::{Arc, Weak};
+pub use alloc::arc::{Arc, Weak};
 pub use lock::{Mutex, MutexGuard, Condvar, Barrier,
                RWLock, RWLockReadGuard, RWLockWriteGuard};
 
 // The mutex/rwlock in this module are not meant for reexport
 pub use raw::{Semaphore, SemaphoreGuard};
 
-mod arc;
 mod comm;
 mod future;
 mod lock;
diff --git a/src/libsync/lock.rs b/src/libsync/lock.rs
index 930b3009042..9f59f587770 100644
--- a/src/libsync/lock.rs
+++ b/src/libsync/lock.rs
@@ -447,7 +447,7 @@ mod tests {
     use std::task;
     use std::task::TaskBuilder;
 
-    use arc::Arc;
+    use Arc;
     use super::{Mutex, Barrier, RWLock};
 
     #[test]
diff --git a/src/libsync/raw.rs b/src/libsync/raw.rs
index 990aba3ebff..591318d24b2 100644
--- a/src/libsync/raw.rs
+++ b/src/libsync/raw.rs
@@ -622,7 +622,7 @@ impl<'a> Drop for RWLockReadGuard<'a> {
 
 #[cfg(test)]
 mod tests {
-    use arc::Arc;
+    use Arc;
     use super::{Semaphore, Mutex, RWLock, Condvar};
 
     use std::mem;