A shareable atomically reference counted pointer wrapper.
Needs more tests to ensure safety, and probably some more work on usability too.
This commit is contained in:
parent
9773a22119
commit
6fa1a084f7
5 changed files with 101 additions and 1 deletions
59
src/libstd/arc.rs
Normal file
59
src/libstd/arc.rs
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
#[doc = "An atomically reference counted wrapper that can be used
|
||||||
|
hare immutable data between tasks."]
|
||||||
|
|
||||||
|
export arc, get, clone;
|
||||||
|
|
||||||
|
#[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> = {
|
||||||
|
mut count: libc::intptr_t,
|
||||||
|
data: T
|
||||||
|
};
|
||||||
|
|
||||||
|
resource arc_destruct<T>(data: *arc_data<T>) {
|
||||||
|
unsafe {
|
||||||
|
let ptr = ptr::mut_addr_of((*data).count);
|
||||||
|
|
||||||
|
let new_count = rustrt::rust_atomic_decrement(ptr);
|
||||||
|
assert new_count >= 0;
|
||||||
|
if new_count == 0 {
|
||||||
|
let _ptr : ~arc_data<T> = unsafe::reinterpret_cast(data);
|
||||||
|
// drop glue takes over.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type arc<T> = arc_destruct<T>;
|
||||||
|
|
||||||
|
fn arc<T>(-data: T) -> arc<T> {
|
||||||
|
let data = ~{mut count: 1, data: data};
|
||||||
|
unsafe {
|
||||||
|
let ptr = unsafe::reinterpret_cast(data);
|
||||||
|
unsafe::forget(data);
|
||||||
|
arc_destruct(ptr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get<T>(rc: &a.arc<T>) -> &a.T {
|
||||||
|
unsafe {
|
||||||
|
&(***rc).data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clone<T>(rc: &arc<T>) -> arc<T> {
|
||||||
|
let data = **rc;
|
||||||
|
unsafe {
|
||||||
|
rustrt::rust_atomic_increment(
|
||||||
|
ptr::mut_addr_of((*data).count));
|
||||||
|
}
|
||||||
|
arc_destruct(**rc)
|
||||||
|
}
|
|
@ -17,7 +17,7 @@ export net, net_tcp;
|
||||||
export uv, uv_ll, uv_hl, uv_global_loop;
|
export uv, uv_ll, uv_hl, uv_global_loop;
|
||||||
export c_vec, util, timer;
|
export c_vec, util, timer;
|
||||||
export bitv, deque, fun_treemap, list, map, smallintmap, sort, treemap;
|
export bitv, deque, fun_treemap, list, map, smallintmap, sort, treemap;
|
||||||
export rope, arena;
|
export rope, arena, arc;
|
||||||
export ebml, dbg, getopts, json, rand, sha1, term, time, prettyprint;
|
export ebml, dbg, getopts, json, rand, sha1, term, time, prettyprint;
|
||||||
export test, tempfile, serialization;
|
export test, tempfile, serialization;
|
||||||
|
|
||||||
|
@ -66,6 +66,7 @@ mod term;
|
||||||
mod time;
|
mod time;
|
||||||
mod prettyprint;
|
mod prettyprint;
|
||||||
mod arena;
|
mod arena;
|
||||||
|
mod arc;
|
||||||
|
|
||||||
#[cfg(unicode)]
|
#[cfg(unicode)]
|
||||||
mod unicode;
|
mod unicode;
|
||||||
|
|
|
@ -816,6 +816,16 @@ rust_compare_and_swap_ptr(intptr_t *address,
|
||||||
return sync::compare_and_swap(address, oldval, newval);
|
return sync::compare_and_swap(address, oldval, newval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" CDECL intptr_t
|
||||||
|
rust_atomic_increment(intptr_t *address) {
|
||||||
|
return sync::increment(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" CDECL intptr_t
|
||||||
|
rust_atomic_decrement(intptr_t *address) {
|
||||||
|
return sync::decrement(address);
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" CDECL void
|
extern "C" CDECL void
|
||||||
rust_task_weaken(rust_port_id chan) {
|
rust_task_weaken(rust_port_id chan) {
|
||||||
rust_task *task = rust_get_current_task();
|
rust_task *task = rust_get_current_task();
|
||||||
|
|
|
@ -154,6 +154,8 @@ rust_dbg_lock_signal
|
||||||
rust_dbg_call
|
rust_dbg_call
|
||||||
rust_osmain_sched_id
|
rust_osmain_sched_id
|
||||||
rust_compare_and_swap_ptr
|
rust_compare_and_swap_ptr
|
||||||
|
rust_atomic_increment
|
||||||
|
rust_atomic_decrement
|
||||||
rust_global_env_chan_ptr
|
rust_global_env_chan_ptr
|
||||||
rust_port_take
|
rust_port_take
|
||||||
rust_port_drop
|
rust_port_drop
|
||||||
|
|
28
src/test/run-pass/share-arc.rs
Normal file
28
src/test/run-pass/share-arc.rs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
use std;
|
||||||
|
import std::arc;
|
||||||
|
import comm::*;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
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);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue