(index<- ) ./libstd/local_data.rs
git branch: * master 5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
modified: Fri May 9 13:02:28 2014
1 // Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 /*!
12
13 Task local data management
14
15 Allows storing arbitrary types inside task-local-storage (TLS), to be accessed
16 anywhere within a task, keyed by a global pointer parameterized over the type of
17 the TLS slot. Useful for dynamic variables, singletons, and interfacing with
18 foreign code with bad callback interfaces.
19
20 To declare a new key for storing local data of a particular type, use the
21 `local_data_key!` macro. This macro will expand to a `static` item appropriately
22 named and annotated. This name is then passed to the functions in this module to
23 modify/read the slot specified by the key.
24
25 ```rust
26 local_data_key!(key_int: int)
27 local_data_key!(key_vector: ~[int])
28
29 key_int.replace(Some(3));
30 assert_eq!(*key_int.get().unwrap(), 3);
31
32 key_vector.replace(Some(~[4]));
33 assert_eq!(*key_vector.get().unwrap(), ~[4]);
34 ```
35
36 */
37
38 // Casting 'Arcane Sight' reveals an overwhelming aura of Transmutation
39 // magic.
40
41 use cast;
42 use iter::{Iterator};
43 use kinds::Send;
44 use kinds::marker;
45 use mem::replace;
46 use ops::{Drop, Deref};
47 use option::{None, Option, Some};
48 use owned::Box;
49 use raw;
50 use rt::task::{Task, LocalStorage};
51 use slice::{ImmutableVector, MutableVector};
52 use vec::Vec;
53
54 /**
55 * Indexes a task-local data slot. This pointer is used for comparison to
56 * differentiate keys from one another. The actual type `T` is not used anywhere
57 * as a member of this type, except that it is parameterized with it to define
58 * the type of each key's value.
59 *
60 * The value of each Key is of the singleton enum KeyValue. These also have the
61 * same name as `Key` and their purpose is to take up space in the programs data
62 * sections to ensure that each value of the `Key` type points to a unique
63 * location.
64 */
65 pub type Key<T> = &'static KeyValue<T>;
66
67 #[allow(missing_doc)]
68 pub enum KeyValue<T> { Key }
69
70 #[doc(hidden)]
71 trait LocalData {}
72 impl<T: 'static> LocalData for T {}
73
74 // The task-local-map stores all TLS information for the currently running task.
75 // It is stored as an owned pointer into the runtime, and it's only allocated
76 // when TLS is used for the first time. This map must be very carefully
77 // constructed because it has many mutable loans unsoundly handed out on it to
78 // the various invocations of TLS requests.
79 //
80 // One of the most important operations is loaning a value via `get` to a
81 // caller. In doing so, the slot that the TLS entry is occupying cannot be
82 // invalidated because upon returning its loan state must be updated. Currently
83 // the TLS map is a vector, but this is possibly dangerous because the vector
84 // can be reallocated/moved when new values are pushed onto it.
85 //
86 // This problem currently isn't solved in a very elegant way. Inside the `get`
87 // function, it internally "invalidates" all references after the loan is
88 // finished and looks up into the vector again. In theory this will prevent
89 // pointers from being moved under our feet so long as LLVM doesn't go too crazy
90 // with the optimizations.
91 //
92 // n.b. If TLS is used heavily in future, this could be made more efficient with
93 // a proper map.
94 #[doc(hidden)]
95 pub type Map = Vec<Option<(*u8, TLSValue, uint)>>;
96 type TLSValue = Box<LocalData:Send>;
97
98 // Gets the map from the runtime. Lazily initialises if not done so already.
99 unsafe fn get_local_map() -> &mut Map {
100 use rt::local::Local;
101
102 let task: *mut Task = Local::unsafe_borrow();
103 match &mut (*task).storage {
104 // If the at_exit function is already set, then we just need to take
105 // a loan out on the TLS map stored inside
106 &LocalStorage(Some(ref mut map_ptr)) => {
107 return map_ptr;
108 }
109 // If this is the first time we've accessed TLS, perform similar
110 // actions to the oldsched way of doing things.
111 &LocalStorage(ref mut slot) => {
112 *slot = Some(vec!());
113 match *slot {
114 Some(ref mut map_ptr) => { return map_ptr }
115 None => unreachable!(),
116 }
117 }
118 }
119 }
120
121 fn key_to_key_value<T: 'static>(key: Key<T>) -> *u8 {
122 key as *KeyValue<T> as *u8
123 }
124
125 /// An RAII immutable reference to a task-local value.
126 ///
127 /// The task-local data can be accessed through this value, and when this
128 /// structure is dropped it will return the borrow on the data.
129 pub struct Ref<T> {
130 ptr: &'static T,
131 key: Key<T>,
132 index: uint,
133 nosend: marker::NoSend,
134 }
135
136 impl<T: 'static> KeyValue<T> {
137 /// Replaces a value in task local storage.
138 ///
139 /// If this key is already present in TLS, then the previous value is
140 /// replaced with the provided data, and then returned.
141 ///
142 /// # Failure
143 ///
144 /// This function will fail if this key is present in TLS and currently on
145 /// loan with the `get` method.
146 ///
147 /// # Example
148 ///
149 /// ```
150 /// local_data_key!(foo: int)
151 ///
152 /// assert_eq!(foo.replace(Some(10)), None);
153 /// assert_eq!(foo.replace(Some(4)), Some(10));
154 /// assert_eq!(foo.replace(None), Some(4));
155 /// ```
156 pub fn replace(&'static self, data: Option<T>) -> Option<T> {
157 let map = unsafe { get_local_map() };
158 let keyval = key_to_key_value(self);
159
160 // When the task-local map is destroyed, all the data needs to be
161 // cleaned up. For this reason we can't do some clever tricks to store
162 // '~T' as a '*c_void' or something like that. To solve the problem, we
163 // cast everything to a trait (LocalData) which is then stored inside
164 // the map. Upon destruction of the map, all the objects will be
165 // destroyed and the traits have enough information about them to
166 // destroy themselves.
167 //
168 // Additionally, the type of the local data map must ascribe to Send, so
169 // we do the transmute here to add the Send bound back on. This doesn't
170 // actually matter because TLS will always own the data (until its moved
171 // out) and we're not actually sending it to other schedulers or
172 // anything.
173 let newval = data.map(|d| {
174 let d = box d as Box<LocalData>;
175 let d: Box<LocalData:Send> = unsafe { cast::transmute(d) };
176 (keyval, d, 0)
177 });
178
179 let pos = match self.find(map) {
180 Some((i, _, &0)) => Some(i),
181 Some((_, _, _)) => fail!("TLS value cannot be replaced because it \
182 is already borrowed"),
183 None => map.iter().position(|entry| entry.is_none()),
184 };
185
186 match pos {
187 Some(i) => {
188 replace(map.get_mut(i), newval).map(|(_, data, _)| {
189 // Move `data` into transmute to get out the memory that it
190 // owns, we must free it manually later.
191 let t: raw::TraitObject = unsafe { cast::transmute(data) };
192 let alloc: Box<T> = unsafe { cast::transmute(t.data) };
193
194 // Now that we own `alloc`, we can just move out of it as we
195 // would with any other data.
196 *alloc
197 })
198 }
199 None => {
200 map.push(newval);
201 None
202 }
203 }
204 }
205
206 /// Borrows a value from TLS.
207 ///
208 /// If `None` is returned, then this key is not present in TLS. If `Some` is
209 /// returned, then the returned data is a smart pointer representing a new
210 /// loan on this TLS key. While on loan, this key cannot be altered via the
211 /// `replace` method.
212 ///
213 /// # Example
214 ///
215 /// ```
216 /// local_data_key!(key: int)
217 ///
218 /// assert!(key.get().is_none());
219 ///
220 /// key.replace(Some(3));
221 /// assert_eq!(*key.get().unwrap(), 3);
222 /// ```
223 pub fn get(&'static self) -> Option<Ref<T>> {
224 let map = unsafe { get_local_map() };
225
226 self.find(map).map(|(pos, data, loan)| {
227 *loan += 1;
228
229 // data was created with `~T as ~LocalData`, so we extract
230 // pointer part of the trait, (as ~T), and then use
231 // compiler coercions to achieve a '&' pointer.
232 let ptr = unsafe {
233 let data = data as *Box<LocalData:Send> as *raw::TraitObject;
234 &mut *((*data).data as *mut T)
235 };
236 Ref { ptr: ptr, index: pos, nosend: marker::NoSend, key: self }
237 })
238 }
239
240 fn find<'a>(&'static self,
241 map: &'a mut Map) -> Option<(uint, &'a TLSValue, &'a mut uint)>{
242 let key_value = key_to_key_value(self);
243 map.mut_iter().enumerate().filter_map(|(i, entry)| {
244 match *entry {
245 Some((k, ref data, ref mut loan)) if k == key_value => {
246 Some((i, data, loan))
247 }
248 _ => None
249 }
250 }).next()
251 }
252 }
253
254 impl<T: 'static> Deref<T> for Ref<T> {
255 fn deref<'a>(&'a self) -> &'a T { self.ptr }
256 }
257
258 #[unsafe_destructor]
259 impl<T: 'static> Drop for Ref<T> {
260 fn drop(&mut self) {
261 let map = unsafe { get_local_map() };
262
263 let (_, _, ref mut loan) = *map.get_mut(self.index).get_mut_ref();
264 *loan -= 1;
265 }
266 }
267
268 #[cfg(test)]
269 mod tests {
270 use prelude::*;
271 use super::*;
272 use owned::Box;
273 use task;
274
275 #[test]
276 fn test_tls_multitask() {
277 static my_key: Key<~str> = &Key;
278 my_key.replace(Some("parent data".to_owned()));
279 task::spawn(proc() {
280 // TLS shouldn't carry over.
281 assert!(my_key.get().is_none());
282 my_key.replace(Some("child data".to_owned()));
283 assert!(my_key.get().get_ref().as_slice() == "child data");
284 // should be cleaned up for us
285 });
286
287 // Must work multiple times
288 assert!(my_key.get().unwrap().as_slice() == "parent data");
289 assert!(my_key.get().unwrap().as_slice() == "parent data");
290 assert!(my_key.get().unwrap().as_slice() == "parent data");
291 }
292
293 #[test]
294 fn test_tls_overwrite() {
295 static my_key: Key<~str> = &Key;
296 my_key.replace(Some("first data".to_owned()));
297 my_key.replace(Some("next data".to_owned())); // Shouldn't leak.
298 assert!(my_key.get().unwrap().as_slice() == "next data");
299 }
300
301 #[test]
302 fn test_tls_pop() {
303 static my_key: Key<~str> = &Key;
304 my_key.replace(Some("weasel".to_owned()));
305 assert!(my_key.replace(None).unwrap() == "weasel".to_owned());
306 // Pop must remove the data from the map.
307 assert!(my_key.replace(None).is_none());
308 }
309
310 #[test]
311 fn test_tls_crust_automorestack_memorial_bug() {
312 // This might result in a stack-canary clobber if the runtime fails to
313 // set sp_limit to 0 when calling the cleanup extern - it might
314 // automatically jump over to the rust stack, which causes next_c_sp
315 // to get recorded as something within a rust stack segment. Then a
316 // subsequent upcall (esp. for logging, think vsnprintf) would run on
317 // a stack smaller than 1 MB.
318 static my_key: Key<~str> = &Key;
319 task::spawn(proc() {
320 my_key.replace(Some("hax".to_owned()));
321 });
322 }
323
324 #[test]
325 fn test_tls_multiple_types() {
326 static str_key: Key<~str> = &Key;
327 static box_key: Key<@()> = &Key;
328 static int_key: Key<int> = &Key;
329 task::spawn(proc() {
330 str_key.replace(Some("string data".to_owned()));
331 box_key.replace(Some(@()));
332 int_key.replace(Some(42));
333 });
334 }
335
336 #[test]
337 fn test_tls_overwrite_multiple_types() {
338 static str_key: Key<~str> = &Key;
339 static box_key: Key<@()> = &Key;
340 static int_key: Key<int> = &Key;
341 task::spawn(proc() {
342 str_key.replace(Some("string data".to_owned()));
343 str_key.replace(Some("string data 2".to_owned()));
344 box_key.replace(Some(@()));
345 box_key.replace(Some(@()));
346 int_key.replace(Some(42));
347 // This could cause a segfault if overwriting-destruction is done
348 // with the crazy polymorphic transmute rather than the provided
349 // finaliser.
350 int_key.replace(Some(31337));
351 });
352 }
353
354 #[test]
355 #[should_fail]
356 fn test_tls_cleanup_on_failure() {
357 static str_key: Key<~str> = &Key;
358 static box_key: Key<@()> = &Key;
359 static int_key: Key<int> = &Key;
360 str_key.replace(Some("parent data".to_owned()));
361 box_key.replace(Some(@()));
362 task::spawn(proc() {
363 str_key.replace(Some("string data".to_owned()));
364 box_key.replace(Some(@()));
365 int_key.replace(Some(42));
366 fail!();
367 });
368 // Not quite nondeterministic.
369 int_key.replace(Some(31337));
370 fail!();
371 }
372
373 #[test]
374 fn test_static_pointer() {
375 static key: Key<&'static int> = &Key;
376 static VALUE: int = 0;
377 key.replace(Some(&VALUE));
378 }
379
380 #[test]
381 fn test_owned() {
382 static key: Key<Box<int>> = &Key;
383 key.replace(Some(box 1));
384
385 {
386 let k1 = key.get().unwrap();
387 let k2 = key.get().unwrap();
388 let k3 = key.get().unwrap();
389 assert_eq!(**k1, 1);
390 assert_eq!(**k2, 1);
391 assert_eq!(**k3, 1);
392 }
393 key.replace(Some(box 2));
394 assert_eq!(**key.get().unwrap(), 2);
395 }
396
397 #[test]
398 fn test_same_key_type() {
399 static key1: Key<int> = &Key;
400 static key2: Key<int> = &Key;
401 static key3: Key<int> = &Key;
402 static key4: Key<int> = &Key;
403 static key5: Key<int> = &Key;
404 key1.replace(Some(1));
405 key2.replace(Some(2));
406 key3.replace(Some(3));
407 key4.replace(Some(4));
408 key5.replace(Some(5));
409
410 assert_eq!(*key1.get().unwrap(), 1);
411 assert_eq!(*key2.get().unwrap(), 2);
412 assert_eq!(*key3.get().unwrap(), 3);
413 assert_eq!(*key4.get().unwrap(), 4);
414 assert_eq!(*key5.get().unwrap(), 5);
415 }
416
417 #[test]
418 #[should_fail]
419 fn test_nested_get_set1() {
420 static key: Key<int> = &Key;
421 key.replace(Some(4));
422
423 let _k = key.get();
424 key.replace(Some(4));
425 }
426 }
libstd/local_data.rs:64:4-64:4 -NK_AS_STR_TODO- definition:
*/
pub type Key<T> = &'static KeyValue<T>;
pub enum KeyValue<T> { Key }
references:- 2121: fn key_to_key_value<T: 'static>(key: Key<T>) -> *u8 {
122: key as *KeyValue<T> as *u8
--
130: ptr: &'static T,
131: key: Key<T>,
132: index: uint,
libstd/local_data.rs:67:22-67:22 -enum- definition:
pub enum KeyValue<T> { Key }
trait LocalData {}
impl<T: 'static> LocalData for T {}
references:- 3121: fn key_to_key_value<T: 'static>(key: Key<T>) -> *u8 {
122: key as *KeyValue<T> as *u8
123: }
--
136: impl<T: 'static> KeyValue<T> {
137: /// Replaces a value in task local storage.
libstd/local_data.rs:95:51-95:51 -NK_AS_STR_TODO- definition:
pub type Map = Vec<Option<(*u8, TLSValue, uint)>>;
type TLSValue = Box<LocalData:Send>;
// Gets the map from the runtime. Lazily initialises if not done so already.
references:- 2240: fn find<'a>(&'static self,
241: map: &'a mut Map) -> Option<(uint, &'a TLSValue, &'a mut uint)>{
242: let key_value = key_to_key_value(self);
libstd/local_data.rs:70:15-70:15 -trait- definition:
trait LocalData {}
impl<T: 'static> LocalData for T {}
// The task-local-map stores all TLS information for the currently running task.
references:- 5173: let newval = data.map(|d| {
174: let d = box d as Box<LocalData>;
175: let d: Box<LocalData:Send> = unsafe { cast::transmute(d) };
176: (keyval, d, 0)
--
232: let ptr = unsafe {
233: let data = data as *Box<LocalData:Send> as *raw::TraitObject;
234: &mut *((*data).data as *mut T)
libstd/local_data.rs:120:1-120:1 -fn- definition:
fn key_to_key_value<T: 'static>(key: Key<T>) -> *u8 {
key as *KeyValue<T> as *u8
}
references:- 2241: map: &'a mut Map) -> Option<(uint, &'a TLSValue, &'a mut uint)>{
242: let key_value = key_to_key_value(self);
243: map.mut_iter().enumerate().filter_map(|(i, entry)| {
libstd/local_data.rs:94:15-94:15 -NK_AS_STR_TODO- definition:
pub type Map = Vec<Option<(*u8, TLSValue, uint)>>;
type TLSValue = Box<LocalData:Send>;
// Gets the map from the runtime. Lazily initialises if not done so already.
references:- 398: // Gets the map from the runtime. Lazily initialises if not done so already.
99: unsafe fn get_local_map() -> &mut Map {
100: use rt::local::Local;
libstd/rt/task.rs:
61: pub struct GarbageCollector;
62: pub struct LocalStorage(pub Option<local_data::Map>);
libstd/local_data.rs:
240: fn find<'a>(&'static self,
241: map: &'a mut Map) -> Option<(uint, &'a TLSValue, &'a mut uint)>{
242: let key_value = key_to_key_value(self);
libstd/local_data.rs:98:77-98:77 -fn- definition:
// Gets the map from the runtime. Lazily initialises if not done so already.
unsafe fn get_local_map() -> &mut Map {
use rt::local::Local;
references:- 3223: pub fn get(&'static self) -> Option<Ref<T>> {
224: let map = unsafe { get_local_map() };
--
260: fn drop(&mut self) {
261: let map = unsafe { get_local_map() };
libstd/local_data.rs:128:64-128:64 -struct- definition:
/// structure is dropped it will return the borrow on the data.
pub struct Ref<T> {
ptr: &'static T,
references:- 4222: /// ```
223: pub fn get(&'static self) -> Option<Ref<T>> {
224: let map = unsafe { get_local_map() };
--
254: impl<T: 'static> Deref<T> for Ref<T> {
255: fn deref<'a>(&'a self) -> &'a T { self.ptr }
--
259: impl<T: 'static> Drop for Ref<T> {
260: fn drop(&mut self) {