(index<- )        ./libstd/rt/thread.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-2014 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  //! Native os-thread management
  12  //!
  13  //! This modules contains bindings necessary for managing OS-level threads.
  14  //! These functions operate outside of the rust runtime, creating threads
  15  //! which are not used for scheduling in any way.
  16  
  17  #![allow(non_camel_case_types)]
  18  #![allow(unsigned_negate)]
  19  
  20  use cast;
  21  use kinds::Send;
  22  use libc;
  23  use ops::Drop;
  24  use option::{Option, Some, None};
  25  use owned::Box;
  26  use uint;
  27  
  28  type StartFn = extern "C" fn(*libc::c_void) -> imp::rust_thread_return;
  29  
  30  /// This struct represents a native thread's state. This is used to join on an
  31  /// existing thread created in the join-able state.
  32  pub struct Thread<T> {
  33      native: imp::rust_thread,
  34      joined: bool,
  35      packet: Box<Option<T>>,
  36  }
  37  
  38  static DEFAULT_STACK_SIZE: uint = 1024 * 1024;
  39  
  40  // This is the starting point of rust os threads. The first thing we do
  41  // is make sure that we don't trigger __morestack (also why this has a
  42  // no_split_stack annotation), and then we extract the main function
  43  // and invoke it.
  44  #[no_split_stack]
  45  extern fn thread_start(main: *libc::c_void) -> imp::rust_thread_return {
  46      use rt::stack;
  47      unsafe {
  48          stack::record_stack_bounds(0, uint::MAX);
  49          let fBox<proc()> = cast::transmute(main);
  50          (*f)();
  51          cast::transmute(0 as imp::rust_thread_return)
  52      }
  53  }
  54  
  55  // There are two impl blocks b/c if T were specified at the top then it's just a
  56  // pain to specify a type parameter on Thread::spawn (which doesn't need the
  57  // type parameter).
  58  impl Thread<()> {
  59  
  60      /// Starts execution of a new OS thread.
  61      ///
  62      /// This function will not wait for the thread to join, but a handle to the
  63      /// thread will be returned.
  64      ///
  65      /// Note that the handle returned is used to acquire the return value of the
  66      /// procedure `main`. The `join` function will wait for the thread to finish
  67      /// and return the value that `main` generated.
  68      ///
  69      /// Also note that the `Thread` returned will *always* wait for the thread
  70      /// to finish executing. This means that even if `join` is not explicitly
  71      /// called, when the `Thread` falls out of scope its destructor will block
  72      /// waiting for the OS thread.
  73      pub fn start<T: Send>(mainproc():Send -> T) -> Thread<T> {
  74          Thread::start_stack(DEFAULT_STACK_SIZE, main)
  75      }
  76  
  77      /// Performs the same functionality as `start`, but specifies an explicit
  78      /// stack size for the new thread.
  79      pub fn start_stack<T: Send>(stackuint, mainproc():Send -> T) -> Thread<T> {
  80  
  81          // We need the address of the packet to fill in to be stable so when
  82          // `main` fills it in it's still valid, so allocate an extra box to do
  83          // so.
  84          let packet = box None;
  85          let packet2*mut Option<T> = unsafe {
  86              *cast::transmute::<&Box<Option<T>>, **mut Option<T>>(&packet)
  87          };
  88          let main = proc() unsafe { *packet2 = Some(main()); };
  89          let native = unsafe { imp::create(stack, box main) };
  90  
  91          Thread {
  92              native: native,
  93              joined: false,
  94              packet: packet,
  95          }
  96      }
  97  
  98      /// This will spawn a new thread, but it will not wait for the thread to
  99      /// finish, nor is it possible to wait for the thread to finish.
 100      ///
 101      /// This corresponds to creating threads in the 'detached' state on unix
 102      /// systems. Note that platforms may not keep the main program alive even if
 103      /// there are detached thread still running around.
 104      pub fn spawn(mainproc():Send) {
 105          Thread::spawn_stack(DEFAULT_STACK_SIZE, main)
 106      }
 107  
 108      /// Performs the same functionality as `spawn`, but explicitly specifies a
 109      /// stack size for the new thread.
 110      pub fn spawn_stack(stackuint, mainproc():Send) {
 111          unsafe {
 112              let handle = imp::create(stack, box main);
 113              imp::detach(handle);
 114          }
 115      }
 116  
 117      /// Relinquishes the CPU slot that this OS-thread is currently using,
 118      /// allowing another thread to run for awhile.
 119      pub fn yield_now() {
 120          unsafe { imp::yield_now(); }
 121      }
 122  }
 123  
 124  impl<T: Send> Thread<T> {
 125      /// Wait for this thread to finish, returning the result of the thread's
 126      /// calculation.
 127      pub fn join(mut self) -> T {
 128          assert!(!self.joined);
 129          unsafe { imp::join(self.native) };
 130          self.joined = true;
 131          assert!(self.packet.is_some());
 132          self.packet.take_unwrap()
 133      }
 134  }
 135  
 136  #[unsafe_destructor]
 137  impl<T: Send> Drop for Thread<T> {
 138      fn drop(&mut self) {
 139          // This is required for correctness. If this is not done then the thread
 140          // would fill in a return box which no longer exists.
 141          if !self.joined {
 142              unsafe { imp::join(self.native) };
 143          }
 144      }
 145  }
 146  
 147  #[cfg(windows)]
 148  mod imp {
 149      use cast;
 150      use cmp;
 151      use kinds::Send;
 152      use libc;
 153      use libc::types::os::arch::extra::{LPSECURITY_ATTRIBUTES, SIZE_T, BOOL,
 154                                         LPVOID, DWORD, LPDWORD, HANDLE};
 155      use os;
 156      use owned::Box;
 157      use ptr;
 158      use rt::stack::RED_ZONE;
 159  
 160      pub type rust_thread = HANDLE;
 161      pub type rust_thread_return = DWORD;
 162  
 163      pub unsafe fn create(stack: uint, p: Box<proc():Send>) -> rust_thread {
 164          let arg: *mut libc::c_void = cast::transmute(p);
 165          // FIXME On UNIX, we guard against stack sizes that are too small but
 166          // that's because pthreads enforces that stacks are at least
 167          // PTHREAD_STACK_MIN bytes big.  Windows has no such lower limit, it's
 168          // just that below a certain threshold you can't do anything useful.
 169          // That threshold is application and architecture-specific, however.
 170          // For now, the only requirement is that it's big enough to hold the
 171          // red zone.  Round up to the next 64 kB because that's what the NT
 172          // kernel does, might as well make it explicit.  With the current
 173          // 20 kB red zone, that makes for a 64 kB minimum stack.
 174          let stack_size = (cmp::max(stack, RED_ZONE) + 0xfffe) & (-0xfffe - 1);
 175          let ret = CreateThread(ptr::mut_null(), stack_size as libc::size_t,
 176                                 super::thread_start, arg, 0, ptr::mut_null());
 177  
 178          if ret as uint == 0 {
 179              // be sure to not leak the closure
 180              let _p: Box<proc():Send> = cast::transmute(arg);
 181              fail!("failed to spawn native thread: {}", os::last_os_error());
 182          }
 183          return ret;
 184      }
 185  
 186      pub unsafe fn join(native: rust_thread) {
 187          use libc::consts::os::extra::INFINITE;
 188          WaitForSingleObject(native, INFINITE);
 189      }
 190  
 191      pub unsafe fn detach(native: rust_thread) {
 192          assert!(libc::CloseHandle(native) != 0);
 193      }
 194  
 195      pub unsafe fn yield_now() {
 196          // This function will return 0 if there are no other threads to execute,
 197          // but this also means that the yield was useless so this isn't really a
 198          // case that needs to be worried about.
 199          SwitchToThread();
 200      }
 201  
 202      extern "system" {
 203          fn CreateThread(lpThreadAttributes: LPSECURITY_ATTRIBUTES,
 204                          dwStackSize: SIZE_T,
 205                          lpStartAddress: super::StartFn,
 206                          lpParameter: LPVOID,
 207                          dwCreationFlags: DWORD,
 208                          lpThreadId: LPDWORD) -> HANDLE;
 209          fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD;
 210          fn SwitchToThread() -> BOOL;
 211      }
 212  }
 213  
 214  #[cfg(unix)]
 215  mod imp {
 216      use cast;
 217      use cmp;
 218      use kinds::Send;
 219      use libc::consts::os::posix01::{PTHREAD_CREATE_JOINABLE, PTHREAD_STACK_MIN};
 220      use libc;
 221      use mem;
 222      use os;
 223      use owned::Box;
 224      use ptr;
 225      use rt::stack::RED_ZONE;
 226  
 227      pub type rust_thread = libc::pthread_t;
 228      pub type rust_thread_return = *u8;
 229  
 230      pub unsafe fn create(stack: uint, pBox<proc():Send>) -> rust_thread {
 231          let mut nativelibc::pthread_t = mem::uninit();
 232          let mut attrlibc::pthread_attr_t = mem::uninit();
 233          assert_eq!(pthread_attr_init(&mut attr), 0);
 234          assert_eq!(pthread_attr_setdetachstate(&mut attr,
 235                                                 PTHREAD_CREATE_JOINABLE), 0);
 236  
 237          // Reserve room for the red zone, the runtime's stack of last resort.
 238          let stack_size = cmp::max(stack, RED_ZONE + min_stack_size(&attr) as uint);
 239          match pthread_attr_setstacksize(&mut attr, stack_size as libc::size_t) {
 240              0 => {
 241              },
 242              libc::EINVAL => {
 243                  // EINVAL means |stack_size| is either too small or not a
 244                  // multiple of the system page size.  Because it's definitely
 245                  // >= PTHREAD_STACK_MIN, it must be an alignment issue.
 246                  // Round up to the neareast page and try again.
 247                  let page_size = os::page_size();
 248                  let stack_size = (stack_size + page_size - 1) & (-(page_size - 1) - 1);
 249                  assert_eq!(pthread_attr_setstacksize(&mut attr, stack_size as libc::size_t), 0);
 250              },
 251              errno => {
 252                  // This cannot really happen.
 253                  fail!("pthread_attr_setstacksize() error: {} ({})", os::last_os_error(), errno);
 254              },
 255          };
 256  
 257          let arg*libc::c_void = cast::transmute(p);
 258          let ret = pthread_create(&mut native, &attr, super::thread_start, arg);
 259          assert_eq!(pthread_attr_destroy(&mut attr), 0);
 260  
 261          if ret != 0 {
 262              // be sure to not leak the closure
 263              let _pBox<proc():Send> = cast::transmute(arg);
 264              fail!("failed to spawn native thread: {}", os::last_os_error());
 265          }
 266          native
 267      }
 268  
 269      pub unsafe fn join(nativerust_thread) {
 270          assert_eq!(pthread_join(native, ptr::null()), 0);
 271      }
 272  
 273      pub unsafe fn detach(nativerust_thread) {
 274          assert_eq!(pthread_detach(native), 0);
 275      }
 276  
 277      #[cfg(target_os = "macos")]
 278      #[cfg(target_os = "android")]
 279      pub unsafe fn yield_now() { assert_eq!(sched_yield(), 0); }
 280  
 281      #[cfg(not(target_os = "macos"), not(target_os = "android"))]
 282      pub unsafe fn yield_now() { assert_eq!(pthread_yield(), 0); }
 283  
 284      // glibc >= 2.15 has a __pthread_get_minstack() function that returns
 285      // PTHREAD_STACK_MIN plus however many bytes are needed for thread-local
 286      // storage.  We need that information to avoid blowing up when a small stack
 287      // is created in an application with big thread-local storage requirements.
 288      // See #6233 for rationale and details.
 289      //
 290      // Link weakly to the symbol for compatibility with older versions of glibc.
 291      // Assumes that we've been dynamically linked to libpthread but that is
 292      // currently always the case.  Note that you need to check that the symbol
 293      // is non-null before calling it!
 294      #[cfg(target_os = "linux")]
 295      fn min_stack_size(attr: *libc::pthread_attr_t) -> libc::size_t {
 296          use ptr::RawPtr;
 297          type F = extern "C" unsafe fn(*libc::pthread_attr_t) -> libc::size_t;
 298          extern {
 299              #[linkage = "extern_weak"]
 300              static __pthread_get_minstack: *();
 301          }
 302          if __pthread_get_minstack.is_null() {
 303              PTHREAD_STACK_MIN
 304          } else {
 305              unsafe { cast::transmute::<*(), F>(__pthread_get_minstack)(attr) }
 306          }
 307      }
 308  
 309      // __pthread_get_minstack() is marked as weak but extern_weak linkage is
 310      // not supported on OS X, hence this kludge...
 311      #[cfg(not(target_os = "linux"))]
 312      fn min_stack_size(_: *libc::pthread_attr_t) -> libc::size_t {
 313          PTHREAD_STACK_MIN
 314      }
 315  
 316      extern {
 317          fn pthread_create(native: *mut libc::pthread_t,
 318                            attr: *libc::pthread_attr_t,
 319                            fsuper::StartFn,
 320                            value: *libc::c_void) -> libc::c_int;
 321          fn pthread_join(nativelibc::pthread_t,
 322                          value: **libc::c_void) -> libc::c_int;
 323          fn pthread_attr_init(attr: *mut libc::pthread_attr_t) -> libc::c_int;
 324          fn pthread_attr_destroy(attr: *mut libc::pthread_attr_t) -> libc::c_int;
 325          fn pthread_attr_setstacksize(attr: *mut libc::pthread_attr_t,
 326                                       stack_sizelibc::size_t) -> libc::c_int;
 327          fn pthread_attr_setdetachstate(attr: *mut libc::pthread_attr_t,
 328                                         statelibc::c_int) -> libc::c_int;
 329          fn pthread_detach(threadlibc::pthread_t) -> libc::c_int;
 330  
 331          #[cfg(target_os = "macos")]
 332          #[cfg(target_os = "android")]
 333          fn sched_yield() -> libc::c_int;
 334          #[cfg(not(target_os = "macos"), not(target_os = "android"))]
 335          fn pthread_yield() -> libc::c_int;
 336      }
 337  }
 338  
 339  #[cfg(test)]
 340  mod tests {
 341      use super::Thread;
 342  
 343      #[test]
 344      fn smoke() { Thread::start(proc (){}).join(); }
 345  
 346      #[test]
 347      fn data() { assert_eq!(Thread::start(proc () { 1 }).join(), 1); }
 348  
 349      #[test]
 350      fn detached() { Thread::spawn(proc () {}) }
 351  
 352      #[test]
 353      fn small_stacks() {
 354          assert_eq!(42, Thread::start_stack(0, proc () 42).join());
 355          assert_eq!(42, Thread::start_stack(1, proc () 42).join());
 356      }
 357  }
 358  


