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
This commit is contained in:
Dirkjan Bussink 2013-11-05 14:13:02 +01:00
parent 92065ceb63
commit 47e0bd403a
7 changed files with 154 additions and 182 deletions

View file

@ -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 \

View file

@ -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 {
}

View file

@ -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;
}

View file

@ -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 <sys/types.h>
#include <dirent.h>

View file

@ -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

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#include "rust_thread.h"
#include <limits.h>
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;
}

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 */