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.
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.
13 Task local data management
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.
20 To use, declare a static variable of the type you wish to store. The
21 initialization should be `&local_data::Key`. This is then the key to what you
27 static key_int: local_data::Key<int> = &local_data::Key;
28 static key_vector: local_data::Key<~[int]> = &local_data::Key;
30 local_data::set(key_int, 3);
31 local_data::get(key_int, |opt| assert_eq!(opt, Some(&3)));
33 local_data::set(key_vector, ~[4]);
34 local_data::get(key_int, |opt| assert_eq!(opt, Some(&~[4])));
37 Casting 'Arcane Sight' reveals an overwhelming aura of Transmutation
44 use task::local_data_priv::*;
46 #[cfg(test)] use task;
49 * Indexes a task-local data slot. This pointer is used for comparison to
50 * differentiate keys from one another. The actual type `T` is not used anywhere
51 * as a member of this type, except that it is parameterized with it to define
52 * the type of each key's value.
54 * The value of each Key is of the singleton enum KeyValue. These also have the
55 * same name as `Key` and their purpose is to take up space in the programs data
56 * sections to ensure that each value of the `Key` type points to a unique
59 pub type Key<T> = &'static KeyValue<T>;
61 pub enum KeyValue<T> { Key }
64 * Remove a task-local data value from the table, returning the
65 * reference that was originally created to insert it.
67 pub fn pop<T: 'static>(key: Key<T>) -> Option<T> {
68 unsafe { local_pop(Handle::new(), key) }
72 * Retrieve a task-local data value. It will also be kept alive in the
73 * table until explicitly removed.
75 pub fn get<T: 'static, U>(key: Key<T>, f: &fn(Option<&T>) -> U) -> U {
76 unsafe { local_get(Handle::new(), key, f) }
80 * Retrieve a mutable borrowed pointer to a task-local data value.
82 pub fn get_mut<T: 'static, U>(key: Key<T>, f: &fn(Option<&mut T>) -> U) -> U {
83 unsafe { local_get_mut(Handle::new(), key, f) }
87 * Store a value in task-local data. If this key already has a value,
88 * that value is overwritten (and its destructor is run).
90 pub fn set<T: 'static>(key: Key<T>, data: T) {
91 unsafe { local_set(Handle::new(), key, data) }
95 * Modify a task-local data value. If the function returns 'None', the
96 * data is removed (and its reference dropped).
98 pub fn modify<T: 'static>(key: Key<T>, f: &fn(Option<T>) -> Option<T>) {
100 match f(pop(::cast::unsafe_copy(&key))) {
101 Some(next) => { set(key, next); }
108 fn test_tls_multitask() {
109 static my_key: Key<@~str> = &Key;
110 set(my_key, @~"parent data");
112 // TLS shouldn't carry over.
113 assert!(get(my_key, |k| k.map(|&k| *k)).is_none());
114 set(my_key, @~"child data");
115 assert!(*(get(my_key, |k| k.map(|&k| *k)).unwrap()) ==
117 // should be cleaned up for us
119 // Must work multiple times
120 assert!(*(get(my_key, |k| k.map(|&k| *k)).unwrap()) == ~"parent data");
121 assert!(*(get(my_key, |k| k.map(|&k| *k)).unwrap()) == ~"parent data");
122 assert!(*(get(my_key, |k| k.map(|&k| *k)).unwrap()) == ~"parent data");
126 fn test_tls_overwrite() {
127 static my_key: Key<@~str> = &Key;
128 set(my_key, @~"first data");
129 set(my_key, @~"next data"); // Shouldn't leak.
130 assert!(*(get(my_key, |k| k.map(|&k| *k)).unwrap()) == ~"next data");
135 static my_key: Key<@~str> = &Key;
136 set(my_key, @~"weasel");
137 assert!(*(pop(my_key).unwrap()) == ~"weasel");
138 // Pop must remove the data from the map.
139 assert!(pop(my_key).is_none());
143 fn test_tls_modify() {
144 static my_key: Key<@~str> = &Key;
145 modify(my_key, |data| {
147 Some(@ref val) => fail!("unwelcome value: %s", *val),
148 None => Some(@~"first data")
151 modify(my_key, |data| {
153 Some(@~"first data") => Some(@~"next data"),
154 Some(@ref val) => fail!("wrong value: %s", *val),
155 None => fail!("missing value")
158 assert!(*(pop(my_key).unwrap()) == ~"next data");
162 fn test_tls_crust_automorestack_memorial_bug() {
163 // This might result in a stack-canary clobber if the runtime fails to
164 // set sp_limit to 0 when calling the cleanup extern - it might
165 // automatically jump over to the rust stack, which causes next_c_sp
166 // to get recorded as something within a rust stack segment. Then a
167 // subsequent upcall (esp. for logging, think vsnprintf) would run on
168 // a stack smaller than 1 MB.
169 static my_key: Key<@~str> = &Key;
171 set(my_key, @~"hax");
176 fn test_tls_multiple_types() {
177 static str_key: Key<@~str> = &Key;
178 static box_key: Key<@@()> = &Key;
179 static int_key: Key<@int> = &Key;
181 set(str_key, @~"string data");
188 fn test_tls_overwrite_multiple_types() {
189 static str_key: Key<@~str> = &Key;
190 static box_key: Key<@@()> = &Key;
191 static int_key: Key<@int> = &Key;
193 set(str_key, @~"string data");
195 // This could cause a segfault if overwriting-destruction is done
196 // with the crazy polymorphic transmute rather than the provided
198 set(int_key, @31337);
204 #[ignore(cfg(windows))]
205 fn test_tls_cleanup_on_failure() {
206 static str_key: Key<@~str> = &Key;
207 static box_key: Key<@@()> = &Key;
208 static int_key: Key<@int> = &Key;
209 set(str_key, @~"parent data");
213 set(str_key, @~"string data");
218 // Not quite nondeterministic.
219 set(int_key, @31337);
224 fn test_static_pointer() {
225 static key: Key<@&'static int> = &Key;
226 static VALUE: int = 0;
227 let v: @&'static int = @&VALUE;
233 static key: Key<~int> = &Key;
239 assert_eq!(**v.unwrap(), 1);
241 assert_eq!(**v.unwrap(), 1);
243 assert_eq!(**v.unwrap(), 1);
247 assert_eq!(**v.unwrap(), 2);
253 static key: Key<int> = &Key;
256 do get_mut(key) |v| {
261 assert_eq!(*v.unwrap(), 2);
266 fn test_same_key_type() {
267 static key1: Key<int> = &Key;
268 static key2: Key<int> = &Key;
269 static key3: Key<int> = &Key;
270 static key4: Key<int> = &Key;
271 static key5: Key<int> = &Key;
278 get(key1, |x| assert_eq!(*x.unwrap(), 1));
279 get(key2, |x| assert_eq!(*x.unwrap(), 2));
280 get(key3, |x| assert_eq!(*x.unwrap(), 3));
281 get(key4, |x| assert_eq!(*x.unwrap(), 4));
282 get(key5, |x| assert_eq!(*x.unwrap(), 5));
287 fn test_nested_get_set1() {
288 static key: Key<int> = &Key;
297 fn test_nested_get_mut2() {
298 static key: Key<int> = &Key;
307 fn test_nested_get_mut3() {
308 static key: Key<int> = &Key;
310 do get_mut(key) |_| {
317 fn test_nested_get_mut4() {
318 static key: Key<int> = &Key;
320 do get_mut(key) |_| {