libstd/rt/thread.rs:31:52-31:52 -struct- definition:
/// existing thread created in the join-able state.
pub struct Thread<T> {
    native: imp::rust_thread,
references:- 6
91:         Thread {
92:             native: native,
--
124: impl<T: Send> Thread<T> {
125:     /// Wait for this thread to finish, returning the result of the thread's
--
137: impl<T: Send> Drop for Thread<T> {
138:     fn drop(&mut self) {


libstd/rt/thread.rs:269:4-269:4 -fn- definition:
    pub unsafe fn join(native: rust_thread) {
        assert_eq!(pthread_join(native, ptr::null()), 0);
    }
references:- 2
128:         assert!(!self.joined);
129:         unsafe { imp::join(self.native) };
130:         self.joined = true;
--
141:         if !self.joined {
142:             unsafe { imp::join(self.native) };
143:         }


libstd/rt/thread.rs:227:4-227:4 -NK_AS_STR_TODO- definition:
    pub type rust_thread = libc::pthread_t;
    pub type rust_thread_return = *u8;
    pub unsafe fn create(stack: uint, p: Box<proc():Send>) -> rust_thread {
references:- 4
230:     pub unsafe fn create(stack: uint, p: Box<proc():Send>) -> rust_thread {
231:         let mut native: libc::pthread_t = mem::uninit();
--
273:     pub unsafe fn detach(native: rust_thread) {
274:         assert_eq!(pthread_detach(native), 0);


libstd/rt/thread.rs:228:4-228:4 -NK_AS_STR_TODO- definition:
    pub type rust_thread_return = *u8;
    pub unsafe fn create(stack: uint, p: Box<proc():Send>) -> rust_thread {
        let mut native: libc::pthread_t = mem::uninit();
references:- 3
28: type StartFn = extern "C" fn(*libc::c_void) -> imp::rust_thread_return;
--
50:         (*f)();
51:         cast::transmute(0 as imp::rust_thread_return)
52:     }


libstd/rt/thread.rs:230:4-230:4 -fn- definition:
    pub unsafe fn create(stack: uint, p: Box<proc():Send>) -> rust_thread {
        let mut native: libc::pthread_t = mem::uninit();
        let mut attr: libc::pthread_attr_t = mem::uninit();
references:- 2
88:         let main = proc() unsafe { *packet2 = Some(main()); };
89:         let native = unsafe { imp::create(stack, box main) };
--
111:         unsafe {
112:             let handle = imp::create(stack, box main);
113:             imp::detach(handle);