From 47e0bd403a04d26506f723ac44ee9ea0aa5d3ad5 Mon Sep 17 00:00:00 2001 From: Dirkjan Bussink Date: Tue, 5 Nov 2013 14:13:02 +0100 Subject: [PATCH] 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 --- mk/rt.mk | 1 - src/libstd/libc.rs | 63 ++++++++++++++++-- src/libstd/rt/thread.rs | 129 +++++++++++++++++++++++++++--------- src/rt/rust_builtin.cpp | 37 ----------- src/rt/rustrt.def.in | 3 - src/rt/sync/rust_thread.cpp | 65 ------------------ src/rt/sync/rust_thread.h | 38 ----------- 7 files changed, 154 insertions(+), 182 deletions(-) delete mode 100644 src/rt/sync/rust_thread.cpp delete mode 100644 src/rt/sync/rust_thread.h diff --git a/mk/rt.mk b/mk/rt.mk index d51b09b56da..15b13d99465 100644 --- a/mk/rt.mk +++ b/mk/rt.mk @@ -84,7 +84,6 @@ endif RUNTIME_CXXS_$(1)_$(2) := \ rt/sync/lock_and_signal.cpp \ - rt/sync/rust_thread.cpp \ rt/rust_builtin.cpp \ rt/rust_upcall.cpp \ rt/miniz.cpp \ diff --git a/src/libstd/libc.rs b/src/libstd/libc.rs index f992b327495..9c84f770807 100644 --- a/src/libstd/libc.rs +++ b/src/libstd/libc.rs @@ -224,7 +224,10 @@ pub mod types { pub mod common { pub mod posix01 { use libc::types::common::c95::{c_void}; - use libc::types::os::arch::c95::{c_char, size_t}; + use libc::types::os::arch::c95::{c_char, c_ulong, size_t}; + + pub type pthread_t = c_ulong; + pub struct glob_t { gl_pathc: size_t, gl_pathv: **c_char, @@ -294,7 +297,7 @@ pub mod types { } #[cfg(target_arch = "x86")] pub mod posix01 { - use libc::types::os::arch::c95::{c_short, c_long, time_t}; + use libc::types::os::arch::c95::{c_char, c_short, c_long, time_t}; use libc::types::os::arch::posix88::{dev_t, gid_t, ino_t}; use libc::types::os::arch::posix88::{mode_t, off_t}; use libc::types::os::arch::posix88::{uid_t}; @@ -325,10 +328,14 @@ pub mod types { __unused4: c_long, __unused5: c_long, } + + pub struct pthread_attr_t { + __size: [c_char, ..36] + } } #[cfg(target_arch = "arm")] pub mod posix01 { - use libc::types::os::arch::c95::{c_uchar, c_uint, c_ulong, time_t}; + use libc::types::os::arch::c95::{c_char, c_uchar, c_uint, c_ulong, time_t}; use libc::types::os::arch::c99::{c_longlong, c_ulonglong}; use libc::types::os::arch::posix88::{uid_t, gid_t, ino_t}; @@ -357,10 +364,14 @@ pub mod types { st_ctime_nsec: c_ulong, st_ino: c_ulonglong } + + pub struct pthread_attr_t { + __size: [c_char, ..36] + } } #[cfg(target_arch = "mips")] pub mod posix01 { - use libc::types::os::arch::c95::{c_long, c_ulong, time_t}; + use libc::types::os::arch::c95::{c_char, c_long, c_ulong, time_t}; use libc::types::os::arch::posix88::{gid_t, ino_t}; use libc::types::os::arch::posix88::{mode_t, off_t}; use libc::types::os::arch::posix88::{uid_t}; @@ -391,6 +402,10 @@ pub mod types { st_blocks: blkcnt_t, st_pad5: [c_long, ..14], } + + pub struct pthread_attr_t { + __size: [c_char, ..36] + } } pub mod posix08 {} pub mod bsd44 {} @@ -435,7 +450,7 @@ pub mod types { pub type ssize_t = i64; } pub mod posix01 { - use libc::types::os::arch::c95::{c_int, c_long, time_t}; + use libc::types::os::arch::c95::{c_char, c_int, c_long, time_t}; use libc::types::os::arch::posix88::{dev_t, gid_t, ino_t}; use libc::types::os::arch::posix88::{mode_t, off_t}; use libc::types::os::arch::posix88::{uid_t}; @@ -463,6 +478,10 @@ pub mod types { st_ctime_nsec: c_long, __unused: [c_long, ..3], } + + pub struct pthread_attr_t { + __size: [c_char, ..56] + } } pub mod posix08 { } @@ -479,6 +498,10 @@ pub mod types { pub mod posix01 { use libc::types::common::c95::{c_void}; use libc::types::os::arch::c95::{c_char, c_int, size_t}; + use libc::types::os::arch::c99::{uintptr_t}; + + pub type pthread_t = uintptr_t; + pub struct glob_t { gl_pathc: size_t, __unused1: size_t, @@ -535,6 +558,7 @@ pub mod types { pub type ssize_t = i64; } pub mod posix01 { + use libc::types::common::c95::{c_void}; use libc::types::common::c99::{uint8_t, uint32_t, int32_t}; use libc::types::os::arch::c95::{c_long, time_t}; use libc::types::os::arch::posix88::{dev_t, gid_t, ino_t}; @@ -569,6 +593,8 @@ pub mod types { st_birthtime_nsec: c_long, __unused: [uint8_t, ..2], } + + pub type pthread_attr_t = *c_void; } pub mod posix08 { } @@ -945,6 +971,10 @@ pub mod types { pub mod posix01 { use libc::types::common::c95::{c_void}; use libc::types::os::arch::c95::{c_char, c_int, size_t}; + use libc::types::os::arch::c99::{uintptr_t}; + + pub type pthread_t = uintptr_t; + pub struct glob_t { gl_pathc: size_t, __unused1: c_int, @@ -1002,7 +1032,7 @@ pub mod types { } pub mod posix01 { use libc::types::common::c99::{int32_t, int64_t, uint32_t}; - use libc::types::os::arch::c95::{c_long, time_t}; + use libc::types::os::arch::c95::{c_char, c_long, time_t}; use libc::types::os::arch::posix88::{dev_t, gid_t, ino_t, mode_t, off_t, uid_t}; @@ -1034,6 +1064,11 @@ pub mod types { st_lspare: int32_t, st_qspare: [int64_t, ..2], } + + pub struct pthread_attr_t { + __sig: c_long, + __opaque: [c_char, ..36] + } } pub mod posix08 { } @@ -1083,7 +1118,7 @@ pub mod types { pub mod posix01 { use libc::types::common::c99::{int32_t, int64_t}; use libc::types::common::c99::{uint32_t}; - use libc::types::os::arch::c95::{c_long, time_t}; + use libc::types::os::arch::c95::{c_char, c_long, time_t}; use libc::types::os::arch::posix88::{dev_t, gid_t, ino_t}; use libc::types::os::arch::posix88::{mode_t, off_t, uid_t}; @@ -1115,6 +1150,11 @@ pub mod types { st_lspare: int32_t, st_qspare: [int64_t, ..2], } + + pub struct pthread_attr_t { + __sig: c_long, + __opaque: [c_char, ..56] + } } pub mod posix08 { } @@ -1800,6 +1840,9 @@ pub mod consts { pub static _SC_XOPEN_LEGACY : c_int = 129; pub static _SC_XOPEN_REALTIME : c_int = 130; pub static _SC_XOPEN_REALTIME_THREADS : c_int = 131; + + pub static PTHREAD_CREATE_JOINABLE: c_int = 0; + pub static PTHREAD_CREATE_DETACHED: c_int = 1; } pub mod posix08 { } @@ -2207,6 +2250,9 @@ pub mod consts { pub static _SC_XOPEN_UNIX : c_int = 115; pub static _SC_XOPEN_VERSION : c_int = 116; pub static _SC_XOPEN_XCU_VERSION : c_int = 117; + + pub static PTHREAD_CREATE_JOINABLE: c_int = 0; + pub static PTHREAD_CREATE_DETACHED: c_int = 1; } pub mod posix08 { } @@ -2560,6 +2606,9 @@ pub mod consts { pub static _SC_XOPEN_UNIX : c_int = 115; pub static _SC_XOPEN_VERSION : c_int = 116; pub static _SC_XOPEN_XCU_VERSION : c_int = 121; + + pub static PTHREAD_CREATE_JOINABLE: c_int = 1; + pub static PTHREAD_CREATE_DETACHED: c_int = 2; } pub mod posix08 { } 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; -#[allow(non_camel_case_types)] // runtime type -type raw_thread = libc::c_void; +#[cfg(windows)] +use libc::types::os::arch::extra::{LPSECURITY_ATTRIBUTES, SIZE_T, + LPVOID, DWORD, LPDWORD, HANDLE}; + +#[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) } } } -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); +#[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 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; } diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp index 90cfd98bc48..486c95a548d 100644 --- a/src/rt/rust_builtin.cpp +++ b/src/rt/rust_builtin.cpp @@ -11,7 +11,6 @@ /* Foreign builtins. */ #include "rust_util.h" -#include "sync/rust_thread.h" #include "sync/lock_and_signal.h" #include "vg/valgrind.h" @@ -385,42 +384,6 @@ rust_signal_little_lock(lock_and_signal *lock) { lock->signal(); } -typedef void(startfn)(void*, void*); - -class raw_thread: public rust_thread { -public: - startfn *raw_start; - void *rust_fn; - void *rust_env; - - raw_thread(startfn *raw_start, void *rust_fn, void *rust_env) - : raw_start(raw_start), rust_fn(rust_fn), rust_env(rust_env) { } - - virtual void run() { - raw_start(rust_fn, rust_env); - } -}; - -extern "C" raw_thread* -rust_raw_thread_start(startfn *raw_start, void *rust_start, void *rust_env) { - assert(raw_start && rust_start); - raw_thread *thread = new raw_thread(raw_start, rust_start, rust_env); - thread->start(); - return thread; -} - -extern "C" void -rust_raw_thread_join(raw_thread *thread) { - assert(thread); - thread->join(); -} - -extern "C" void -rust_raw_thread_delete(raw_thread *thread) { - assert(thread); - delete thread; -} - #ifndef _WIN32 #include #include diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index 275966583d9..3b581e94be7 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -42,9 +42,6 @@ rust_signal_little_lock rust_wait_little_lock tdefl_compress_mem_to_heap tinfl_decompress_mem_to_heap -rust_raw_thread_start -rust_raw_thread_join -rust_raw_thread_delete swap_registers rust_readdir rust_opendir diff --git a/src/rt/sync/rust_thread.cpp b/src/rt/sync/rust_thread.cpp deleted file mode 100644 index 7223d187137..00000000000 --- a/src/rt/sync/rust_thread.cpp +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - - -#include "rust_thread.h" -#include - -const size_t default_stack_sz = 1024*1024; - -rust_thread::rust_thread() : thread(0) { -} - -rust_thread::~rust_thread() { -} - -#if defined(__WIN32__) -static DWORD WINAPI -#elif defined(__GNUC__) -static void * -#else -#error "Platform not supported" -#endif -rust_thread_start(void *ptr) { - rust_thread *thread = (rust_thread *) ptr; - thread->run(); - return 0; -} - -void -rust_thread::start() { -#if defined(__WIN32__) - thread = CreateThread(NULL, default_stack_sz, rust_thread_start, this, 0, NULL); -#else - // PTHREAD_STACK_MIN of some system is larger than default size - // so we check stack_sz to prevent assertion failure. - size_t stack_sz = default_stack_sz; - if (stack_sz < PTHREAD_STACK_MIN) { - stack_sz = PTHREAD_STACK_MIN; - } - pthread_attr_t attr; - CHECKED(pthread_attr_init(&attr)); - CHECKED(pthread_attr_setstacksize(&attr, stack_sz)); - CHECKED(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE)); - CHECKED(pthread_create(&thread, &attr, rust_thread_start, (void *) this)); -#endif -} - -void -rust_thread::join() { -#if defined(__WIN32__) - if (thread) - WaitForSingleObject(thread, INFINITE); -#else - if (thread) - CHECKED(pthread_join(thread, NULL)); -#endif - thread = 0; -} diff --git a/src/rt/sync/rust_thread.h b/src/rt/sync/rust_thread.h deleted file mode 100644 index 257eefceb43..00000000000 --- a/src/rt/sync/rust_thread.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#ifndef RUST_THREAD_H -#define RUST_THREAD_H - -#include "rust_globals.h" - -/** - * Thread utility class. Derive and implement your own run() method. - */ -class rust_thread { - private: -#if defined(__WIN32__) - HANDLE thread; -#else - pthread_t thread; -#endif - public: - - rust_thread(); - virtual ~rust_thread(); - - void start(); - - virtual void run() = 0; - - void join(); -}; - -#endif /* RUST_THREAD_H */