(index<- )        ./libstd/rt/local_ptr.rs

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Fri May  9 13:02:28 2014
   1  // Copyright 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  //! Access to a single thread-local pointer.
  12  //!
  13  //! The runtime will use this for storing Box<Task>.
  14  //!
  15  //! FIXME: Add runtime checks for usage of inconsistent pointer types.
  16  //! and for overwriting an existing pointer.
  17  
  18  #![allow(dead_code)]
  19  
  20  use cast;
  21  use ops::{Drop, Deref, DerefMut};
  22  use owned::Box;
  23  use ptr::RawPtr;
  24  
  25  #[cfg(windows)]               // mingw-w32 doesn't like thread_local things
  26  #[cfg(target_os = "android")] // see #10686
  27  pub use self::native::{init, cleanup, put, take, try_take, unsafe_take, exists,
  28                         unsafe_borrow, try_unsafe_borrow};
  29  
  30  #[cfg(not(windows), not(target_os = "android"))]
  31  pub use self::compiled::{init, cleanup, put, take, try_take, unsafe_take, exists,
  32                           unsafe_borrow, try_unsafe_borrow};
  33  
  34  /// Encapsulates a borrowed value. When this value goes out of scope, the
  35  /// pointer is returned.
  36  pub struct Borrowed<T> {
  37      val: *(),
  38  }
  39  
  40  #[unsafe_destructor]
  41  impl<T> Drop for Borrowed<T> {
  42      fn drop(&mut self) {
  43          unsafe {
  44              if self.val.is_null() {
  45                  rtabort!("Aiee, returning null borrowed object!");
  46              }
  47              let valBox<T> = cast::transmute(self.val);
  48              put::<T>(val);
  49              rtassert!(exists());
  50          }
  51      }
  52  }
  53  
  54  impl<T> Deref<T> for Borrowed<T> {
  55      fn deref<'a>(&'a self) -> &'a T {
  56          unsafe { &*(self.val as *T) }
  57      }
  58  }
  59  
  60  impl<T> DerefMut<T> for Borrowed<T> {
  61      fn deref_mut<'a>(&'a mut self) -> &'a mut T {
  62          unsafe { &mut *(self.val as *mut T) }
  63      }
  64  }
  65  
  66  /// Borrow the thread-local value from thread-local storage.
  67  /// While the value is borrowed it is not available in TLS.
  68  ///
  69  /// # Safety note
  70  ///
  71  /// Does not validate the pointer type.
  72  #[inline]
  73  pub unsafe fn borrow<T>() -> Borrowed<T> {
  74      let val*() = cast::transmute(take::<T>());
  75      Borrowed {
  76          val: val,
  77      }
  78  }
  79  
  80  /// Compiled implementation of accessing the runtime local pointer. This is
  81  /// implemented using LLVM's thread_local attribute which isn't necessarily
  82  /// working on all platforms. This implementation is faster, however, so we use
  83  /// it wherever possible.
  84  #[cfg(not(windows), not(target_os = "android"))]
  85  pub mod compiled {
  86      use cast;
  87      use option::{Option, Some, None};
  88      use owned::Box;
  89      use ptr::RawPtr;
  90  
  91      #[cfg(test)]
  92      pub use realstd::rt::shouldnt_be_public::RT_TLS_PTR;
  93  
  94      #[cfg(not(test))]
  95      #[thread_local]
  96      pub static mut RT_TLS_PTR: *mut u8 = 0 as *mut u8;
  97  
  98      pub fn init() {}
  99  
 100      pub unsafe fn cleanup() {}
 101  
 102      // Rationale for all of these functions being inline(never)
 103      //
 104      // The #[thread_local] annotation gets propagated all the way through to
 105      // LLVM, meaning the global is specially treated by LLVM to lower it to an
 106      // efficient sequence of instructions. This also involves dealing with fun
 107      // stuff in object files and whatnot. Regardless, it turns out this causes
 108      // trouble with green threads and lots of optimizations turned on. The
 109      // following case study was done on linux x86_64, but I would imagine that
 110      // other platforms are similar.
 111      //
 112      // On linux, the instruction sequence for loading the tls pointer global
 113      // looks like:
 114      //
 115      //      mov %fs:0x0, %rax
 116      //      mov -0x8(%rax), %rbx
 117      //
 118      // This code leads me to believe that (%fs:0x0) is a table, and then the
 119      // table contains the TLS values for the process. Hence, the slot at offset
 120      // -0x8 is the task TLS pointer. This leads us to the conclusion that this
 121      // table is the actual thread local part of each thread. The kernel sets up
 122      // the fs segment selector to point at the right region of memory for each
 123      // thread.
 124      //
 125      // Optimizations lead me to believe that this code is lowered to these
 126      // instructions in the LLVM codegen passes, because you'll see code like
 127      // this when everything is optimized:
 128      //
 129      //      mov %fs:0x0, %r14
 130      //      mov -0x8(%r14), %rbx
 131      //      // do something with %rbx, the rust Task pointer
 132      //
 133      //      ... // <- do more things
 134      //
 135      //      mov -0x8(%r14), %rbx
 136      //      // do something else with %rbx
 137      //
 138      // Note that the optimization done here is that the first load is not
 139      // duplicated during the lower instructions. This means that the %fs:0x0
 140      // memory location is only dereferenced once.
 141      //
 142      // Normally, this is actually a good thing! With green threads, however,
 143      // it's very possible for the code labeled "do more things" to context
 144      // switch to another thread. If this happens, then we *must* re-load %fs:0x0
 145      // because it's changed (we're on a different thread). If we don't re-load
 146      // the table location, then we'll be reading the original thread's TLS
 147      // values, not our thread's TLS values.
 148      //
 149      // Hence, we never inline these functions. By never inlining, we're
 150      // guaranteed that loading the table is a local decision which is forced to
 151      // *always* happen.
 152  
 153      /// Give a pointer to thread-local storage.
 154      ///
 155      /// # Safety note
 156      ///
 157      /// Does not validate the pointer type.
 158      #[inline(never)] // see comments above
 159      pub unsafe fn put<T>(schedBox<T>) {
 160          RT_TLS_PTR = cast::transmute(sched)
 161      }
 162  
 163      /// Take ownership of a pointer from thread-local storage.
 164      ///
 165      /// # Safety note
 166      ///
 167      /// Does not validate the pointer type.
 168      #[inline(never)] // see comments above
 169      pub unsafe fn take<T>() -> Box<T> {
 170          let ptr = RT_TLS_PTR;
 171          rtassert!(!ptr.is_null());
 172          let ptrBox<T> = cast::transmute(ptr);
 173          // can't use `as`, due to type not matching with `cfg(test)`
 174          RT_TLS_PTR = cast::transmute(0);
 175          ptr
 176      }
 177  
 178      /// Optionally take ownership of a pointer from thread-local storage.
 179      ///
 180      /// # Safety note
 181      ///
 182      /// Does not validate the pointer type.
 183      #[inline(never)] // see comments above
 184      pub unsafe fn try_take<T>() -> Option<Box<T>> {
 185          let ptr = RT_TLS_PTR;
 186          if ptr.is_null() {
 187              None
 188          } else {
 189              let ptrBox<T> = cast::transmute(ptr);
 190              // can't use `as`, due to type not matching with `cfg(test)`
 191              RT_TLS_PTR = cast::transmute(0);
 192              Some(ptr)
 193          }
 194      }
 195  
 196      /// Take ownership of a pointer from thread-local storage.
 197      ///
 198      /// # Safety note
 199      ///
 200      /// Does not validate the pointer type.
 201      /// Leaves the old pointer in TLS for speed.
 202      #[inline(never)] // see comments above
 203      pub unsafe fn unsafe_take<T>() -> Box<T> {
 204          cast::transmute(RT_TLS_PTR)
 205      }
 206  
 207      /// Check whether there is a thread-local pointer installed.
 208      #[inline(never)] // see comments above
 209      pub fn exists() -> bool {
 210          unsafe {
 211              RT_TLS_PTR.is_not_null()
 212          }
 213      }
 214  
 215      #[inline(never)] // see comments above
 216      pub unsafe fn unsafe_borrow<T>() -> *mut T {
 217          if RT_TLS_PTR.is_null() {
 218              rtabort!("thread-local pointer is null. bogus!");
 219          }
 220          RT_TLS_PTR as *mut T
 221      }
 222  
 223      #[inline(never)] // see comments above
 224      pub unsafe fn try_unsafe_borrow<T>() -> Option<*mut T> {
 225          if RT_TLS_PTR.is_null() {
 226              None
 227          } else {
 228              Some(RT_TLS_PTR as *mut T)
 229          }
 230      }
 231  }
 232  
 233  /// Native implementation of having the runtime thread-local pointer. This
 234  /// implementation uses the `thread_local_storage` module to provide a
 235  /// thread-local value.
 236  pub mod native {
 237      use cast;
 238      use option::{Option, Some, None};
 239      use owned::Box;
 240      use ptr;
 241      use ptr::RawPtr;
 242      use tls = rt::thread_local_storage;
 243  
 244      static mut RT_TLS_KEY: tls::Key = -1;
 245  
 246      /// Initialize the TLS key. Other ops will fail if this isn't executed
 247      /// first.
 248      pub fn init() {
 249          unsafe {
 250              tls::create(&mut RT_TLS_KEY);
 251          }
 252      }
 253  
 254      pub unsafe fn cleanup() {
 255          rtassert!(RT_TLS_KEY != -1);
 256          tls::destroy(RT_TLS_KEY);
 257      }
 258  
 259      /// Give a pointer to thread-local storage.
 260      ///
 261      /// # Safety note
 262      ///
 263      /// Does not validate the pointer type.
 264      #[inline]
 265      pub unsafe fn put<T>(schedBox<T>) {
 266          let key = tls_key();
 267          let void_ptr*mut u8 = cast::transmute(sched);
 268          tls::set(key, void_ptr);
 269      }
 270  
 271      /// Take ownership of a pointer from thread-local storage.
 272      ///
 273      /// # Safety note
 274      ///
 275      /// Does not validate the pointer type.
 276      #[inline]
 277      pub unsafe fn take<T>() -> Box<T> {
 278          let key = tls_key();
 279          let void_ptr*mut u8 = tls::get(key);
 280          if void_ptr.is_null() {
 281              rtabort!("thread-local pointer is null. bogus!");
 282          }
 283          let ptrBox<T> = cast::transmute(void_ptr);
 284          tls::set(key, ptr::mut_null());
 285          return ptr;
 286      }
 287  
 288      /// Optionally take ownership of a pointer from thread-local storage.
 289      ///
 290      /// # Safety note
 291      ///
 292      /// Does not validate the pointer type.
 293      #[inline]
 294      pub unsafe fn try_take<T>() -> Option<Box<T>> {
 295          match maybe_tls_key() {
 296              Some(key) => {
 297                  let void_ptr*mut u8 = tls::get(key);
 298                  if void_ptr.is_null() {
 299                      None
 300                  } else {
 301                      let ptrBox<T> = cast::transmute(void_ptr);
 302                      tls::set(key, ptr::mut_null());
 303                      Some(ptr)
 304                  }
 305              }
 306              None => None
 307          }
 308      }
 309  
 310      /// Take ownership of a pointer from thread-local storage.
 311      ///
 312      /// # Safety note
 313      ///
 314      /// Does not validate the pointer type.
 315      /// Leaves the old pointer in TLS for speed.
 316      #[inline]
 317      pub unsafe fn unsafe_take<T>() -> Box<T> {
 318          let key = tls_key();
 319          let void_ptr*mut u8 = tls::get(key);
 320          if void_ptr.is_null() {
 321              rtabort!("thread-local pointer is null. bogus!");
 322          }
 323          let ptrBox<T> = cast::transmute(void_ptr);
 324          return ptr;
 325      }
 326  
 327      /// Check whether there is a thread-local pointer installed.
 328      pub fn exists() -> bool {
 329          unsafe {
 330              match maybe_tls_key() {
 331                  Some(key) => tls::get(key).is_not_null(),
 332                  None => false
 333              }
 334          }
 335      }
 336  
 337      /// Borrow a mutable reference to the thread-local value
 338      ///
 339      /// # Safety Note
 340      ///
 341      /// Because this leaves the value in thread-local storage it is possible
 342      /// For the Scheduler pointer to be aliased
 343      pub unsafe fn unsafe_borrow<T>() -> *mut T {
 344          let key = tls_key();
 345          let void_ptr = tls::get(key);
 346          if void_ptr.is_null() {
 347              rtabort!("thread-local pointer is null. bogus!");
 348          }
 349          void_ptr as *mut T
 350      }
 351  
 352      pub unsafe fn try_unsafe_borrow<T>() -> Option<*mut T> {
 353          match maybe_tls_key() {
 354              Some(key) => {
 355                  let void_ptr = tls::get(key);
 356                  if void_ptr.is_null() {
 357                      None
 358                  } else {
 359                      Some(void_ptr as *mut T)
 360                  }
 361              }
 362              None => None
 363          }
 364      }
 365  
 366      #[inline]
 367      fn tls_key() -> tls::Key {
 368          match maybe_tls_key() {
 369              Some(key) => key,
 370              None => rtabort!("runtime tls key not initialized")
 371          }
 372      }
 373  
 374      #[inline]
 375      #[cfg(not(test))]
 376      #[allow(visible_private_types)]
 377      pub fn maybe_tls_key() -> Option<tls::Key> {
 378          unsafe {
 379              // NB: This is a little racy because, while the key is
 380              // initialized under a mutex and it's assumed to be initialized
 381              // in the Scheduler ctor by any thread that needs to use it,
 382              // we are not accessing the key under a mutex.  Threads that
 383              // are not using the new Scheduler but still *want to check*
 384              // whether they are running under a new Scheduler may see a 0
 385              // value here that is in the process of being initialized in
 386              // another thread. I think this is fine since the only action
 387              // they could take if it was initialized would be to check the
 388              // thread-local value and see that it's not set.
 389              if RT_TLS_KEY != -1 {
 390                  return Some(RT_TLS_KEY);
 391              } else {
 392                  return None;
 393              }
 394          }
 395      }
 396  
 397      #[inline] #[cfg(test)]
 398      pub fn maybe_tls_key() -> Option<tls::Key> {
 399          use realstd;
 400          unsafe {
 401              cast::transmute(realstd::rt::shouldnt_be_public::maybe_tls_key())
 402          }
 403      }
 404  }


