@@ -14,15 +14,18 @@ Casting 'Arcane Sight' reveals an overwhelming aura of Transmutation magic.
14
14
15
15
*/
16
16
17
- export local_data_key ;
17
+ export LocalDataKey ;
18
18
export local_data_pop;
19
19
export local_data_get;
20
20
export local_data_set;
21
21
export local_data_modify;
22
22
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
+ } ;
26
29
27
30
/**
28
31
* Indexes a task-local data slot. The function's code pointer is used for
@@ -40,162 +43,6 @@ export local_set;
40
43
*/
41
44
type LocalDataKey < T : Owned > = & fn ( +@T ) ;
42
45
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). */
199
46
/**
200
47
* Remove a task-local data value from the table, returning the
201
48
* reference that was originally created to insert it.
0 commit comments