about summary refs log tree commit diff
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
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.
-rw-r--r--src/libstd/sys/common/thread.rs15
-rw-r--r--src/libstd/sys/unix/thread.rs318
-rw-r--r--src/libstd/sys/windows/thread.rs66
-rw-r--r--src/libstd/thread.rs19
4 files changed, 197 insertions, 221 deletions
diff --git a/src/libstd/sys/common/thread.rs b/src/libstd/sys/common/thread.rs
index 731617858e9..f45daea18a2 100644
--- a/src/libstd/sys/common/thread.rs
+++ b/src/libstd/sys/common/thread.rs
@@ -8,28 +8,23 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use core::prelude::*;
+use prelude::v1::*;
 
-use boxed::Box;
-use mem;
 use usize;
 use libc;
 use thunk::Thunk;
 use sys_common::stack;
-use sys::{thread, stack_overflow};
+use sys::stack_overflow;
 
 // This is the starting point of rust os threads. The first thing we do
 // is make sure that we don't trigger __morestack (also why this has a
 // no_stack_check annotation), and then we extract the main function
 // and invoke it.
 #[no_stack_check]
-pub fn start_thread(main: *mut libc::c_void) -> thread::rust_thread_return {
+pub fn start_thread(main: *mut libc::c_void) {
     unsafe {
         stack::record_os_managed_stack_bounds(0, usize::MAX);
-        let handler = stack_overflow::Handler::new();
-        let f: Box<Thunk> = Box::from_raw(main as *mut Thunk);
-        f.invoke(());
-        drop(handler);
-        mem::transmute(0 as thread::rust_thread_return)
+        let _handler = stack_overflow::Handler::new();
+        Box::from_raw(main as *mut Thunk).invoke(());
     }
 }
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,
diff --git a/src/libstd/sys/windows/thread.rs b/src/libstd/sys/windows/thread.rs
index aa22b6b1307..d1d4ad90081 100644
--- a/src/libstd/sys/windows/thread.rs
+++ b/src/libstd/sys/windows/thread.rs
@@ -10,43 +10,28 @@
 
 use prelude::v1::*;
 
-use boxed;
 use cmp;
 use io;
-use ptr;
-use libc;
+use libc::{self, c_void};
 use libc::types::os::arch::extra::{LPSECURITY_ATTRIBUTES, SIZE_T, BOOL,
                                    LPVOID, DWORD, LPDWORD, HANDLE};
-use thunk::Thunk;
+use mem;
+use ptr;
 use sys_common::stack::RED_ZONE;
 use sys_common::thread::*;
+use thunk::Thunk;
+use time::Duration;
 
 pub type rust_thread = HANDLE;
-pub type rust_thread_return = DWORD;
-
-pub type StartFn = extern "system" fn(*mut libc::c_void) -> rust_thread_return;
-
-#[no_stack_check]
-pub extern "system" fn thread_start(main: *mut libc::c_void) -> rust_thread_return {
-    return start_thread(main);
-}
 
 pub mod guard {
-    pub unsafe fn main() -> uint {
-        0
-    }
-
-    pub unsafe fn current() -> uint {
-        0
-    }
-
-    pub unsafe fn init() {
-    }
+    pub unsafe fn main() -> uint { 0 }
+    pub unsafe fn current() -> uint { 0 }
+    pub unsafe fn init() {}
 }
 
-pub unsafe fn create(stack: uint, p: Thunk) -> io::Result<rust_thread> {
-    let raw_p = boxed::into_raw(box p);
-    let arg = raw_p as *mut libc::c_void;
+pub unsafe fn create(stack: usize, p: Thunk) -> io::Result<rust_thread> {
+    let p = box p;
     // FIXME On UNIX, we guard against stack sizes that are too small but
     // that's because pthreads enforces that stacks are at least
     // PTHREAD_STACK_MIN bytes big.  Windows has no such lower limit, it's
@@ -58,14 +43,20 @@ pub unsafe fn create(stack: uint, p: Thunk) -> io::Result<rust_thread> {
     // 20 kB red zone, that makes for a 64 kB minimum stack.
     let stack_size = (cmp::max(stack, RED_ZONE) + 0xfffe) & (-0xfffe - 1);
     let ret = CreateThread(ptr::null_mut(), stack_size as libc::size_t,
-                           thread_start, arg, 0, ptr::null_mut());
+                           thread_start, &*p as *const _ as *mut _,
+                           0, ptr::null_mut());
 
-    if ret as uint == 0 {
-        // be sure to not leak the closure
-        let _p: Box<Thunk> = Box::from_raw(raw_p);
+    return if ret as usize == 0 {
         Err(io::Error::last_os_error())
     } else {
+        mem::forget(p); // ownership passed to CreateThread
         Ok(ret)
+    };
+
+    #[no_stack_check]
+    extern "system" fn thread_start(main: *mut libc::c_void) -> DWORD {
+        start_thread(main);
+        0
     }
 }
 
@@ -92,14 +83,29 @@ pub unsafe fn yield_now() {
     SwitchToThread();
 }
 
+pub fn sleep(dur: Duration) {
+    unsafe {
+        if dur < Duration::zero() {
+            return yield_now()
+        }
+        let ms = dur.num_milliseconds();
+        // if we have a fractional number of milliseconds then add an extra
+        // millisecond to sleep for
+        let extra = dur - Duration::milliseconds(ms);
+        let ms = ms + if extra.is_zero() {0} else {1};
+        Sleep(ms as DWORD);
+    }
+}
+
 #[allow(non_snake_case)]
 extern "system" {
     fn CreateThread(lpThreadAttributes: LPSECURITY_ATTRIBUTES,
                     dwStackSize: SIZE_T,
-                    lpStartAddress: StartFn,
+                    lpStartAddress: extern "system" fn(*mut c_void) -> DWORD,
                     lpParameter: LPVOID,
                     dwCreationFlags: DWORD,
                     lpThreadId: LPDWORD) -> HANDLE;
     fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD;
     fn SwitchToThread() -> BOOL;
+    fn Sleep(dwMilliseconds: DWORD);
 }
diff --git a/src/libstd/thread.rs b/src/libstd/thread.rs
index a40b26c85be..d2742d4b45a 100644
--- a/src/libstd/thread.rs
+++ b/src/libstd/thread.rs
@@ -379,6 +379,19 @@ pub fn panicking() -> bool {
     unwind::panicking()
 }
 
+/// Put the current thread to sleep for the specified amount of time.
+///
+/// The thread may sleep longer than the duration specified due to scheduling
+/// specifics or platform-dependent functionality. Note that on unix platforms
+/// this function will not return early due to a signal being received or a
+/// spurious wakeup.
+#[unstable(feature = "thread_sleep",
+           reason = "recently added, needs an RFC, and `Duration` itself is \
+                     unstable")]
+pub fn sleep(dur: Duration) {
+    imp::sleep(dur)
+}
+
 /// Block unless or until the current thread's token is made available (may wake spuriously).
 ///
 /// See the module doc for more detail.
@@ -935,6 +948,12 @@ mod test {
         }
     }
 
+    #[test]
+    fn sleep_smoke() {
+        thread::sleep(Duration::milliseconds(2));
+        thread::sleep(Duration::milliseconds(-2));
+    }
+
     // NOTE: the corresponding test for stderr is in run-pass/task-stderr, due
     // to the test harness apparently interfering with stderr configuration.
 }