(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>(keyKey<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 selfdataOption<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 dBox<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 traw::TraitObject = unsafe { cast::transmute(data) };
 192                      let allocBox<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:- 2
121: 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:- 3
121: 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:- 2
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: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:- 5
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)
--
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:- 2
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)| {


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:- 3
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;
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:- 3
223:     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:- 4
222:     /// ```
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) {