13
13
use cast;
14
14
use cmp:: Eq ;
15
15
use libc;
16
+ use local_data:: LocalDataKey ;
16
17
use prelude:: * ;
18
+ use sys;
17
19
use task:: rt;
18
- use local_data:: LocalDataKey ;
19
20
20
21
use super :: rt:: rust_task;
21
22
use rt:: task:: { Task , LocalStorage } ;
@@ -61,7 +62,7 @@ impl Eq for @LocalData {
61
62
// proper map.
62
63
type TaskLocalElement = ( * libc:: c_void , * libc:: c_void , @LocalData ) ;
63
64
// Has to be a pointer at outermost layer; the foreign call returns void *.
64
- type TaskLocalMap = @ mut ~[ Option < TaskLocalElement > ] ;
65
+ type TaskLocalMap = ~[ Option < TaskLocalElement > ] ;
65
66
66
67
fn cleanup_task_local_map ( map_ptr : * libc:: c_void ) {
67
68
unsafe {
@@ -74,85 +75,75 @@ fn cleanup_task_local_map(map_ptr: *libc::c_void) {
74
75
}
75
76
76
77
// Gets the map from the runtime. Lazily initialises if not done so already.
77
- unsafe fn get_local_map ( handle : Handle ) -> TaskLocalMap {
78
+ unsafe fn get_local_map ( handle : Handle ) -> & mut TaskLocalMap {
78
79
match handle {
79
80
OldHandle ( task) => get_task_local_map ( task) ,
80
81
NewHandle ( local_storage) => get_newsched_local_map ( local_storage)
81
82
}
82
83
}
83
84
84
- unsafe fn get_task_local_map ( task : * rust_task ) -> TaskLocalMap {
85
+ unsafe fn get_task_local_map ( task : * rust_task ) -> & mut TaskLocalMap {
85
86
86
87
extern fn cleanup_task_local_map_extern_cb ( map_ptr : * libc:: c_void ) {
87
88
cleanup_task_local_map ( map_ptr) ;
88
89
}
89
90
90
91
// Relies on the runtime initialising the pointer to null.
91
- // Note: The map's box lives in TLS invisibly referenced once. Each time
92
- // we retrieve it for get/set, we make another reference, which get/set
93
- // drop when they finish. No "re-storing after modifying" is needed .
92
+ // Note: the map is an owned pointer and is "owned" by TLS. It is moved
93
+ // into the tls slot for this task, and then mutable loans are taken from
94
+ // this slot to modify the map .
94
95
let map_ptr = rt:: rust_get_task_local_data ( task) ;
95
- if map_ptr. is_null ( ) {
96
- let map: TaskLocalMap = @ mut ~ [ ] ;
97
- // NB: This bumps the ref count before converting to an unsafe pointer,
98
- // keeping the map alive until TLS is destroyed
99
- rt :: rust_set_task_local_data ( task , cast:: transmute ( map) ) ;
96
+ if ( * map_ptr) . is_null ( ) {
97
+ // First time TLS is used, create a new map and set up the necessary
98
+ // TLS information for its safe destruction
99
+ let map: TaskLocalMap = ~ [ ] ;
100
+ * map_ptr = cast:: transmute ( map) ;
100
101
rt:: rust_task_local_data_atexit ( task, cleanup_task_local_map_extern_cb) ;
101
- map
102
- } else {
103
- let map = cast:: transmute ( map_ptr) ;
104
- let nonmut = cast:: transmute :: < TaskLocalMap ,
105
- @~[ Option < TaskLocalElement > ] > ( map) ;
106
- cast:: bump_box_refcount ( nonmut) ;
107
- map
108
102
}
103
+ return cast:: transmute ( map_ptr) ;
109
104
}
110
105
111
- unsafe fn get_newsched_local_map ( local : * mut LocalStorage ) -> TaskLocalMap {
106
+ unsafe fn get_newsched_local_map ( local : * mut LocalStorage ) -> & mut TaskLocalMap {
107
+ // This is based on the same idea as the oldsched code above.
112
108
match & mut * local {
113
- & LocalStorage ( map_ptr, Some ( _) ) => {
109
+ // If the at_exit function is already set, then we just need to take a
110
+ // loan out on the TLS map stored inside
111
+ & LocalStorage ( ref mut map_ptr, Some ( _) ) => {
114
112
assert ! ( map_ptr. is_not_null( ) ) ;
115
- let map = cast:: transmute ( map_ptr) ;
116
- let nonmut = cast:: transmute :: < TaskLocalMap ,
117
- @~[ Option < TaskLocalElement > ] > ( map) ;
118
- cast:: bump_box_refcount ( nonmut) ;
119
- return map;
113
+ return cast:: transmute ( map_ptr) ;
120
114
}
115
+ // If this is the first time we've accessed TLS, perform similar
116
+ // actions to the oldsched way of doing things.
121
117
& LocalStorage ( ref mut map_ptr, ref mut at_exit) => {
122
- assert ! ( ( * map_ptr) . is_null( ) ) ;
123
- let map: TaskLocalMap = @mut ~[ ] ;
118
+ assert ! ( map_ptr. is_null( ) ) ;
119
+ assert ! ( at_exit. is_none( ) ) ;
120
+ let map: TaskLocalMap = ~[ ] ;
124
121
* map_ptr = cast:: transmute ( map) ;
125
- let at_exit_fn: ~fn ( * libc:: c_void ) = |p|cleanup_task_local_map ( p) ;
122
+ let at_exit_fn: ~fn ( * libc:: c_void ) = |p| cleanup_task_local_map ( p) ;
126
123
* at_exit = Some ( at_exit_fn) ;
127
- return map ;
124
+ return cast :: transmute ( map_ptr ) ;
128
125
}
129
126
}
130
127
}
131
128
132
129
unsafe fn key_to_key_value < T : ' static > ( key : LocalDataKey < T > ) -> * libc:: c_void {
133
- // Keys are closures, which are (fnptr,envptr) pairs. Use fnptr.
134
- // Use reinterpret_cast -- transmute would leak (forget) the closure.
135
- let pair: ( * libc:: c_void , * libc:: c_void ) = cast:: transmute_copy ( & key) ;
136
- pair. first ( )
130
+ let pair: sys:: Closure = cast:: transmute ( key) ;
131
+ return pair. code as * libc:: c_void ;
137
132
}
138
133
139
134
// If returning Some(..), returns with @T with the map's reference. Careful!
140
135
unsafe fn local_data_lookup< T : ' static > (
141
- map : TaskLocalMap , key : LocalDataKey < T > )
136
+ map : & mut TaskLocalMap , key : LocalDataKey < T > )
142
137
-> Option < ( uint , * libc:: c_void ) > {
143
138
144
139
let key_value = key_to_key_value ( key) ;
145
- let map_pos = ( * map) . iter ( ) . position ( | entry|
140
+ for map. iter( ) . enumerate ( ) . advance | ( i , entry) | {
146
141
match * entry {
147
- Some ( ( k, _ , _) ) => k == key_value,
148
- None => false
142
+ Some ( ( k, data , _) ) if k == key_value => { return Some ( ( i , data ) ) ; }
143
+ _ => { }
149
144
}
150
- ) ;
151
- do map_pos. map |index| {
152
- // .get() is guaranteed because of "None { false }" above.
153
- let ( _, data_ptr, _) = ( * map) [ * index] . get ( ) ;
154
- ( * index, data_ptr)
155
145
}
146
+ return None ;
156
147
}
157
148
158
149
unsafe fn local_get_helper < T : ' static > (
@@ -215,7 +206,7 @@ pub unsafe fn local_set<T: 'static>(
215
206
}
216
207
None => {
217
208
// Find an empty slot. If not, grow the vector.
218
- match ( * map) . iter ( ) . position ( |x| x. is_none ( ) ) {
209
+ match map. iter ( ) . position ( |x| x. is_none ( ) ) {
219
210
Some ( empty_index) => { map[ empty_index] = new_entry; }
220
211
None => { map. push ( new_entry) ; }
221
212
}
0 commit comments