From 47e0bd403a04d26506f723ac44ee9ea0aa5d3ad5 Mon Sep 17 00:00:00 2001 From: Dirkjan Bussink Date: Tue, 5 Nov 2013 14:13:02 +0100 Subject: Move implementation for threads to Rust This binds to the appropriate pthreads_* and Windows specific functions and calls them from Rust. This allows for removal of the C++ support code for threads. Fixes #10162 --- src/libstd/rt/thread.rs | 127 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 97 insertions(+), 30 deletions(-) (limited to 'src/libstd/rt') diff --git a/src/libstd/rt/thread.rs b/src/libstd/rt/thread.rs index a3731e0b57a..9838a191197 100644 --- a/src/libstd/rt/thread.rs +++ b/src/libstd/rt/thread.rs @@ -8,74 +8,141 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#[allow(non_camel_case_types)]; + use cast; use libc; use ops::Drop; -use unstable::raw; use uint; +use ptr; + +#[cfg(windows)] +use libc::types::os::arch::extra::{LPSECURITY_ATTRIBUTES, SIZE_T, + LPVOID, DWORD, LPDWORD, HANDLE}; -#[allow(non_camel_case_types)] // runtime type -type raw_thread = libc::c_void; +#[cfg(windows)] type rust_thread = HANDLE; +#[cfg(unix)] type rust_thread = libc::pthread_t; pub struct Thread { - priv main: ~fn(), - priv raw_thread: *raw_thread, + priv native: rust_thread, priv joined: bool } +static DEFAULT_STACK_SIZE: libc::size_t = 1024*1024; + +#[cfg(windows)] type rust_thread_return = DWORD; +#[cfg(unix)] type rust_thread_return = *libc::c_void; + impl Thread { - #[fixed_stack_segment] #[inline(never)] + pub fn start(main: ~fn()) -> Thread { // 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_split_stack annotation), and then we re-build the main function - // and invoke it from there. + // no_split_stack annotation), and then we extract the main function + // and invoke it. #[no_split_stack] - extern "C" fn thread_start(code: *(), env: *()) { + extern "C" fn thread_start(trampoline: *libc::c_void) -> rust_thread_return { use rt::context; unsafe { context::record_stack_bounds(0, uint::max_value); - let f: &fn() = cast::transmute(raw::Closure { - code: code, - env: env, - }); - f(); + let f: ~~fn() = cast::transmute(trampoline); + (*f)(); } + unsafe { cast::transmute(0) } } - let raw_thread = unsafe { - let c: raw::Closure = cast::transmute_copy(&main); - let raw::Closure { code, env } = c; - rust_raw_thread_start(thread_start, code, env) - }; + let native = native_thread_create(thread_start, ~main); Thread { - main: main, - raw_thread: raw_thread, + native: native, joined: false, } } pub fn join(mut self) { - #[fixed_stack_segment]; #[inline(never)]; - assert!(!self.joined); - unsafe { rust_raw_thread_join(self.raw_thread); } + native_thread_join(self.native); self.joined = true; } } +#[cfg(windows)] +fn native_thread_create(thread_start: extern "C" fn(*libc::c_void) -> rust_thread_return, + tramp: ~~fn()) -> rust_thread { + #[fixed_stack_segment]; + + unsafe { + let ptr: *mut libc::c_void = cast::transmute(tramp); + CreateThread(ptr::mut_null(), DEFAULT_STACK_SIZE, thread_start, ptr, 0, ptr::mut_null()) + } +} + +#[cfg(windows)] +fn native_thread_join(native: rust_thread) { + #[fixed_stack_segment]; + use libc::consts::os::extra::INFINITE; + unsafe { WaitForSingleObject(native, INFINITE); } +} + +#[cfg(unix)] +fn native_thread_create(thread_start: extern "C" fn(*libc::c_void) -> rust_thread_return, + tramp: ~~fn()) -> rust_thread { + #[fixed_stack_segment]; + + use unstable::intrinsics; + let mut native: libc::pthread_t = unsafe { intrinsics::uninit() }; + + unsafe { + use libc::consts::os::posix01::PTHREAD_CREATE_JOINABLE; + + let mut attr: libc::pthread_attr_t = intrinsics::uninit(); + assert!(pthread_attr_init(&mut attr) == 0); + assert!(pthread_attr_setstacksize(&mut attr, DEFAULT_STACK_SIZE) == 0); + assert!(pthread_attr_setdetachstate(&mut attr, PTHREAD_CREATE_JOINABLE) == 0); + + let ptr: *libc::c_void = cast::transmute(tramp); + assert!(pthread_create(&mut native, &attr, thread_start, ptr) == 0); + } + native +} + +#[cfg(unix)] +fn native_thread_join(native: rust_thread) { + #[fixed_stack_segment]; + unsafe { assert!(pthread_join(native, ptr::null()) == 0) } +} + impl Drop for Thread { fn drop(&mut self) { #[fixed_stack_segment]; #[inline(never)]; - assert!(self.joined); - unsafe { rust_raw_thread_delete(self.raw_thread) } } } +#[cfg(windows, target_arch = "x86")] +extern "stdcall" { + fn CreateThread(lpThreadAttributes: LPSECURITY_ATTRIBUTES, dwStackSize: SIZE_T, + lpStartAddress: extern "C" fn(*libc::c_void) -> rust_thread_return, + lpParameter: LPVOID, dwCreationFlags: DWORD, lpThreadId: LPDWORD) -> HANDLE; + fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD; +} + +#[cfg(windows, target_arch = "x86_64")] +extern { + fn CreateThread(lpThreadAttributes: LPSECURITY_ATTRIBUTES, dwStackSize: SIZE_T, + lpStartAddress: extern "C" fn(*libc::c_void) -> rust_thread_return, + lpParameter: LPVOID, dwCreationFlags: DWORD, lpThreadId: LPDWORD) -> HANDLE; + fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD; +} + +#[cfg(unix)] extern { - fn rust_raw_thread_start(f: extern "C" fn(*(), *()), - code: *(), env: *()) -> *raw_thread; - fn rust_raw_thread_join(thread: *raw_thread); - fn rust_raw_thread_delete(thread: *raw_thread); + fn pthread_create(native: *mut libc::pthread_t, attr: *libc::pthread_attr_t, + f: extern "C" fn(*libc::c_void) -> rust_thread_return, + value: *libc::c_void) -> libc::c_int; + fn pthread_join(native: libc::pthread_t, value: **libc::c_void) -> libc::c_int; + fn pthread_attr_init(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, + state: libc::c_int) -> libc::c_int; } -- cgit 1.4.1-3-g733a5