Skip to content

Commit 472ca3d

Browse files
committed
---
yaml --- r: 28617 b: refs/heads/try c: f996b3a h: refs/heads/master i: 28615: e6e1c0f v: v3
1 parent 82c6b8a commit 472ca3d

File tree

5 files changed

+170
-164
lines changed

5 files changed

+170
-164
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
refs/heads/master: cd6f24f9d14ac90d167386a56e7a6ac1f0318195
33
refs/heads/snap-stage1: e33de59e47c5076a89eadeb38f4934f58a3618a6
44
refs/heads/snap-stage3: cd6f24f9d14ac90d167386a56e7a6ac1f0318195
5-
refs/heads/try: 1397dca2dd07b93789226a22b2ccc456d0a5317a
5+
refs/heads/try: f996b3ae8169d699362622e4530d014659628108
66
refs/tags/release-0.1: 1f5c5126e96c79d22cb7862f75304136e204f105
77
refs/heads/ndm: f3868061cd7988080c30d6d5bf352a5a5fe2460b
88
refs/heads/try2: d0c6ce338884ee21843f4b40bf6bf18d222ce5df

branches/try/src/libcore/core.rc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ mod send_map;
221221
mod comm;
222222
mod task {
223223
mod local_data;
224+
mod local_data_priv;
224225
}
225226
mod future;
226227
mod pipes;

branches/try/src/libcore/task.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
use cmp::Eq;
3131
use result::Result;
3232
use pipes::{stream, Chan, Port};
33+
use local_data_priv::{local_get, local_set};
3334

