Skip to content

Commit

Permalink
auto merge of #10290 : dbussink/rust/thread_in_rust, r=alexcrichton
Browse files Browse the repository at this point in the history
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.

This needs to be reviewed for the Windows parts, I've tested on OS X and Linux.

Fixes #10162
  • Loading branch information
bors committed Nov 5, 2013
2 parents 92065ce + 47e0bd4 commit 7fb583b
Show file tree
Hide file tree
Showing 7 changed files with 153 additions and 181 deletions.
1 change: 0 additions & 1 deletion mk/rt.mk
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
63 changes: 56 additions & 7 deletions src/libstd/libc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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};
Expand Down Expand Up @@ -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};

Expand Down Expand Up @@ -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};
Expand Down Expand Up @@ -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 {}
Expand Down Expand Up @@ -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};
Expand Down Expand Up @@ -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 {
}
Expand All @@ -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,
Expand Down Expand Up @@ -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};
Expand Down Expand Up @@ -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 {
}
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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};

Expand Down Expand Up @@ -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 {
}
Expand Down Expand Up @@ -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};

Expand Down Expand Up @@ -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 {
}
Expand Down Expand Up @@ -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 {
}
Expand Down Expand Up @@ -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 {
}
Expand Down Expand Up @@ -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 {
}
Expand Down
127 changes: 97 additions & 30 deletions src/libstd/rt/thread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Loading

0 comments on commit 7fb583b

Please sign in to comment.