diff options
| author | Tim Chevalier <chevalier@alum.wellesley.edu> | 2012-06-16 15:21:08 -0700 |
|---|---|---|
| committer | Tim Chevalier <chevalier@alum.wellesley.edu> | 2012-06-16 15:21:08 -0700 |
| commit | 0276a3376bd18b5acd2a5daaca6167bb1d9bc2d9 (patch) | |
| tree | 4f2378c00b4c41a981e63dd331d833330a88f28d /src/libstd | |
| parent | 69447e90021d7a35968ba32a8755a1be7e9d2a4c (diff) | |
| download | rust-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.rs | 163 | ||||
| -rw-r--r-- | src/libstd/std.rc | 3 |
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; |