libstd/rt/local_ptr.rs:159:4-159:4 -fn- definition:
    pub unsafe fn put<T>(sched: Box<T>) {
        RT_TLS_PTR = cast::transmute(sched)
    }
references:- 2
libstd/rt/local.rs:
30:     #[inline]
31:     fn put(value: Box<Task>) { unsafe { local_ptr::put(value) } }
32:     #[inline]
libstd/rt/local_ptr.rs:
47:             let val: Box<T> = cast::transmute(self.val);
48:             put::<T>(val);
49:             rtassert!(exists());


libstd/rt/local_ptr.rs:169:4-169:4 -fn- definition:
    pub unsafe fn take<T>() -> Box<T> {
        let ptr = RT_TLS_PTR;
        rtassert!(!ptr.is_null());
references:- 2
73: pub unsafe fn borrow<T>() -> Borrowed<T> {
74:     let val: *() = cast::transmute(take::<T>());
75:     Borrowed {
libstd/rt/local.rs:
32:     #[inline]
33:     fn take() -> Box<Task> { unsafe { local_ptr::take() } }
34:     #[inline]


libstd/rt/local_ptr.rs:209:4-209:4 -fn- definition:
    pub fn exists() -> bool {
        unsafe {
            RT_TLS_PTR.is_not_null()
references:- 2
libstd/rt/local.rs:
35:     fn try_take() -> Option<Box<Task>> { unsafe { local_ptr::try_take() } }
36:     fn exists(_: Option<Task>) -> bool { local_ptr::exists() }
37:     #[inline]
libstd/rt/local_ptr.rs:
48:             put::<T>(val);
49:             rtassert!(exists());
50:         }


libstd/rt/local_ptr.rs:35:25-35:25 -struct- definition:
/// pointer is returned.
pub struct Borrowed<T> {
    val: *(),
references:- 14
74:     let val: *() = cast::transmute(take::<T>());
75:     Borrowed {
76:         val: val,
libstd/task.rs:
276:     use rt::task::Task;
277:     Local::borrow(None::<Task>).unwinder.unwinding()
278: }
libstd/io/stdio.rs:
231:             // and only then drop the previous handle.
232:             let prev = replace(&mut Local::borrow(None::<Task>).stdout, my_stdout);
233:             drop(prev);
libstd/rt/task.rs:
132:                     let stderr = task.stderr.take();
133:                     let stdout = task.stdout.take();
134:                     drop(task);
--
163:                 let storage_map = {
164:                     let &LocalStorage(ref mut optmap) = &mut task.storage;
165:                     optmap.take()
libstd/rt/local.rs:
37:     #[inline]
38:     fn borrow(_: Option<Task>) -> local_ptr::Borrowed<Task> {
39:         unsafe {
libstd/rt/local_heap.rs:
321: pub fn live_allocs() -> *mut Box {
322:     Local::borrow(None::<Task>).heap.live_allocs
323: }
libstd/rt/local_ptr.rs:
60: impl<T> DerefMut<T> for Borrowed<T> {
61:     fn deref_mut<'a>(&'a mut self) -> &'a mut T {


libstd/rt/local_ptr.rs:367:4-367:4 -fn- definition:
    fn tls_key() -> tls::Key {
        match maybe_tls_key() {
            Some(key) => key,
references:- 4
343:     pub unsafe fn unsafe_borrow<T>() -> *mut T {
344:         let key = tls_key();
345:         let void_ptr = tls::get(key);


libstd/rt/local_ptr.rs:377:4-377:4 -fn- definition:
    pub fn maybe_tls_key() -> Option<tls::Key> {
        unsafe {
            // NB: This is a little racy because, while the key is
references:- 4
294:     pub unsafe fn try_take<T>() -> Option<Box<T>> {
295:         match maybe_tls_key() {
296:             Some(key) => {
--
367:     fn tls_key() -> tls::Key {
368:         match maybe_tls_key() {
369:             Some(key) => key,