about summary refs log tree commit diff
path: root/src/libstd/sys/unix/thread.rs
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2015-03-17 17:15:54 +0000
committerbors <bors@rust-lang.org>2015-03-17 17:15:54 +0000
commitbfac337daab9b86971bcb3db61382ac44f94621c (patch)
tree34bc72817ddffae38dde0fa30b8f35a0bc92e1d3 /src/libstd/sys/unix/thread.rs
parentc64d671671aea2e44ee7fc6eb00ee75fc30ed7b9 (diff)
parent04cf5344111c357ad80335b88709281bb4bfaa0a (diff)
downloadrust-bfac337daab9b86971bcb3db61382ac44f94621c.tar.gz
rust-bfac337daab9b86971bcb3db61382ac44f94621c.zip
Auto merge of #23330 - alexcrichton:thread-sleep, r=aturon
This function is the current replacement for `std::old_io::timer` which will
soon be deprecated. This function is unstable and has its own feature gate as it
does not yet have an RFC nor has it existed for very long.
Diffstat (limited to 'src/libstd/sys/unix/thread.rs')
-rw-r--r--src/libstd/sys/unix/thread.rs318
1 files changed, 137 insertions, 181 deletions
diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs
index b4002f266a1..04508294981 100644
--- a/src/libstd/sys/unix/thread.rs
+++ b/src/libstd/sys/unix/thread.rs
@@ -12,44 +12,30 @@
 
 use core::prelude::*;
 
-use io;
-use boxed;
-use boxed::Box;
 use cmp;
+use ffi::CString;
+use io;
+use libc::consts::os::posix01::PTHREAD_STACK_MIN;
+use libc;
 use mem;
 use ptr;
-use libc::consts::os::posix01::{PTHREAD_CREATE_JOINABLE, PTHREAD_STACK_MIN};
-use libc;
+use sys::os;
 use thunk::Thunk;
-use ffi::CString;
+use time::Duration;
 
 use sys_common::stack::RED_ZONE;
 use sys_common::thread::*;
 
 pub type rust_thread = libc::pthread_t;
-pub type rust_thread_return = *mut u8;
-pub type StartFn = extern "C" fn(*mut libc::c_void) -> rust_thread_return;
-
-#[no_stack_check]
-pub extern fn thread_start(main: *mut libc::c_void) -> rust_thread_return {
-    return start_thread(main);
-}
 
 #[cfg(all(not(target_os = "linux"),
           not(target_os = "macos"),
           not(target_os = "bitrig"),
           not(target_os = "openbsd")))]
 pub mod guard {
-    pub unsafe fn current() -> uint {
-        0
-    }
-
-    pub unsafe fn main() -> uint {
-        0
-    }
-
-    pub unsafe fn init() {
-    }
+    pub unsafe fn current() -> usize { 0 }
+    pub unsafe fn main() -> usize { 0 }
+    pub unsafe fn init() {}
 }
 
 
@@ -57,26 +43,22 @@ pub mod guard {
           target_os = "macos",
           target_os = "bitrig",
           target_os = "openbsd"))]
+#[allow(unused_imports)]
 pub mod guard {
-    use super::*;
-    #[cfg(any(target_os = "linux",
-              target_os = "android",
-              target_os = "bitrig",
-              target_os = "openbsd"))]
-    use mem;
-    #[cfg(any(target_os = "linux", target_os = "android"))]
-    use ptr;
-    use libc;
-    use libc::funcs::posix88::mman::{mmap};
+    use libc::{self, pthread_t};
+    use libc::funcs::posix88::mman::mmap;
     use libc::consts::os::posix88::{PROT_NONE,
                                     MAP_PRIVATE,
                                     MAP_ANON,
                                     MAP_FAILED,
                                     MAP_FIXED};
+    use mem;
+    use ptr;
+    use super::{pthread_self, pthread_attr_destroy};
+    use sys::os;
 
     // These are initialized in init() and only read from after
-    static mut PAGE_SIZE: uint = 0;
-    static mut GUARD_PAGE: uint = 0;
+    static mut GUARD_PAGE: usize = 0;
 
     #[cfg(any(target_os = "macos",
               target_os = "bitrig",
