From be664ddd2917e13c1c5f05a49476f8b67be85140 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Wed, 6 Jun 2012 17:58:15 -0700 Subject: [PATCH] Moved arc to libcore and added an arc that allows shared mutable state through mutual exclusion. --- src/{libstd => libcore}/arc.rs | 72 +++++++++++++++++++++- src/libcore/core.rc | 3 +- src/libcore/sys.rs | 4 +- src/libstd/std.rc | 3 +- src/test/bench/graph500-bfs.rs | 1 - src/test/compile-fail/no-capture-arc.rs | 2 - src/test/compile-fail/no-reuse-move-arc.rs | 2 - src/test/run-fail/issue-2444.rs | 3 - 8 files changed, 74 insertions(+), 16 deletions(-) rename src/{libstd => libcore}/arc.rs (66%) diff --git a/src/libstd/arc.rs b/src/libcore/arc.rs similarity index 66% rename from src/libstd/arc.rs rename to src/libcore/arc.rs index 5200b0fe7a79..312606be906a 100644 --- a/src/libstd/arc.rs +++ b/src/libcore/arc.rs @@ -2,9 +2,12 @@ share immutable data between tasks."] import comm::{port, chan, methods}; +import sys::methods; export arc, get, clone, shared_arc, get_arc; +export exclusive, methods; + #[abi = "cdecl"] native mod rustrt { #[rust_stack] @@ -16,12 +19,12 @@ native mod rustrt { -> libc::intptr_t; } -type arc_data = { +type arc_data = { mut count: libc::intptr_t, data: T }; -resource arc_destruct(data: *libc::c_void) { +resource arc_destruct(data: *libc::c_void) { unsafe { let data: ~arc_data = unsafe::reinterpret_cast(data); let new_count = rustrt::rust_atomic_decrement(&mut data.count); @@ -71,6 +74,43 @@ fn clone(rc: &arc) -> arc { arc_destruct(**rc) } +// An arc over mutable data that is protected by a lock. +type ex_data = {lock: sys::lock_and_signal, data: T}; +type exclusive = arc_destruct>; + +fn exclusive(-data: T) -> exclusive { + let data = ~{mut count: 1, data: {lock: sys::create_lock(), + data: data}}; + unsafe { + let ptr = unsafe::reinterpret_cast(data); + unsafe::forget(data); + arc_destruct(ptr) + } +} + +impl methods for exclusive { + fn clone() -> exclusive { + unsafe { + // this makes me nervous... + let ptr: ~arc_data> = unsafe::reinterpret_cast(*self); + rustrt::rust_atomic_increment(&mut ptr.count); + unsafe::forget(ptr); + } + arc_destruct(*self) + } + + fn with(f: fn(sys::condition, x: &T) -> U) -> U { + unsafe { + let ptr: ~arc_data> = unsafe::reinterpret_cast(*self); + let rec: &ex_data = &(*ptr).data; + unsafe::forget(ptr); + rec.lock.lock_cond() {|c| + f(c, &rec.data) + } + } + } +} + // Convenience code for sharing arcs between tasks type get_chan = chan>>; @@ -115,6 +155,7 @@ fn get_arc(c: get_chan) -> arc::arc { #[cfg(test)] mod tests { import comm::*; + import future::future; #[test] fn manually_share_arc() { @@ -160,4 +201,31 @@ mod tests { assert p.recv() == (); } + + #[test] + fn exclusive_arc() { + let mut futures = []; + + let num_tasks = 10u; + let count = 1000u; + + let total = exclusive(~mut 0u); + + for uint::range(0u, num_tasks) {|_i| + let total = total.clone(); + futures += [future::spawn({|| + for uint::range(0u, count) {|_i| + total.with {|_cond, count| + **count += 1u; + } + } + })]; + }; + + for futures.each {|f| f.get() }; + + total.with {|_cond, total| + assert **total == num_tasks * count + }; + } } diff --git a/src/libcore/core.rc b/src/libcore/core.rc index f1ceeff9ea80..913832a7f07a 100644 --- a/src/libcore/core.rc +++ b/src/libcore/core.rc @@ -39,7 +39,7 @@ export float, f32, f64; export box, char, str, ptr, vec, bool; export either, option, result, iter; export libc, os, io, run, rand, sys, unsafe, logging; -export comm, task, future; +export arc, comm, task, future; export extfmt; export tuple; export to_str; @@ -175,6 +175,7 @@ mod dvec_iter { } // Concurrency +mod arc; mod comm; mod task; mod future; diff --git a/src/libcore/sys.rs b/src/libcore/sys.rs index 90ea10601ae7..af93009874f0 100644 --- a/src/libcore/sys.rs +++ b/src/libcore/sys.rs @@ -7,7 +7,7 @@ export min_align_of; export pref_align_of; export refcount; export log_str; -export lock_and_signal, condition, methods; +export create_lock, lock_and_signal, condition, methods; enum type_desc = { first_param: **libc::c_int, @@ -126,8 +126,6 @@ impl methods for condition { #[cfg(test)] mod tests { - use std; - import std::arc; #[test] fn size_of_basic() { diff --git a/src/libstd/std.rc b/src/libstd/std.rc index 10b008d07c87..2effb04cd3f7 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, arc, par; +export rope, arena, par; export ebml, dbg, getopts, json, rand, sha1, term, time, prettyprint; export test, tempfile, serialization; export cmp; @@ -69,7 +69,6 @@ mod term; mod time; mod prettyprint; mod arena; -mod arc; mod par; mod cmp; diff --git a/src/test/bench/graph500-bfs.rs b/src/test/bench/graph500-bfs.rs index 85c77b04c5f3..e51cb6c98b23 100644 --- a/src/test/bench/graph500-bfs.rs +++ b/src/test/bench/graph500-bfs.rs @@ -10,7 +10,6 @@ import std::map; import std::map::hashmap; import std::deque; import std::deque::t; -import std::arc; import std::par; import io::writer_util; import comm::*; diff --git a/src/test/compile-fail/no-capture-arc.rs b/src/test/compile-fail/no-capture-arc.rs index 6cacd7cd679e..6c8c80dab0a2 100644 --- a/src/test/compile-fail/no-capture-arc.rs +++ b/src/test/compile-fail/no-capture-arc.rs @@ -1,7 +1,5 @@ // error-pattern: copying a noncopyable value -use std; -import std::arc; import comm::*; fn main() { diff --git a/src/test/compile-fail/no-reuse-move-arc.rs b/src/test/compile-fail/no-reuse-move-arc.rs index 34adff6f0ae0..fa88111d2744 100644 --- a/src/test/compile-fail/no-reuse-move-arc.rs +++ b/src/test/compile-fail/no-reuse-move-arc.rs @@ -1,5 +1,3 @@ -use std; -import std::arc; import comm::*; fn main() { diff --git a/src/test/run-fail/issue-2444.rs b/src/test/run-fail/issue-2444.rs index 1dd1123e7e7d..5101de2c46ca 100644 --- a/src/test/run-fail/issue-2444.rs +++ b/src/test/run-fail/issue-2444.rs @@ -1,8 +1,5 @@ // error-pattern:explicit failure -use std; -import std::arc; - enum e { e(arc::arc) } fn foo() -> e {fail;}