about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorTim Chevalier <chevalier@alum.wellesley.edu>2012-06-16 15:21:08 -0700
committerTim Chevalier <chevalier@alum.wellesley.edu>2012-06-16 15:21:08 -0700
commit0276a3376bd18b5acd2a5daaca6167bb1d9bc2d9 (patch)
tree4f2378c00b4c41a981e63dd331d833330a88f28d /src/libstd
parent69447e90021d7a35968ba32a8755a1be7e9d2a4c (diff)
downloadrust-0276a3376bd18b5acd2a5daaca6167bb1d9bc2d9.tar.gz
rust-0276a3376bd18b5acd2a5daaca6167bb1d9bc2d9.zip
Revert "Moved arc to libstd and added an arc that allows shared mutable state through mutual exclusion."
This reverts commit 015527b0cee0bc5cfaac8dd610035a0c1b2f8ea6.
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/arc.rs163
-rw-r--r--src/libstd/std.rc3
2 files changed, 165 insertions, 1 deletions
diff --git a/src/libstd/arc.rs b/src/libstd/arc.rs
new file mode 100644
index 00000000000..5200b0fe7a7
--- /dev/null
+++ b/src/libstd/arc.rs
@@ -0,0 +1,163 @@
+#[doc = "An atomically reference counted wrapper that can be used to
+share immutable data between tasks."]
+
+import comm::{port, chan, methods};
+
+export arc, get, clone, shared_arc, get_arc;
+
+#[abi = "cdecl"]
+native mod rustrt {
+    #[rust_stack]
+    fn rust_atomic_increment(p: &mut libc::intptr_t)
+        -> libc::intptr_t;
+
+    #[rust_stack]
+    fn rust_atomic_decrement(p: &mut libc::intptr_t)
+        -> libc::intptr_t;
+}
+
+type arc_data<T: const> = {
+    mut count: libc::intptr_t,
+    data: T
+};
+
+resource arc_destruct<T: const>(data: *libc::c_void) {
+    unsafe {
+        let data: ~arc_data<T> = unsafe::reinterpret_cast(data);
+        let new_count = rustrt::rust_atomic_decrement(&mut data.count);
+        assert new_count >= 0;
+        if new_count == 0 {
+            // drop glue takes over.
+        } else {
+            unsafe::forget(data);
+        }
+    }
+}
+
+type arc<T: const> = arc_destruct<T>;
+
+#[doc="Create an atomically reference counted wrapper."]
+fn arc<T: const>(-data: T) -> arc<T> {
+    let data = ~{mut count: 1, data: data};
+    unsafe {
+        let ptr = unsafe::transmute(data);
+        arc_destruct(ptr)
+    }
+}
+
+#[doc="Access the underlying data in an atomically reference counted
+ wrapper."]
+fn get<T: const>(rc: &a.arc<T>) -> &a.T {
+    unsafe {
+        let ptr: ~arc_data<T> = unsafe::reinterpret_cast(**rc);
+        // Cast us back into the correct region
+        let r = unsafe::reinterpret_cast(&ptr.data);
+        unsafe::forget(ptr);
+        ret r;
+    }
+}
+
+#[doc="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."]
+fn clone<T: const>(rc: &arc<T>) -> arc<T> {
+    unsafe {
+        let ptr: ~arc_data<T> = unsafe::reinterpret_cast(**rc);
+        rustrt::rust_atomic_increment(&mut ptr.count);
+        unsafe::forget(ptr);
+    }
+    arc_destruct(**rc)
+}
+
+// Convenience code for sharing arcs between tasks
+
+type get_chan<T: const send> = chan<chan<arc<T>>>;
+
+// (terminate, get)
+type shared_arc<T: const send> = (shared_arc_res, get_chan<T>);
+
+resource shared_arc_res(c: comm::chan<()>) {
+    c.send(());
+}
+
+fn shared_arc<T: send const>(-data: T) -> shared_arc<T> {
+    let a = arc::arc(data);
+    let p = port();
+    let c = chan(p);
+    task::spawn() {|move a|
+        let mut live = true;
+        let terminate = port();
+        let get = port();
+
+        c.send((chan(terminate), chan(get)));
+
+        while live {
+            alt comm::select2(terminate, get) {
+              either::left(()) { live = false; }
+              either::right(cc) {
+                comm::send(cc, arc::clone(&a));
+              }
+            }
+        }
+    };
+    let (terminate, get) = p.recv();
+    (shared_arc_res(terminate), get)
+}
+
+fn get_arc<T: send const>(c: get_chan<T>) -> arc::arc<T> {
+    let p = port();
+    c.send(chan(p));
+    p.recv()
+}
+
+#[cfg(test)]
+mod tests {
+    import comm::*;
+
+    #[test]
+    fn manually_share_arc() {
+        let v = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+        let arc_v = arc::arc(v);
+
+        let p = port();
+        let c = chan(p);
+
+        task::spawn() {||
+            let p = port();
+            c.send(chan(p));
+
+            let arc_v = p.recv();
+
+            let v = *arc::get::<[int]>(&arc_v);
+            assert v[3] == 4;
+        };
+
+        let c = p.recv();
+        c.send(arc::clone(&arc_v));
+
+        assert (*arc::get(&arc_v))[2] == 3;
+
+        log(info, arc_v);
+    }
+
+    #[test]
+    fn auto_share_arc() {
+        let v = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+        let (_res, arc_c) = shared_arc(v);
+
+        let p = port();
+        let c = chan(p);
+
+        task::spawn() {||
+            let arc_v = get_arc(arc_c);
+            let v = *get(&arc_v);
+            assert v[2] == 3;
+
+            c.send(());
+        };
+
+        assert p.recv() == ();
+    }
+}
diff --git a/src/libstd/std.rc b/src/libstd/std.rc
index 2effb04cd3f..10b008d07c8 100644
--- a/src/libstd/std.rc
+++ b/src/libstd/std.rc
@@ -19,7 +19,7 @@ export net, net_tcp;
 export uv, uv_ll, uv_iotask, uv_global_loop;
 export c_vec, util, timer;
 export bitv, deque, fun_treemap, list, map, smallintmap, sort, treemap;
-export rope, arena, par;
+export rope, arena, arc, par;
 export ebml, dbg, getopts, json, rand, sha1, term, time, prettyprint;
 export test, tempfile, serialization;
 export cmp;
@@ -69,6 +69,7 @@ mod term;
 mod time;
 mod prettyprint;
 mod arena;
+mod arc;
 mod par;
 mod cmp;