@@ -88,28 +70,16 @@ pub mod guard {
     #[cfg(any(target_os = "linux", target_os = "android"))]
     unsafe fn get_stack_start() -> *mut libc::c_void {
         let mut attr: libc::pthread_attr_t = mem::zeroed();
-        if pthread_getattr_np(pthread_self(), &mut attr) != 0 {
-            panic!("failed to get thread attributes");
-        }
+        assert_eq!(pthread_getattr_np(pthread_self(), &mut attr), 0);
         let mut stackaddr = ptr::null_mut();
         let mut stacksize = 0;
-        if pthread_attr_getstack(&attr, &mut stackaddr, &mut stacksize) != 0 {
-            panic!("failed to get stack information");
-        }
-        if pthread_attr_destroy(&mut attr) != 0 {
-            panic!("failed to destroy thread attributes");
-        }
+        assert_eq!(pthread_attr_getstack(&attr, &mut stackaddr, &mut stacksize), 0);
+        assert_eq!(pthread_attr_destroy(&mut attr), 0);
         stackaddr
     }
 
     pub unsafe fn init() {
-        let psize = libc::sysconf(libc::consts::os::sysconf::_SC_PAGESIZE);
-        if psize == -1 {
-            panic!("failed to get page size");
-        }
-
-        PAGE_SIZE = psize as uint;
-
+        let psize = os::page_size();
         let mut stackaddr = get_stack_start();
 
         // Ensure stackaddr is page aligned! A parent process might
@@ -118,9 +88,9 @@ pub mod guard {
         // stackaddr < stackaddr + stacksize, so if stackaddr is not
         // page-aligned, calculate the fix such that stackaddr <
         // new_page_aligned_stackaddr < stackaddr + stacksize
-        let remainder = (stackaddr as usize) % (PAGE_SIZE as usize);
+        let remainder = (stackaddr as usize) % psize;
         if remainder != 0 {
-            stackaddr = ((stackaddr as usize) + (PAGE_SIZE as usize) - remainder)
+            stackaddr = ((stackaddr as usize) + psize - remainder)
                 as *mut libc::c_void;
         }
 
@@ -128,7 +98,7 @@ pub mod guard {
         // This ensures SIGBUS will be raised on
         // stack overflow.
         let result = mmap(stackaddr,
-                          PAGE_SIZE as libc::size_t,
+                          psize as libc::size_t,
                           PROT_NONE,
                           MAP_PRIVATE | MAP_ANON | MAP_FIXED,
                           -1,
@@ -138,124 +108,119 @@ pub mod guard {
             panic!("failed to allocate a guard page");
         }
 
-        let offset = if cfg!(target_os = "linux") {
-            2
-        } else {
-            1
-        };
+        let offset = if cfg!(target_os = "linux") {2} else {1};
 
-        GUARD_PAGE = stackaddr as uint + offset * PAGE_SIZE;
+        GUARD_PAGE = stackaddr as usize + offset * psize;
     }
 
-    pub unsafe fn main() -> uint {
+    pub unsafe fn main() -> usize {
         GUARD_PAGE
     }
 
     #[cfg(target_os = "macos")]
-    pub unsafe fn current() -> uint {
+    pub unsafe fn current() -> usize {
+        extern {
+            fn pthread_get_stackaddr_np(thread: pthread_t) -> *mut libc::c_void;
+            fn pthread_get_stacksize_np(thread: pthread_t) -> libc::size_t;
+        }
         (pthread_get_stackaddr_np(pthread_self()) as libc::size_t -
-         pthread_get_stacksize_np(pthread_self())) as uint
+         pthread_get_stacksize_np(pthread_self())) as usize
     }
 
-    #[cfg(target_os = "openbsd")]
-    pub unsafe fn current() -> uint {
-        let mut current_stack: stack_t = mem::zeroed();
-        if pthread_stackseg_np(pthread_self(), &mut current_stack) != 0 {
-            panic!("failed to get current stack: pthread_stackseg_np")
+    #[cfg(any(target_os = "openbsd", target_os = "bitrig"))]
+    pub unsafe fn current() -> usize {
+        #[repr(C)]
+        pub struct stack_t {
+            ss_sp: *mut libc::c_void,
+            ss_size: libc::size_t,
+            ss_flags: libc::c_int,
+        }
+        extern {
+            fn pthread_stackseg_np(thread: pthread_t,
+                                   sinfo: *mut stack_t) -> libc::c_uint;
         }
 
+        let mut current_stack: stack_t = mem::zeroed();
+        assert_eq!(pthread_stackseg_np(pthread_self(), &mut current_stack), 0);
+
+        let extra = if cfg!(target_os = "bitrig") {3} else {1} * os::page_size();
         if pthread_main_np() == 1 {
             // main thread
-            current_stack.ss_sp as uint - current_stack.ss_size as uint + PAGE_SIZE as uint
-
+            current_stack.ss_sp as usize - current_stack.ss_size as usize + extra
         } else {
             // new thread
-            current_stack.ss_sp as uint - current_stack.ss_size as uint
+            current_stack.ss_sp as usize - current_stack.ss_size as usize
         }
     }
 
     #[cfg(any(target_os = "linux", target_os = "android"))]
-    pub unsafe fn current() -> uint {
+    pub unsafe fn current() -> usize {
         let mut attr: libc::pthread_attr_t = mem::zeroed();
-        if pthread_getattr_np(pthread_self(), &mut attr) != 0 {
-            panic!("failed to get thread attributes");
-        }
+        assert_eq!(pthread_getattr_np(pthread_self(), &mut attr), 0);
         let mut guardsize = 0;
-        if pthread_attr_getguardsize(&attr, &mut guardsize) != 0 {
-            panic!("failed to get stack guard page");
-        }
+        assert_eq!(pthread_attr_getguardsize(&attr, &mut guardsize), 0);
         if guardsize == 0 {
             panic!("there is no guard page");
         }
         let mut stackaddr = ptr::null_mut();
-        let mut stacksize = 0;
-        if pthread_attr_getstack(&attr, &mut stackaddr, &mut stacksize) != 0 {
-            panic!("failed to get stack information");
-        }
-        if pthread_attr_destroy(&mut attr) != 0 {
-            panic!("failed to destroy thread attributes");
-        }
+        let mut size = 0;
+        assert_eq!(pthread_attr_getstack(&attr, &mut stackaddr, &mut size), 0);
+        assert_eq!(pthread_attr_destroy(&mut attr), 0);
 
-        stackaddr as uint + guardsize as uint
+        stackaddr as usize + guardsize as usize
     }
 
-    #[cfg(target_os = "bitrig")]
-    pub unsafe fn current() -> uint {
-      let mut current_stack: stack_t = mem::zeroed();
-      if pthread_stackseg_np(pthread_self(), &mut current_stack) != 0 {
-        panic!("failed to get current stack: pthread_stackseg_np")
-      }
-
-      if pthread_main_np() == 1 {
-        // main thread
-        current_stack.ss_sp as uint - current_stack.ss_size as uint + 3 * PAGE_SIZE as uint
-      } else {
-        // new thread
-        current_stack.ss_sp as uint - current_stack.ss_size as uint
-      }
+    #[cfg(any(target_os = "linux", target_os = "android"))]
+    extern {
+        fn pthread_getattr_np(native: libc::pthread_t,
+                              attr: *mut libc::pthread_attr_t) -> libc::c_int;
+        fn pthread_attr_getguardsize(attr: *const libc::pthread_attr_t,
+                                     guardsize: *mut libc::size_t) -> libc::c_int;
+        fn pthread_attr_getstack(attr: *const libc::pthread_attr_t,
+                                 stackaddr: *mut *mut libc::c_void,
+                                 stacksize: *mut libc::size_t) -> libc::c_int;
     }
 }
 
-pub unsafe fn create(stack: uint, p: Thunk) -> io::Result<rust_thread> {
+pub unsafe fn create(stack: usize, p: Thunk) -> io::Result<rust_thread> {
+    let p = box p;
     let mut native: libc::pthread_t = mem::zeroed();
     let mut attr: libc::pthread_attr_t = mem::zeroed();
     assert_eq!(pthread_attr_init(&mut attr), 0);
-    assert_eq!(pthread_attr_setdetachstate(&mut attr,
-                                           PTHREAD_CREATE_JOINABLE), 0);
 
     // Reserve room for the red zone, the runtime's stack of last resort.
-    let stack_size = cmp::max(stack, RED_ZONE + min_stack_size(&attr) as uint);
+    let stack_size = cmp::max(stack, RED_ZONE + min_stack_size(&attr) as usize);
     match pthread_attr_setstacksize(&mut attr, stack_size as libc::size_t) {
-        0 => {
-        },
-        libc::EINVAL => {
+        0 => {}
+        n => {
+            assert_eq!(n, libc::EINVAL);
             // EINVAL means |stack_size| is either too small or not a
             // multiple of the system page size.  Because it's definitely
             // >= PTHREAD_STACK_MIN, it must be an alignment issue.
             // Round up to the nearest page and try again.
-            let page_size = libc::sysconf(libc::_SC_PAGESIZE) as uint;
+            let page_size = os::page_size();
             let stack_size = (stack_size + page_size - 1) &
-                             (-(page_size as int - 1) as uint - 1);
-            assert_eq!(pthread_attr_setstacksize(&mut attr, stack_size as libc::size_t), 0);
-        },
-        errno => {
-            // This cannot really happen.
-            panic!("pthread_attr_setstacksize() error: {}", errno);
-        },
+                             (-(page_size as isize - 1) as usize - 1);
+            assert_eq!(pthread_attr_setstacksize(&mut attr,
+                                                 stack_size as libc::size_t), 0);
+        }
     };
 
-    // must box since sizeof(p)=2*uint
-    let raw_p = boxed::into_raw(box p);
-    let arg = raw_p as *mut libc::c_void;
-    let ret = pthread_create(&mut native, &attr, thread_start, arg);
+    let ret = pthread_create(&mut native, &attr, thread_start,
+                             &*p as *const _ as *mut _);
     assert_eq!(pthread_attr_destroy(&mut attr), 0);
 
-    if ret != 0 {
-        // be sure to not leak the closure
-        let _p: Box<Thunk> = Box::from_raw(raw_p);
+    return if ret != 0 {
         Err(io::Error::from_os_error(ret))
     } else {
+        mem::forget(p); // ownership passed to pthread_create
         Ok(native)
+    };
+
+    #[no_stack_check]
+    extern fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void {
+        start_thread(main);
+        0 as *mut _
     }
 }
 
@@ -263,14 +228,14 @@ pub unsafe fn create(stack: uint, p: Thunk) -> io::Result<rust_thread> {
 pub unsafe fn set_name(name: &str) {
     // pthread_setname_np() since glibc 2.12
     // availability autodetected via weak linkage
-    let cname = CString::new(name).unwrap();
-    type F = unsafe extern "C" fn(libc::pthread_t, *const libc::c_char)
-                                  -> libc::c_int;
+    type F = unsafe extern fn(libc::pthread_t, *const libc::c_char)
+                              -> libc::c_int;
     extern {
         #[linkage = "extern_weak"]
         static pthread_setname_np: *const ();
     }
     if !pthread_setname_np.is_null() {
+        let cname = CString::new(name).unwrap();
         mem::transmute::<*const (), F>(pthread_setname_np)(pthread_self(),
                                                            cname.as_ptr());
     }
@@ -281,14 +246,18 @@ pub unsafe fn set_name(name: &str) {
           target_os = "bitrig",
           target_os = "openbsd"))]
 pub unsafe fn set_name(name: &str) {
-    // pthread_set_name_np() since almost forever on all BSDs
+    extern {
+        fn pthread_set_name_np(tid: libc::pthread_t, name: *const libc::c_char);
+    }
     let cname = CString::new(name).unwrap();
     pthread_set_name_np(pthread_self(), cname.as_ptr());
 }
 
 #[cfg(any(target_os = "macos", target_os = "ios"))]
 pub unsafe fn set_name(name: &str) {
-    // pthread_setname_np() since OS X 10.6 and iOS 3.2
+    extern {
+        fn pthread_setname_np(name: *const libc::c_char) -> libc::c_int;
+    }
     let cname = CString::new(name).unwrap();
     pthread_setname_np(cname.as_ptr());
 }
@@ -301,7 +270,42 @@ pub unsafe fn detach(native: rust_thread) {
     assert_eq!(pthread_detach(native), 0);
 }
 
-pub unsafe fn yield_now() { assert_eq!(sched_yield(), 0); }
+pub unsafe fn yield_now() {
+    assert_eq!(sched_yield(), 0);
+}
+
+pub fn sleep(dur: Duration) {
+    unsafe {
+        if dur < Duration::zero() {
+            return yield_now()
+        }
+        let seconds = dur.num_seconds();
+        let ns = dur - Duration::seconds(seconds);
+        let mut ts = libc::timespec {
+            tv_sec: seconds as libc::time_t,
+            tv_nsec: ns.num_nanoseconds().unwrap() as libc::c_long,
+        };
+        // If we're awoken with a signal then the return value will be -1 and
+        // nanosleep will fill in `ts` with the remaining time.
+        while dosleep(&mut ts) == -1 {
+            assert_eq!(os::errno(), libc::EINTR);
+        }
+    }
+
+    #[cfg(target_os = "linux")]
+    unsafe fn dosleep(ts: *mut libc::timespec) -> libc::c_int {
+        extern {
+            fn clock_nanosleep(clock_id: libc::c_int, flags: libc::c_int,
+                               request: *const libc::timespec,
+                               remain: *mut libc::timespec) -> libc::c_int;
+        }
+        clock_nanosleep(libc::CLOCK_MONOTONIC, 0, ts, ts)
+    }
+    #[cfg(not(target_os = "linux"))]
+    unsafe fn dosleep(ts: *mut libc::timespec) -> libc::c_int {
+        libc::nanosleep(ts, ts)
+    }
+}
 
 // glibc >= 2.15 has a __pthread_get_minstack() function that returns
 // PTHREAD_STACK_MIN plus however many bytes are needed for thread-local
@@ -334,67 +338,19 @@ fn min_stack_size(_: *const libc::pthread_attr_t) -> libc::size_t {
     PTHREAD_STACK_MIN
 }
 
-#[cfg(any(target_os = "linux", target_os = "android"))]
-extern {
-    pub fn pthread_self() -> libc::pthread_t;
-    pub fn pthread_getattr_np(native: libc::pthread_t,
-                              attr: *mut libc::pthread_attr_t) -> libc::c_int;
-    pub fn pthread_attr_getguardsize(attr: *const libc::pthread_attr_t,
-                                     guardsize: *mut libc::size_t) -> libc::c_int;
-    pub fn pthread_attr_getstack(attr: *const libc::pthread_attr_t,
-                                 stackaddr: *mut *mut libc::c_void,
-                                 stacksize: *mut libc::size_t) -> libc::c_int;
-}
-
-#[cfg(any(target_os = "freebsd",
-          target_os = "dragonfly",
-          target_os = "openbsd"))]
 extern {
-    pub fn pthread_self() -> libc::pthread_t;
-    fn pthread_set_name_np(tid: libc::pthread_t, name: *const libc::c_char);
-}
+    #[cfg(any(target_os = "bitrig", target_os = "openbsd"))]
+    fn pthread_main_np() -> libc::c_uint;
 
-#[cfg(any(target_os = "macos", target_os = "ios"))]
-extern {
-    pub fn pthread_self() -> libc::pthread_t;
-    pub fn pthread_get_stackaddr_np(thread: libc::pthread_t) -> *mut libc::c_void;
-    pub fn pthread_get_stacksize_np(thread: libc::pthread_t) -> libc::size_t;
-    fn pthread_setname_np(name: *const libc::c_char) -> libc::c_int;
-}
-
-#[cfg(target_os = "bitrig")]
-extern {
-    pub fn pthread_self() -> libc::pthread_t;
-    pub fn pthread_stackseg_np(thread: libc::pthread_t,
-                              sinfo: *mut stack_t) -> libc::c_uint;
-    pub fn pthread_main_np() -> libc::c_uint;
-    fn pthread_set_name_np(tid: libc::pthread_t, name: *const libc::c_char);
-}
-
-#[cfg(target_os = "openbsd")]
-extern {
-        pub fn pthread_stackseg_np(thread: libc::pthread_t,
-                                   sinfo: *mut stack_t) -> libc::c_uint;
-        pub fn pthread_main_np() -> libc::c_uint;
-}
-
-#[cfg(any(target_os = "bitrig", target_os = "openbsd"))]
-#[repr(C)]
-pub struct stack_t {
-    pub ss_sp: *mut libc::c_void,
-    pub ss_size: libc::size_t,
-    pub ss_flags: libc::c_int,
-}
-
-extern {
+    fn pthread_self() -> libc::pthread_t;
     fn pthread_create(native: *mut libc::pthread_t,
                       attr: *const libc::pthread_attr_t,
-                      f: StartFn,
+                      f: extern fn(*mut libc::c_void) -> *mut libc::c_void,
                       value: *mut libc::c_void) -> libc::c_int;
     fn pthread_join(native: libc::pthread_t,
                     value: *mut *mut libc::c_void) -> libc::c_int;
     fn pthread_attr_init(attr: *mut libc::pthread_attr_t) -> libc::c_int;
-    pub fn pthread_attr_destroy(attr: *mut libc::pthread_attr_t) -> libc::c_int;
+    fn pthread_attr_destroy(attr: *mut libc::pthread_attr_t) -> libc::c_int;
     fn pthread_attr_setstacksize(attr: *mut libc::pthread_attr_t,
                                  stack_size: libc::size_t) -> libc::c_int;
     fn pthread_attr_setdetachstate(attr: *mut libc::pthread_attr_t,