]> git.lizzy.rs Git - rust.git/blob - src/libstd/sync/arc.rs
Test fixes and rebase problems
[rust.git] / src / libstd / sync / arc.rs
1 // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! Atomically reference counted data
12 //!
13 //! This modules contains the implementation of an atomically reference counted
14 //! pointer for the purpose of sharing data between tasks. This is obviously a
15 //! very unsafe primitive to use, but it has its use cases when implementing
16 //! concurrent data structures and similar tasks.
17 //!
18 //! Great care must be taken to ensure that data races do not arise through the
19 //! usage of `UnsafeArc`, and this often requires some form of external
20 //! synchronization. The only guarantee provided to you by this class is that
21 //! the underlying data will remain valid (not free'd) so long as the reference
22 //! count is greater than one.
23
24 use cast;
25 use clone::Clone;
26 use kinds::Send;
27 use ops::Drop;
28 use ptr::RawPtr;
29 use sync::atomics::{AtomicUint, SeqCst, Relaxed, Acquire};
30 use vec;
31
32 /// An atomically reference counted pointer.
33 ///
34 /// Enforces no shared-memory safety.
35 //#[unsafe_no_drop_flag] FIXME: #9758
36 pub struct UnsafeArc<T> {
37     priv data: *mut ArcData<T>,
38 }
39
40 struct ArcData<T> {
41     count: AtomicUint,
42     data: T,
43 }
44
45 unsafe fn new_inner<T: Send>(data: T, refcount: uint) -> *mut ArcData<T> {
46     let data = ~ArcData { count: AtomicUint::new(refcount), data: data };
47     cast::transmute(data)
48 }
49
50 impl<T: Send> UnsafeArc<T> {
51     /// Creates a new `UnsafeArc` which wraps the given data.
52     pub fn new(data: T) -> UnsafeArc<T> {
53         unsafe { UnsafeArc { data: new_inner(data, 1) } }
54     }
55
56     /// As new(), but returns an extra pre-cloned handle.
57     pub fn new2(data: T) -> (UnsafeArc<T>, UnsafeArc<T>) {
58         unsafe {
59             let ptr = new_inner(data, 2);
60             (UnsafeArc { data: ptr }, UnsafeArc { data: ptr })
61         }
62     }
63
64     /// As new(), but returns a vector of as many pre-cloned handles as
65     /// requested.
66     pub fn newN(data: T, num_handles: uint) -> ~[UnsafeArc<T>] {
67         unsafe {
68             if num_handles == 0 {
69                 ~[] // need to free data here
70             } else {
71                 let ptr = new_inner(data, num_handles);
72                 vec::from_fn(num_handles, |_| UnsafeArc { data: ptr })
73             }
74         }
75     }
76
77     /// Gets a pointer to the inner shared data. Note that care must be taken to
78     /// ensure that the outer `UnsafeArc` does not fall out of scope while this
79     /// pointer is in use, otherwise it could possibly contain a use-after-free.
80     #[inline]
81     pub fn get(&self) -> *mut T {
82         unsafe {
83             assert!((*self.data).count.load(Relaxed) > 0);
84             return &mut (*self.data).data as *mut T;
85         }
86     }
87
88     /// Gets an immutable pointer to the inner shared data. This has the same
89     /// caveats as the `get` method.
90     #[inline]
91     pub fn get_immut(&self) -> *T {
92         unsafe {
93             assert!((*self.data).count.load(Relaxed) > 0);
94             return &(*self.data).data as *T;
95         }
96     }
97 }
98
99 impl<T: Send> Clone for UnsafeArc<T> {
100     fn clone(&self) -> UnsafeArc<T> {
101         unsafe {
102             // This barrier might be unnecessary, but I'm not sure...
103             let old_count = (*self.data).count.fetch_add(1, Acquire);
104             assert!(old_count >= 1);
105             return UnsafeArc { data: self.data };
106         }
107     }
108 }
109
110 #[unsafe_destructor]
111 impl<T> Drop for UnsafeArc<T>{
112     fn drop(&mut self) {
113         unsafe {
114             // Happens when destructing an unwrapper's handle and from
115             // `#[unsafe_no_drop_flag]`
116             if self.data.is_null() {
117                 return
118             }
119             // Must be acquire+release, not just release, to make sure this
120             // doesn't get reordered to after the unwrapper pointer load.
121             let old_count = (*self.data).count.fetch_sub(1, SeqCst);
122             assert!(old_count >= 1);
123             if old_count == 1 {
124                 let _: ~ArcData<T> = cast::transmute(self.data);
125             }
126         }
127     }
128 }
129
130 #[cfg(test)]
131 mod tests {
132     use prelude::*;
133     use super::UnsafeArc;
134     use mem::size_of;
135
136     #[test]
137     fn test_size() {
138         assert_eq!(size_of::<UnsafeArc<[int, ..10]>>(), size_of::<*[int, ..10]>());
139     }
140
141     #[test]
142     fn arclike_newN() {
143         // Tests that the many-refcounts-at-once constructors don't leak.
144         let _ = UnsafeArc::new2(~~"hello");
145         let x = UnsafeArc::newN(~~"hello", 0);
146         assert_eq!(x.len(), 0)
147         let x = UnsafeArc::newN(~~"hello", 1);
148         assert_eq!(x.len(), 1)
149         let x = UnsafeArc::newN(~~"hello", 10);
150         assert_eq!(x.len(), 10)
151     }
152 }