3435
export Task;
3536
export TaskResult;
@@ -1209,7 +1210,7 @@ fn gen_child_taskgroup(linked: bool, supervised: bool)
12091210
/*######################################################################*
12101211
* Step 1. Get spawner's taskgroup info.
12111212
*######################################################################*/
1212-
let spawner_group = match unsafe { local_data::local_get(spawner,
1213+
let spawner_group = match unsafe { local_get(spawner,
12131214
taskgroup_key!()) } {
12141215
None => {
12151216
// Main task, doing first spawn ever. Lazily initialise here.
@@ -1222,7 +1223,7 @@ fn gen_child_taskgroup(linked: bool, supervised: bool)
12221223
let group =
12231224
@TCB(spawner, move tasks, AncestorList(None), true, None);
12241225
unsafe {
1225-
local_data::local_set(spawner, taskgroup_key!(), group);
1226+
local_set(spawner, taskgroup_key!(), group);
12261227
}
12271228
group
12281229
}
@@ -1351,7 +1352,7 @@ fn spawn_raw(+opts: TaskOpts, +f: fn~()) {
13511352
let group = @TCB(child, move child_arc, move ancestors,
13521353
is_main, move notifier);
13531354
unsafe {
1354-
local_data::local_set(child, taskgroup_key!(), group);
1355+
local_set(child, taskgroup_key!(), group);
13551356
}
13561357

13571358
// Run the child's body.

branches/try/src/libcore/task/local_data.rs

Lines changed: 7 additions & 160 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,18 @@ Casting 'Arcane Sight' reveals an overwhelming aura of Transmutation magic.
1414
1515
*/
1616

17-
export local_data_key;
17+
export LocalDataKey;
1818
export local_data_pop;
1919
export local_data_get;
2020
export local_data_set;
2121
export local_data_modify;
2222

23-
// XXX: These shouldn't be exported but they are used by task.rs
24-
export local_get;
25-
export local_set;
23+
use local_data_priv::{
24+
local_pop,
25+
local_get,
26+
local_set,
27+
local_modify
28+
};
2629

2730
/**
2831
* Indexes a task-local data slot. The function's code pointer is used for
@@ -40,162 +43,6 @@ export local_set;
4043
*/
4144
type LocalDataKey<T: Owned> = &fn(+@T);
4245

43-
trait LocalData { }
44-
impl<T: Owned> @T: LocalData { }
45-
46-
impl LocalData: Eq {
47-
pure fn eq(&&other: LocalData) -> bool unsafe {
48-
let ptr_a: (uint, uint) = cast::reinterpret_cast(&self);
49-
let ptr_b: (uint, uint) = cast::reinterpret_cast(&other);
50-
return ptr_a == ptr_b;
51-
}
52-
pure fn ne(&&other: LocalData) -> bool { !self.eq(other) }
53-
}
54-
55-
// We use dvec because it's the best data structure in core. If TLS is used
56-
// heavily in future, this could be made more efficient with a proper map.
57-
type TaskLocalElement = (*libc::c_void, *libc::c_void, LocalData);
58-
// Has to be a pointer at outermost layer; the foreign call returns void *.
59-
type TaskLocalMap = @dvec::DVec<Option<TaskLocalElement>>;
60-
61-
extern fn cleanup_task_local_map(map_ptr: *libc::c_void) unsafe {
62-
assert !map_ptr.is_null();
63-
// Get and keep the single reference that was created at the beginning.
64-
let _map: TaskLocalMap = cast::reinterpret_cast(&map_ptr);
65-
// All local_data will be destroyed along with the map.
66-
}
67-
68-
// Gets the map from the runtime. Lazily initialises if not done so already.
69-
unsafe fn get_task_local_map(task: *rust_task) -> TaskLocalMap {
70-
71-
// Relies on the runtime initialising the pointer to null.
72-
// NOTE: The map's box lives in TLS invisibly referenced once. Each time
73-
// we retrieve it for get/set, we make another reference, which get/set
74-
// drop when they finish. No "re-storing after modifying" is needed.
75-
let map_ptr = rustrt::rust_get_task_local_data(task);
76-
if map_ptr.is_null() {
77-
let map: TaskLocalMap = @dvec::DVec();
78-
// Use reinterpret_cast -- transmute would take map away from us also.
79-
rustrt::rust_set_task_local_data(
80-
task, cast::reinterpret_cast(&map));
81-
rustrt::rust_task_local_data_atexit(task, cleanup_task_local_map);
82-
// Also need to reference it an extra time to keep it for now.
83-
cast::bump_box_refcount(map);
84-
map
85-
} else {
86-
let map = cast::transmute(move map_ptr);
87-
cast::bump_box_refcount(map);
88-
map
89-
}
90-
}
91-
92-
unsafe fn key_to_key_value<T: Owned>(
93-
key: LocalDataKey<T>) -> *libc::c_void {
94-
95-
// Keys are closures, which are (fnptr,envptr) pairs. Use fnptr.
96-
// Use reintepret_cast -- transmute would leak (forget) the closure.
97-
let pair: (*libc::c_void, *libc::c_void) = cast::reinterpret_cast(&key);
98-
pair.first()
99-
}
100-
101-
// If returning Some(..), returns with @T with the map's reference. Careful!
102-
unsafe fn local_data_lookup<T: Owned>(
103-
map: TaskLocalMap, key: LocalDataKey<T>)
104-
-> Option<(uint, *libc::c_void)> {
105-
106-
let key_value = key_to_key_value(key);
107-
let map_pos = (*map).position(|entry|
108-
match entry {
109-
Some((k,_,_)) => k == key_value,
110-
None => false
111-
}
112-
);
113-
do map_pos.map |index| {
114-
// .get() is guaranteed because of "None { false }" above.
115-
let (_, data_ptr, _) = (*map)[index].get();
116-
(index, data_ptr)
117-
}
118-
}
119-
120-
unsafe fn local_get_helper<T: Owned>(
121-
task: *rust_task, key: LocalDataKey<T>,
122-
do_pop: bool) -> Option<@T> {
123-
124-
let map = get_task_local_map(task);
125-
// Interpreturn our findings from the map
126-
do local_data_lookup(map, key).map |result| {
127-
// A reference count magically appears on 'data' out of thin air. It
128-
// was referenced in the local_data box, though, not here, so before
129-
// overwriting the local_data_box we need to give an extra reference.
130-
// We must also give an extra reference when not removing.
131-
let (index, data_ptr) = result;
132-
let data: @T = cast::transmute(move data_ptr);
133-
cast::bump_box_refcount(data);
134-
if do_pop {
135-
(*map).set_elt(index, None);
136-
}
137-
data
138-
}
139-
}
140-
141-
unsafe fn local_pop<T: Owned>(
142-
task: *rust_task,
143-
key: LocalDataKey<T>) -> Option<@T> {
144-
145-
local_get_helper(task, key, true)
146-
}
147-
148-
unsafe fn local_get<T: Owned>(
149-
task: *rust_task,
150-
key: LocalDataKey<T>) -> Option<@T> {
151-
152-
local_get_helper(task, key, false)
153-
}
154-
155-
unsafe fn local_set<T: Owned>(
156-
task: *rust_task, key: LocalDataKey<T>, +data: @T) {
157-
158-
let map = get_task_local_map(task);
159-
// Store key+data as *voids. Data is invisibly referenced once; key isn't.
160-
let keyval = key_to_key_value(key);
161-
// We keep the data in two forms: one as an unsafe pointer, so we can get
162-
// it back by casting; another in an existential box, so the reference we
163-
// own on it can be dropped when the box is destroyed. The unsafe pointer
164-
// does not have a reference associated with it, so it may become invalid
165-
// when the box is destroyed.
166-
let data_ptr = cast::reinterpret_cast(&data);
167-
let data_box = data as LocalData;
168-
// Construct new entry to store in the map.
169-
let new_entry = Some((keyval, data_ptr, data_box));
170-
// Find a place to put it.
171-
match local_data_lookup(map, key) {
172-
Some((index, _old_data_ptr)) => {
173-
// Key already had a value set, _old_data_ptr, whose reference
174-
// will get dropped when the local_data box is overwritten.
175-
(*map).set_elt(index, new_entry);
176-
}
177-
None => {
178-
// Find an empty slot. If not, grow the vector.
179-
match (*map).position(|x| x.is_none()) {
180-
Some(empty_index) => (*map).set_elt(empty_index, new_entry),
181-
None => (*map).push(new_entry)
182-
}
183-
}
184-
}
185-
}
186-
187-
unsafe fn local_modify<T: Owned>(
188-
task: *rust_task, key: LocalDataKey<T>,
189-
modify_fn: fn(Option<@T>) -> Option<@T>) {
190-
191-
// Could be more efficient by doing the lookup work, but this is easy.
192-
let newdata = modify_fn(local_pop(task, key));
193-
if newdata.is_some() {
194-
local_set(task, key, option::unwrap(move newdata));
195-
}
196-
}
197-
198-
/* Exported interface for task-local data (plus local_data_key above). */
19946
/**
20047
* Remove a task-local data value from the table, returning the
20148
* reference that was originally created to insert it.
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
use local_data::LocalDataKey;
2+
3+
trait LocalData { }
4+
impl<T: Owned> @T: LocalData { }
5+
6+
impl LocalData: Eq {
7+
pure fn eq(&&other: LocalData) -> bool unsafe {
8+
let ptr_a: (uint, uint) = cast::reinterpret_cast(&self);
9+
let ptr_b: (uint, uint) = cast::reinterpret_cast(&other);
10+
return ptr_a == ptr_b;
11+
}
12+
pure fn ne(&&other: LocalData) -> bool { !self.eq(other) }
13+
}
14+
15+
// We use dvec because it's the best data structure in core. If TLS is used
16+
// heavily in future, this could be made more efficient with a proper map.
17+
type TaskLocalElement = (*libc::c_void, *libc::c_void, LocalData);
18+
// Has to be a pointer at outermost layer; the foreign call returns void *.
19+
type TaskLocalMap = @dvec::DVec<Option<TaskLocalElement>>;
20+
21+
extern fn cleanup_task_local_map(map_ptr: *libc::c_void) unsafe {
22+
assert !map_ptr.is_null();
23+
// Get and keep the single reference that was created at the beginning.
24+
let _map: TaskLocalMap = cast::reinterpret_cast(&map_ptr);
25+
// All local_data will be destroyed along with the map.
26+
}
27+
28+
// Gets the map from the runtime. Lazily initialises if not done so already.
29+
unsafe fn get_task_local_map(task: *rust_task) -> TaskLocalMap {
30+
31+
// Relies on the runtime initialising the pointer to null.
32+
// NOTE: The map's box lives in TLS invisibly referenced once. Each time
33+
// we retrieve it for get/set, we make another reference, which get/set
34+
// drop when they finish. No "re-storing after modifying" is needed.
35+
let map_ptr = rustrt::rust_get_task_local_data(task);
36+
if map_ptr.is_null() {
37+
let map: TaskLocalMap = @dvec::DVec();
38+
// Use reinterpret_cast -- transmute would take map away from us also.
39+
rustrt::rust_set_task_local_data(
40+
task, cast::reinterpret_cast(&map));
41+
rustrt::rust_task_local_data_atexit(task, cleanup_task_local_map);
42+
// Also need to reference it an extra time to keep it for now.
43+
cast::bump_box_refcount(map);
44+
map
45+
} else {
46+
let map = cast::transmute(move map_ptr);
47+
cast::bump_box_refcount(map);
48+
map
49+
}
50+
}
51+
52+
unsafe fn key_to_key_value<T: Owned>(
53+
key: LocalDataKey<T>) -> *libc::c_void {
54+
55+
// Keys are closures, which are (fnptr,envptr) pairs. Use fnptr.
56+
// Use reintepret_cast -- transmute would leak (forget) the closure.
57+
let pair: (*libc::c_void, *libc::c_void) = cast::reinterpret_cast(&key);
58+
pair.first()
59+
}
60+
61+
// If returning Some(..), returns with @T with the map's reference. Careful!
62+
unsafe fn local_data_lookup<T: Owned>(
63+
map: TaskLocalMap, key: LocalDataKey<T>)
64+
-> Option<(uint, *libc::c_void)> {
65+
66+
let key_value = key_to_key_value(key);
67+
let map_pos = (*map).position(|entry|
68+
match entry {
69+
Some((k,_,_)) => k == key_value,
70+
None => false
71+
}
72+
);
73+
do map_pos.map |index| {
74+
// .get() is guaranteed because of "None { false }" above.
75+
let (_, data_ptr, _) = (*map)[index].get();
76+
(index, data_ptr)
77+
}
78+
}
79+
80+
unsafe fn local_get_helper<T: Owned>(
81+
task: *rust_task, key: LocalDataKey<T>,
82+
do_pop: bool) -> Option<@T> {
83+
84+
let map = get_task_local_map(task);
85+
// Interpreturn our findings from the map
86+
do local_data_lookup(map, key).map |result| {
87+
// A reference count magically appears on 'data' out of thin air. It
88+
// was referenced in the local_data box, though, not here, so before
89+
// overwriting the local_data_box we need to give an extra reference.
90+
// We must also give an extra reference when not removing.
91+
let (index, data_ptr) = result;
92+
let data: @T = cast::transmute(move data_ptr);
93+
cast::bump_box_refcount(data);
94+
if do_pop {
95+
(*map).set_elt(index, None);
96+
}
97+
data
98+
}
99+
}
100+
101+
102+
unsafe fn local_pop<T: Owned>(
103+
task: *rust_task,
104+
key: LocalDataKey<T>) -> Option<@T> {
105+
106+
local_get_helper(task, key, true)
107+
}
108+
109+
unsafe fn local_get<T: Owned>(
110+
task: *rust_task,
111+
key: LocalDataKey<T>) -> Option<@T> {
112+
113+
local_get_helper(task, key, false)
114+
}
115+
116+
unsafe fn local_set<T: Owned>(
117+
task: *rust_task, key: LocalDataKey<T>, +data: @T) {
118+
119+
let map = get_task_local_map(task);
120+
// Store key+data as *voids. Data is invisibly referenced once; key isn't.
121+
let keyval = key_to_key_value(key);
122+
// We keep the data in two forms: one as an unsafe pointer, so we can get
123+
// it back by casting; another in an existential box, so the reference we
124+
// own on it can be dropped when the box is destroyed. The unsafe pointer
125+
// does not have a reference associated with it, so it may become invalid
126+
// when the box is destroyed.
127+
let data_ptr = cast::reinterpret_cast(&data);
128+
let data_box = data as LocalData;
129+
// Construct new entry to store in the map.
130+
let new_entry = Some((keyval, data_ptr, data_box));
131+
// Find a place to put it.
132+
match local_data_lookup(map, key) {
133+
Some((index, _old_data_ptr)) => {
134+
// Key already had a value set, _old_data_ptr, whose reference
135+
// will get dropped when the local_data box is overwritten.
136+
(*map).set_elt(index, new_entry);
137+
}
138+
None => {
139+
// Find an empty slot. If not, grow the vector.
140+
match (*map).position(|x| x.is_none()) {
141+
Some(empty_index) => (*map).set_elt(empty_index, new_entry),
142+
None => (*map).push(new_entry)
143+
}
144+
}
145+
}
146+
}
147+
148+
unsafe fn local_modify<T: Owned>(
149+
task: *rust_task, key: LocalDataKey<T>,
150+
modify_fn: fn(Option<@T>) -> Option<@T>) {
151+
152+
// Could be more efficient by doing the lookup work, but this is easy.
153+
let newdata = modify_fn(local_pop(task, key));
154+
if newdata.is_some() {
155+
local_set(task, key, option::unwrap(move newdata));
156+
}
157+
}

0 commit comments

Comments
 (0)