about summary refs log tree commit diff
path: root/src/libstd/sys/windows
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2015-04-14 22:13:57 -0700
committerAlex Crichton <alex@alexcrichton.com>2015-04-22 10:42:33 -0700
commit2e1100997863c4951371cf39554c53266cacb37d (patch)
treee4d266578d80fa55705ba349c4508191fd5a692b /src/libstd/sys/windows
parente9e9279d87d5786fcb8e12482f2920979602267b (diff)
downloadrust-2e1100997863c4951371cf39554c53266cacb37d.tar.gz
rust-2e1100997863c4951371cf39554c53266cacb37d.zip
std: Audit std::thread implementations
Much of this code hasn't been updated in quite some time and this commit does a
small audit of the functionality:

* Implementation functions now centralize all functionality on a locally defined
  `Thread` type.
* The `detach` method has been removed in favor of a `Drop` implementation. This
  notably fixes leaking thread handles on Windows.
* The `Thread` structure is now appropriately annotated with `Send` and `Sync`
  automatically on Windows and in a custom fashion on Unix.
* The unsafety of creating a thread has been pushed out to the right boundaries
  now.

Closes #24442
Diffstat (limited to 'src/libstd/sys/windows')
-rw-r--r--src/libstd/sys/windows/c.rs11
-rw-r--r--src/libstd/sys/windows/thread.rs143
2 files changed, 77 insertions, 77 deletions
diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs
index 331bfbfff36..b07d063de45 100644
--- a/src/libstd/sys/windows/c.rs
+++ b/src/libstd/sys/windows/c.rs
@@ -471,6 +471,17 @@ extern "system" {
                       hWritePipe: libc::LPHANDLE,
                       lpPipeAttributes: libc::LPSECURITY_ATTRIBUTES,
                       nSize: libc::DWORD) -> libc::BOOL;
+    pub fn CreateThread(lpThreadAttributes: libc::LPSECURITY_ATTRIBUTES,
+                        dwStackSize: libc::SIZE_T,
+                        lpStartAddress: extern "system" fn(*mut libc::c_void)
+                                                           -> libc::DWORD,
+                        lpParameter: libc::LPVOID,
+                        dwCreationFlags: libc::DWORD,
+                        lpThreadId: libc::LPDWORD) -> libc::HANDLE;
+    pub fn WaitForSingleObject(hHandle: libc::HANDLE,
+                               dwMilliseconds: libc::DWORD) -> libc::DWORD;
+    pub fn SwitchToThread() -> libc::BOOL;
+    pub fn Sleep(dwMilliseconds: libc::DWORD);
 }
 
 #[link(name = "userenv")]
diff --git a/src/libstd/sys/windows/thread.rs b/src/libstd/sys/windows/thread.rs
index 98e4a737c7b..797f45f8702 100644
--- a/src/libstd/sys/windows/thread.rs
+++ b/src/libstd/sys/windows/thread.rs
@@ -10,102 +10,91 @@
 
 use prelude::v1::*;
 
+use alloc::boxed::FnBox;
 use cmp;
 use io;
-use libc::{self, c_void};
-use libc::types::os::arch::extra::{LPSECURITY_ATTRIBUTES, SIZE_T, BOOL,
-                                   LPVOID, DWORD, LPDWORD, HANDLE};
+use libc::{self, c_void, DWORD};
 use mem;
 use ptr;
+use sys::c;
+use sys::handle::Handle;
 use sys_common::stack::RED_ZONE;
 use sys_common::thread::*;
-use thunk::Thunk;
 use time::Duration;
 
-pub type rust_thread = HANDLE;
-
-pub mod guard {
-    pub unsafe fn main() -> usize { 0 }
-    pub unsafe fn current() -> usize { 0 }
-    pub unsafe fn init() {}
+pub struct Thread {
+    handle: Handle
 }
 
-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
-    // just that below a certain threshold you can't do anything useful.
-    // That threshold is application and architecture-specific, however.
-    // For now, the only requirement is that it's big enough to hold the
-    // red zone.  Round up to the next 64 kB because that's what the NT
-    // kernel does, might as well make it explicit.  With the current
-    // 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, &*p as *const _ as *mut _,
-                           0, ptr::null_mut());
+impl Thread {
+    pub unsafe fn new<'a>(stack: usize, p: Box<FnBox() + 'a>)
+                          -> io::Result<Thread> {
+        let p = box p;
 
-    return if ret as usize == 0 {
-        Err(io::Error::last_os_error())
-    } else {
-        mem::forget(p); // ownership passed to CreateThread
-        Ok(ret)
-    };
+        // 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
+        // just that below a certain threshold you can't do anything useful.
+        // That threshold is application and architecture-specific, however.
+        // For now, the only requirement is that it's big enough to hold the
+        // red zone.  Round up to the next 64 kB because that's what the NT
+        // kernel does, might as well make it explicit.  With the current
+        // 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 = c::CreateThread(ptr::null_mut(), stack_size as libc::size_t,
+                                  thread_start, &*p as *const _ as *mut _,
+                                  0, ptr::null_mut());
 
-    #[no_stack_check]
-    extern "system" fn thread_start(main: *mut libc::c_void) -> DWORD {
-        start_thread(main);
-        0
-    }
-}
+        return if ret as usize == 0 {
+            Err(io::Error::last_os_error())
+        } else {
+            mem::forget(p); // ownership passed to CreateThread
+            Ok(Thread { handle: Handle::new(ret) })
+        };
 
-pub unsafe fn set_name(_name: &str) {
-    // Windows threads are nameless
-    // The names in MSVC debugger are obtained using a "magic" exception,
-    // which requires a use of MS C++ extensions.
-    // See https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
-}
+        #[no_stack_check]
+        extern "system" fn thread_start(main: *mut libc::c_void) -> DWORD {
+            unsafe { start_thread(main); }
+            0
+        }
+    }
 
-pub unsafe fn join(native: rust_thread) {
-    use libc::consts::os::extra::INFINITE;
-    WaitForSingleObject(native, INFINITE);
-}
+    pub fn set_name(_name: &str) {
+        // Windows threads are nameless
+        // The names in MSVC debugger are obtained using a "magic" exception,
+        // which requires a use of MS C++ extensions.
+        // See https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
+    }
 
-pub unsafe fn detach(native: rust_thread) {
-    assert!(libc::CloseHandle(native) != 0);
-}
+    pub fn join(self) {
+        use libc::consts::os::extra::INFINITE;
+        unsafe { c::WaitForSingleObject(self.handle.raw(), INFINITE); }
+    }
 
-pub unsafe fn yield_now() {
-    // This function will return 0 if there are no other threads to execute,
-    // but this also means that the yield was useless so this isn't really a
-    // case that needs to be worried about.
-    SwitchToThread();
-}
+    pub fn yield_now() {
+        // This function will return 0 if there are no other threads to execute,
+        // but this also means that the yield was useless so this isn't really a
+        // case that needs to be worried about.
+        unsafe { c::SwitchToThread(); }
+    }
 
-pub fn sleep(dur: Duration) {
-    unsafe {
-        if dur < Duration::zero() {
-            return yield_now()
+    pub fn sleep(dur: Duration) {
+        unsafe {
+            if dur < Duration::zero() {
+                return Thread::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};
+            c::Sleep(ms as DWORD);
         }
-        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: 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);
+pub mod guard {
+    pub unsafe fn main() -> usize { 0 }
+    pub unsafe fn current() -> usize { 0 }
+    pub unsafe fn init() {}
 }