]> git.lizzy.rs Git - rust.git/blob - src/libstd/local_data.rs
Find the cratemap at runtime on windows.
[rust.git] / src / libstd / local_data.rs
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 apppriately
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 use std::local_data;
27
28 local_data_key!(key_int: int);
29 local_data_key!(key_vector: ~[int]);
30
31 local_data::set(key_int, 3);
32 local_data::get(key_int, |opt| assert_eq!(opt, Some(&3)));
33
34 local_data::set(key_vector, ~[4]);
35 local_data::get(key_vector, |opt| assert_eq!(opt, Some(&~[4])));
36 ~~~
37
38 */
39
40 // Casting 'Arcane Sight' reveals an overwhelming aura of Transmutation
41 // magic.
42
43 use cast;
44 use libc;
45 use prelude::*;
46 use rt::task::{Task, LocalStorage};
47 use util;
48
49 /**
50  * Indexes a task-local data slot. This pointer is used for comparison to
51  * differentiate keys from one another. The actual type `T` is not used anywhere
52  * as a member of this type, except that it is parameterized with it to define
53  * the type of each key's value.
54  *
55  * The value of each Key is of the singleton enum KeyValue. These also have the
56  * same name as `Key` and their purpose is to take up space in the programs data
57  * sections to ensure that each value of the `Key` type points to a unique
58  * location.
59  */
60 pub type Key<T> = &'static KeyValue<T>;
61
62 pub enum KeyValue<T> { Key }
63
64 trait LocalData {}
65 impl<T: 'static> LocalData for T {}
66
67 // The task-local-map stores all TLS information for the currently running task.
68 // It is stored as an owned pointer into the runtime, and it's only allocated
69 // when TLS is used for the first time. This map must be very carefully
70 // constructed because it has many mutable loans unsoundly handed out on it to
71 // the various invocations of TLS requests.
72 //
73 // One of the most important operations is loaning a value via `get` to a
74 // caller. In doing so, the slot that the TLS entry is occupying cannot be
75 // invalidated because upon returning it's loan state must be updated. Currently
76 // the TLS map is a vector, but this is possibly dangerous because the vector
77 // can be reallocated/moved when new values are pushed onto it.
78 //
79 // This problem currently isn't solved in a very elegant way. Inside the `get`
80 // function, it internally "invalidates" all references after the loan is
81 // finished and looks up into the vector again. In theory this will prevent
82 // pointers from being moved under our feet so long as LLVM doesn't go too crazy
83 // with the optimizations.
84 //
85 // n.b. If TLS is used heavily in future, this could be made more efficient with
86 //      a proper map.
87 #[doc(hidden)]
88 pub type Map = ~[Option<(*libc::c_void, TLSValue, LoanState)>];
89 type TLSValue = ~LocalData;
90
91 // Gets the map from the runtime. Lazily initialises if not done so already.
92 unsafe fn get_local_map() -> &mut Map {
93     use rt::local::Local;
94
95     let task: *mut Task = Local::unsafe_borrow();
96     match &mut (*task).storage {
97         // If the at_exit function is already set, then we just need to take
98         // a loan out on the TLS map stored inside
99         &LocalStorage(Some(ref mut map_ptr)) => {
100             return map_ptr;
101         }
102         // If this is the first time we've accessed TLS, perform similar
103         // actions to the oldsched way of doing things.
104         &LocalStorage(ref mut slot) => {
105             *slot = Some(~[]);
106             match *slot {
107                 Some(ref mut map_ptr) => { return map_ptr }
108                 None => abort()
109             }
110         }
111     }
112 }
113
114 #[deriving(Eq)]
115 enum LoanState {
116     NoLoan, ImmLoan, MutLoan
117 }
118
119 impl LoanState {
120     fn describe(&self) -> &'static str {
121         match *self {
122             NoLoan => "no loan",
123             ImmLoan => "immutable",
124             MutLoan => "mutable"
125         }
126     }
127 }
128
129 fn key_to_key_value<T: 'static>(key: Key<T>) -> *libc::c_void {
130     unsafe { cast::transmute(key) }
131 }
132
133 /// Removes a task-local value from task-local storage. This will return
134 /// Some(value) if the key was present in TLS, otherwise it will return None.
135 ///
136 /// A runtime assertion will be triggered it removal of TLS value is attempted
137 /// while the value is still loaned out via `get` or `get_mut`.
138 pub fn pop<T: 'static>(key: Key<T>) -> Option<T> {
139     let map = unsafe { get_local_map() };
140     let key_value = key_to_key_value(key);
141
142     for entry in map.mut_iter() {
143         match *entry {
144             Some((k, _, loan)) if k == key_value => {
145                 if loan != NoLoan {
146                     fail!("TLS value cannot be removed because it is currently \
147                           borrowed as %s", loan.describe());
148                 }
149                 // Move the data out of the `entry` slot via util::replace.
150                 // This is guaranteed to succeed because we already matched
151                 // on `Some` above.
152                 let data = match util::replace(entry, None) {
153                     Some((_, data, _)) => data,
154                     None => abort()
155                 };
156
157                 // Move `data` into transmute to get out the memory that it
158                 // owns, we must free it manually later.
159                 let (_vtable, box): (uint, ~T) = unsafe {
160                     cast::transmute(data)
161                 };
162
163                 // Now that we own `box`, we can just move out of it as we would
164                 // with any other data.
165                 return Some(*box);
166             }
167             _ => {}
168         }
169     }
170     return None;
171 }
172
173 /// Retrieves a value from TLS. The closure provided is yielded `Some` of a
174 /// reference to the value located in TLS if one exists, or `None` if the key
175 /// provided is not present in TLS currently.
176 ///
177 /// It is considered a runtime error to attempt to get a value which is already
178 /// on loan via the `get_mut` method provided.
179 pub fn get<T: 'static, U>(key: Key<T>, f: &fn(Option<&T>) -> U) -> U {
180     get_with(key, ImmLoan, f)
181 }
182
183 /// Retrieves a mutable value from TLS. The closure provided is yielded `Some`
184 /// of a reference to the mutable value located in TLS if one exists, or `None`
185 /// if the key provided is not present in TLS currently.
186 ///
187 /// It is considered a runtime error to attempt to get a value which is already
188 /// on loan via this or the `get` methods. This is similar to how it's a runtime
189 /// error to take two mutable loans on an `@mut` box.
190 pub fn get_mut<T: 'static, U>(key: Key<T>, f: &fn(Option<&mut T>) -> U) -> U {
191     do get_with(key, MutLoan) |x| {
192         match x {
193             None => f(None),
194             // We're violating a lot of compiler guarantees with this
195             // invocation of `transmute_mut`, but we're doing runtime checks to
196             // ensure that it's always valid (only one at a time).
197             //
198             // there is no need to be upset!
199             Some(x) => { f(Some(unsafe { cast::transmute_mut(x) })) }
200         }
201     }
202 }
203
204 fn get_with<T: 'static, U>(key: Key<T>,
205                            state: LoanState,
206                            f: &fn(Option<&T>) -> U) -> U {
207     // This function must be extremely careful. Because TLS can store owned
208     // values, and we must have some form of `get` function other than `pop`,
209     // this function has to give a `&` reference back to the caller.
210     //
211     // One option is to return the reference, but this cannot be sound because
212     // the actual lifetime of the object is not known. The slot in TLS could not
213     // be modified until the object goes out of scope, but the TLS code cannot
214     // know when this happens.
215     //
216     // For this reason, the reference is yielded to a specified closure. This
217     // way the TLS code knows exactly what the lifetime of the yielded pointer
218     // is, allowing callers to acquire references to owned data. This is also
219     // sound so long as measures are taken to ensure that while a TLS slot is
220     // loaned out to a caller, it's not modified recursively.
221     let map = unsafe { get_local_map() };
222     let key_value = key_to_key_value(key);
223
224     let pos = map.iter().position(|entry| {
225         match *entry {
226             Some((k, _, _)) if k == key_value => true, _ => false
227         }
228     });
229     match pos {
230         None => { return f(None); }
231         Some(i) => {
232             let ret;
233             let mut return_loan = false;
234             match map[i] {
235                 Some((_, ref data, ref mut loan)) => {
236                     match (state, *loan) {
237                         (_, NoLoan) => {
238                             *loan = state;
239                             return_loan = true;
240                         }
241                         (ImmLoan, ImmLoan) => {}
242                         (want, cur) => {
243                             fail!("TLS slot cannot be borrowed as %s because \
244                                    it is already borrowed as %s",
245                                   want.describe(), cur.describe());
246                         }
247                     }
248                     // data was created with `~T as ~LocalData`, so we extract
249                     // pointer part of the trait, (as ~T), and then use
250                     // compiler coercions to achieve a '&' pointer.
251                     unsafe {
252                         match *cast::transmute::<&TLSValue, &(uint, ~T)>(data){
253                             (_vtable, ref box) => {
254                                 let value: &T = *box;
255                                 ret = f(Some(value));
256                             }
257                         }
258                     }
259                 }
260                 _ => abort()
261             }
262
263             // n.b. 'data' and 'loans' are both invalid pointers at the point
264             // 'f' returned because `f` could have appended more TLS items which
265             // in turn relocated the vector. Hence we do another lookup here to
266             // fixup the loans.
267             if return_loan {
268                 match map[i] {
269                     Some((_, _, ref mut loan)) => { *loan = NoLoan; }
270                     None => abort()
271                 }
272             }
273             return ret;
274         }
275     }
276 }
277
278 fn abort() -> ! {
279     #[fixed_stack_segment]; #[inline(never)];
280     unsafe { libc::abort() }
281 }
282
283 /// Inserts a value into task local storage. If the key is already present in
284 /// TLS, then the previous value is removed and replaced with the provided data.
285 ///
286 /// It is considered a runtime error to attempt to set a key which is currently
287 /// on loan via the `get` or `get_mut` methods.
288 pub fn set<T: 'static>(key: Key<T>, data: T) {
289     let map = unsafe { get_local_map() };
290     let keyval = key_to_key_value(key);
291
292     // When the task-local map is destroyed, all the data needs to be cleaned
293     // up. For this reason we can't do some clever tricks to store '~T' as a
294     // '*c_void' or something like that. To solve the problem, we cast
295     // everything to a trait (LocalData) which is then stored inside the map.
296     // Upon destruction of the map, all the objects will be destroyed and the
297     // traits have enough information about them to destroy themselves.
298     let data = ~data as ~LocalData:;
299
300     fn insertion_position(map: &mut Map,
301                           key: *libc::c_void) -> Option<uint> {
302         // First see if the map contains this key already
303         let curspot = map.iter().position(|entry| {
304             match *entry {
305                 Some((ekey, _, loan)) if key == ekey => {
306                     if loan != NoLoan {
307                         fail!("TLS value cannot be overwritten because it is
308                                already borrowed as %s", loan.describe())
309                     }
310                     true
311                 }
312                 _ => false,
313             }
314         });
315         // If it doesn't contain the key, just find a slot that's None
316         match curspot {
317             Some(i) => Some(i),
318             None => map.iter().position(|entry| entry.is_none())
319         }
320     }
321
322     // The type of the local data map must ascribe to Send, so we do the
323     // transmute here to add the Send bound back on. This doesn't actually
324     // matter because TLS will always own the data (until its moved out) and
325     // we're not actually sending it to other schedulers or anything.
326     let data: ~LocalData = unsafe { cast::transmute(data) };
327     match insertion_position(map, keyval) {
328         Some(i) => { map[i] = Some((keyval, data, NoLoan)); }
329         None => { map.push(Some((keyval, data, NoLoan))); }
330     }
331 }
332
333 /// Modifies a task-local value by temporarily removing it from task-local
334 /// storage and then re-inserting if `Some` is returned from the closure.
335 ///
336 /// This function will have the same runtime errors as generated from `pop` and
337 /// `set` (the key must not currently be on loan
338 pub fn modify<T: 'static>(key: Key<T>, f: &fn(Option<T>) -> Option<T>) {
339     match f(pop(key)) {
340         Some(next) => { set(key, next); }
341         None => {}
342     }
343 }
344
345 #[cfg(test)]
346 mod tests {
347     use prelude::*;
348     use super::*;
349     use task;
350
351     #[test]
352     fn test_tls_multitask() {
353         static my_key: Key<@~str> = &Key;
354         set(my_key, @~"parent data");
355         do task::spawn {
356             // TLS shouldn't carry over.
357             assert!(get(my_key, |k| k.map_move(|k| *k)).is_none());
358             set(my_key, @~"child data");
359             assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) ==
360                     ~"child data");
361             // should be cleaned up for us
362         }
363         // Must work multiple times
364         assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"parent data");
365         assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"parent data");
366         assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"parent data");
367     }
368
369     #[test]
370     fn test_tls_overwrite() {
371         static my_key: Key<@~str> = &Key;
372         set(my_key, @~"first data");
373         set(my_key, @~"next data"); // Shouldn't leak.
374         assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"next data");
375     }
376
377     #[test]
378     fn test_tls_pop() {
379         static my_key: Key<@~str> = &Key;
380         set(my_key, @~"weasel");
381         assert!(*(pop(my_key).unwrap()) == ~"weasel");
382         // Pop must remove the data from the map.
383         assert!(pop(my_key).is_none());
384     }
385
386     #[test]
387     fn test_tls_modify() {
388         static my_key: Key<@~str> = &Key;
389         modify(my_key, |data| {
390             match data {
391                 Some(@ref val) => fail!("unwelcome value: %s", *val),
392                 None           => Some(@~"first data")
393             }
394         });
395         modify(my_key, |data| {
396             match data {
397                 Some(@~"first data") => Some(@~"next data"),
398                 Some(@ref val)       => fail!("wrong value: %s", *val),
399                 None                 => fail!("missing value")
400             }
401         });
402         assert!(*(pop(my_key).unwrap()) == ~"next data");
403     }
404
405     #[test]
406     fn test_tls_crust_automorestack_memorial_bug() {
407         // This might result in a stack-canary clobber if the runtime fails to
408         // set sp_limit to 0 when calling the cleanup extern - it might
409         // automatically jump over to the rust stack, which causes next_c_sp
410         // to get recorded as something within a rust stack segment. Then a
411         // subsequent upcall (esp. for logging, think vsnprintf) would run on
412         // a stack smaller than 1 MB.
413         static my_key: Key<@~str> = &Key;
414         do task::spawn {
415             set(my_key, @~"hax");
416         }
417     }
418
419     #[test]
420     fn test_tls_multiple_types() {
421         static str_key: Key<@~str> = &Key;
422         static box_key: Key<@@()> = &Key;
423         static int_key: Key<@int> = &Key;
424         do task::spawn {
425             set(str_key, @~"string data");
426             set(box_key, @@());
427             set(int_key, @42);
428         }
429     }
430
431     #[test]
432     fn test_tls_overwrite_multiple_types() {
433         static str_key: Key<@~str> = &Key;
434         static box_key: Key<@@()> = &Key;
435         static int_key: Key<@int> = &Key;
436         do task::spawn {
437             set(str_key, @~"string data");
438             set(int_key, @42);
439             // This could cause a segfault if overwriting-destruction is done
440             // with the crazy polymorphic transmute rather than the provided
441             // finaliser.
442             set(int_key, @31337);
443         }
444     }
445
446     #[test]
447     #[should_fail]
448     fn test_tls_cleanup_on_failure() {
449         static str_key: Key<@~str> = &Key;
450         static box_key: Key<@@()> = &Key;
451         static int_key: Key<@int> = &Key;
452         set(str_key, @~"parent data");
453         set(box_key, @@());
454         do task::spawn {
455             // spawn_linked
456             set(str_key, @~"string data");
457             set(box_key, @@());
458             set(int_key, @42);
459             fail!();
460         }
461         // Not quite nondeterministic.
462         set(int_key, @31337);
463         fail!();
464     }
465
466     #[test]
467     fn test_static_pointer() {
468         static key: Key<@&'static int> = &Key;
469         static VALUE: int = 0;
470         let v: @&'static int = @&VALUE;
471         set(key, v);
472     }
473
474     #[test]
475     fn test_owned() {
476         static key: Key<~int> = &Key;
477         set(key, ~1);
478
479         do get(key) |v| {
480             do get(key) |v| {
481                 do get(key) |v| {
482                     assert_eq!(**v.unwrap(), 1);
483                 }
484                 assert_eq!(**v.unwrap(), 1);
485             }
486             assert_eq!(**v.unwrap(), 1);
487         }
488         set(key, ~2);
489         do get(key) |v| {
490             assert_eq!(**v.unwrap(), 2);
491         }
492     }
493
494     #[test]
495     fn test_get_mut() {
496         static key: Key<int> = &Key;
497         set(key, 1);
498
499         do get_mut(key) |v| {
500             *v.unwrap() = 2;
501         }
502
503         do get(key) |v| {
504             assert_eq!(*v.unwrap(), 2);
505         }
506     }
507
508     #[test]
509     fn test_same_key_type() {
510         static key1: Key<int> = &Key;
511         static key2: Key<int> = &Key;
512         static key3: Key<int> = &Key;
513         static key4: Key<int> = &Key;
514         static key5: Key<int> = &Key;
515         set(key1, 1);
516         set(key2, 2);
517         set(key3, 3);
518         set(key4, 4);
519         set(key5, 5);
520
521         get(key1, |x| assert_eq!(*x.unwrap(), 1));
522         get(key2, |x| assert_eq!(*x.unwrap(), 2));
523         get(key3, |x| assert_eq!(*x.unwrap(), 3));
524         get(key4, |x| assert_eq!(*x.unwrap(), 4));
525         get(key5, |x| assert_eq!(*x.unwrap(), 5));
526     }
527
528     #[test]
529     #[should_fail]
530     fn test_nested_get_set1() {
531         static key: Key<int> = &Key;
532         set(key, 4);
533         do get(key) |_| {
534             set(key, 4);
535         }
536     }
537
538     #[test]
539     #[should_fail]
540     fn test_nested_get_mut2() {
541         static key: Key<int> = &Key;
542         set(key, 4);
543         do get(key) |_| {
544             get_mut(key, |_| {})
545         }
546     }
547
548     #[test]
549     #[should_fail]
550     fn test_nested_get_mut3() {
551         static key: Key<int> = &Key;
552         set(key, 4);
553         do get_mut(key) |_| {
554             get(key, |_| {})
555         }
556     }
557
558     #[test]
559     #[should_fail]
560     fn test_nested_get_mut4() {
561         static key: Key<int> = &Key;
562         set(key, 4);
563         do get_mut(key) |_| {
564             get_mut(key, |_| {})
565         }
566     }
567 }