2014-01-25 20:37:51 +13:00
|
|
|
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
|
2013-02-03 18:15:43 -08:00
|
|
|
// 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.
|
|
|
|
|
2013-11-25 18:08:31 -08:00
|
|
|
//! Native os-thread management
|
|
|
|
//!
|
|
|
|
//! This modules contains bindings necessary for managing OS-level threads.
|
|
|
|
//! These functions operate outside of the rust runtime, creating threads
|
|
|
|
//! which are not used for scheduling in any way.
|
|
|
|
|
2014-03-21 18:05:05 -07:00
|
|
|
#![allow(non_camel_case_types)]
|
2013-11-05 14:13:02 +01:00
|
|
|
|
2014-06-07 11:13:26 -07:00
|
|
|
use core::prelude::*;
|
|
|
|
|
2014-07-10 14:19:17 -07:00
|
|
|
use alloc::boxed::Box;
|
2014-06-07 11:13:26 -07:00
|
|
|
use core::mem;
|
|
|
|
use core::uint;
|
2013-02-03 18:15:43 -08:00
|
|
|
use libc;
|
2014-06-07 11:13:26 -07:00
|
|
|
|
|
|
|
use stack;
|
2014-10-23 07:29:41 +02:00
|
|
|
use stack_overflow;
|
2013-11-05 14:13:02 +01:00
|
|
|
|
2014-10-23 07:29:41 +02:00
|
|
|
pub unsafe fn init() {
|
|
|
|
imp::guard::init();
|
|
|
|
stack_overflow::init();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn cleanup() {
|
|
|
|
stack_overflow::cleanup();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(target_os = "windows")]
|
|
|
|
type StartFn = extern "system" fn(*mut libc::c_void) -> imp::rust_thread_return;
|
|
|
|
|
|
|
|
#[cfg(not(target_os = "windows"))]
|
2014-06-25 12:47:34 -07:00
|
|
|
type StartFn = extern "C" fn(*mut libc::c_void) -> imp::rust_thread_return;
|
2013-11-25 18:08:31 -08:00
|
|
|
|
|
|
|
/// This struct represents a native thread's state. This is used to join on an
|
|
|
|
/// existing thread created in the join-able state.
|
|
|
|
pub struct Thread<T> {
|
2014-03-27 15:09:47 -07:00
|
|
|
native: imp::rust_thread,
|
|
|
|
joined: bool,
|
2014-05-05 18:56:44 -07:00
|
|
|
packet: Box<Option<T>>,
|
2013-02-03 18:15:43 -08:00
|
|
|
}
|
|
|
|
|
2013-12-12 18:06:39 -08:00
|
|
|
static DEFAULT_STACK_SIZE: uint = 1024 * 1024;
|
2013-11-05 14:13:02 +01:00
|
|
|
|
2013-11-25 18:08:31 -08:00
|
|
|
// 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
|
2014-09-05 17:28:24 -07:00
|
|
|
// no_stack_check annotation), and then we extract the main function
|
2013-11-25 18:08:31 -08:00
|
|
|
// and invoke it.
|
2014-09-05 17:28:24 -07:00
|
|
|
#[no_stack_check]
|
2014-10-23 07:29:41 +02:00
|
|
|
fn start_thread(main: *mut libc::c_void) -> imp::rust_thread_return {
|
2013-11-25 18:08:31 -08:00
|
|
|
unsafe {
|
2014-08-05 20:53:42 -07:00
|
|
|
stack::record_os_managed_stack_bounds(0, uint::MAX);
|
2014-10-23 07:29:41 +02:00
|
|
|
let handler = stack_overflow::Handler::new();
|
core: Remove the cast module
This commit revisits the `cast` module in libcore and libstd, and scrutinizes
all functions inside of it. The result was to remove the `cast` module entirely,
folding all functionality into the `mem` module. Specifically, this is the fate
of each function in the `cast` module.
* transmute - This function was moved to `mem`, but it is now marked as
#[unstable]. This is due to planned changes to the `transmute`
function and how it can be invoked (see the #[unstable] comment).
For more information, see RFC 5 and #12898
* transmute_copy - This function was moved to `mem`, with clarification that is
is not an error to invoke it with T/U that are different
sizes, but rather that it is strongly discouraged. This
function is now #[stable]
* forget - This function was moved to `mem` and marked #[stable]
* bump_box_refcount - This function was removed due to the deprecation of
managed boxes as well as its questionable utility.
* transmute_mut - This function was previously deprecated, and removed as part
of this commit.
* transmute_mut_unsafe - This function doesn't serve much of a purpose when it
can be achieved with an `as` in safe code, so it was
removed.
* transmute_lifetime - This function was removed because it is likely a strong
indication that code is incorrect in the first place.
* transmute_mut_lifetime - This function was removed for the same reasons as
`transmute_lifetime`
* copy_lifetime - This function was moved to `mem`, but it is marked
`#[unstable]` now due to the likelihood of being removed in
the future if it is found to not be very useful.
* copy_mut_lifetime - This function was also moved to `mem`, but had the same
treatment as `copy_lifetime`.
* copy_lifetime_vec - This function was removed because it is not used today,
and its existence is not necessary with DST
(copy_lifetime will suffice).
In summary, the cast module was stripped down to these functions, and then the
functions were moved to the `mem` module.
transmute - #[unstable]
transmute_copy - #[stable]
forget - #[stable]
copy_lifetime - #[unstable]
copy_mut_lifetime - #[unstable]
[breaking-change]
2014-05-09 10:34:51 -07:00
|
|
|
let f: Box<proc()> = mem::transmute(main);
|
2013-11-25 18:08:31 -08:00
|
|
|
(*f)();
|
2014-10-23 07:29:41 +02:00
|
|
|
drop(handler);
|
core: Remove the cast module
This commit revisits the `cast` module in libcore and libstd, and scrutinizes
all functions inside of it. The result was to remove the `cast` module entirely,
folding all functionality into the `mem` module. Specifically, this is the fate
of each function in the `cast` module.
* transmute - This function was moved to `mem`, but it is now marked as
#[unstable]. This is due to planned changes to the `transmute`
function and how it can be invoked (see the #[unstable] comment).
For more information, see RFC 5 and #12898
* transmute_copy - This function was moved to `mem`, with clarification that is
is not an error to invoke it with T/U that are different
sizes, but rather that it is strongly discouraged. This
function is now #[stable]
* forget - This function was moved to `mem` and marked #[stable]
* bump_box_refcount - This function was removed due to the deprecation of
managed boxes as well as its questionable utility.
* transmute_mut - This function was previously deprecated, and removed as part
of this commit.
* transmute_mut_unsafe - This function doesn't serve much of a purpose when it
can be achieved with an `as` in safe code, so it was
removed.
* transmute_lifetime - This function was removed because it is likely a strong
indication that code is incorrect in the first place.
* transmute_mut_lifetime - This function was removed for the same reasons as
`transmute_lifetime`
* copy_lifetime - This function was moved to `mem`, but it is marked
`#[unstable]` now due to the likelihood of being removed in
the future if it is found to not be very useful.
* copy_mut_lifetime - This function was also moved to `mem`, but had the same
treatment as `copy_lifetime`.
* copy_lifetime_vec - This function was removed because it is not used today,
and its existence is not necessary with DST
(copy_lifetime will suffice).
In summary, the cast module was stripped down to these functions, and then the
functions were moved to the `mem` module.
transmute - #[unstable]
transmute_copy - #[stable]
forget - #[stable]
copy_lifetime - #[unstable]
copy_mut_lifetime - #[unstable]
[breaking-change]
2014-05-09 10:34:51 -07:00
|
|
|
mem::transmute(0 as imp::rust_thread_return)
|
2013-11-25 18:08:31 -08:00
|
|
|
}
|
|
|
|
}
|
2013-11-05 14:13:02 +01:00
|
|
|
|
2014-10-23 07:29:41 +02:00
|
|
|
#[no_stack_check]
|
|
|
|
#[cfg(target_os = "windows")]
|
|
|
|
extern "system" fn thread_start(main: *mut libc::c_void) -> imp::rust_thread_return {
|
|
|
|
return start_thread(main);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[no_stack_check]
|
|
|
|
#[cfg(not(target_os = "windows"))]
|
|
|
|
extern fn thread_start(main: *mut libc::c_void) -> imp::rust_thread_return {
|
|
|
|
return start_thread(main);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the last writable byte of the main thread's stack next to the guard
|
|
|
|
/// page. Must be called from the main thread.
|
|
|
|
pub fn main_guard_page() -> uint {
|
|
|
|
unsafe {
|
|
|
|
imp::guard::main()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the last writable byte of the current thread's stack next to the
|
|
|
|
/// guard page. Must not be called from the main thread.
|
|
|
|
pub fn current_guard_page() -> uint {
|
|
|
|
unsafe {
|
|
|
|
imp::guard::current()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-25 18:08:31 -08:00
|
|
|
// There are two impl blocks b/c if T were specified at the top then it's just a
|
|
|
|
// pain to specify a type parameter on Thread::spawn (which doesn't need the
|
|
|
|
// type parameter).
|
|
|
|
impl Thread<()> {
|
|
|
|
|
|
|
|
/// Starts execution of a new OS thread.
|
|
|
|
///
|
|
|
|
/// This function will not wait for the thread to join, but a handle to the
|
|
|
|
/// thread will be returned.
|
|
|
|
///
|
|
|
|
/// Note that the handle returned is used to acquire the return value of the
|
|
|
|
/// procedure `main`. The `join` function will wait for the thread to finish
|
|
|
|
/// and return the value that `main` generated.
|
|
|
|
///
|
|
|
|
/// Also note that the `Thread` returned will *always* wait for the thread
|
|
|
|
/// to finish executing. This means that even if `join` is not explicitly
|
|
|
|
/// called, when the `Thread` falls out of scope its destructor will block
|
|
|
|
/// waiting for the OS thread.
|
2014-04-07 13:30:48 -07:00
|
|
|
pub fn start<T: Send>(main: proc():Send -> T) -> Thread<T> {
|
2013-12-12 18:01:59 -08:00
|
|
|
Thread::start_stack(DEFAULT_STACK_SIZE, main)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Performs the same functionality as `start`, but specifies an explicit
|
|
|
|
/// stack size for the new thread.
|
2014-04-07 13:30:48 -07:00
|
|
|
pub fn start_stack<T: Send>(stack: uint, main: proc():Send -> T) -> Thread<T> {
|
2013-11-25 18:08:31 -08:00
|
|
|
|
|
|
|
// We need the address of the packet to fill in to be stable so when
|
2014-05-05 18:56:44 -07:00
|
|
|
// `main` fills it in it's still valid, so allocate an extra box to do
|
2013-11-25 18:08:31 -08:00
|
|
|
// so.
|
2014-04-25 01:08:02 -07:00
|
|
|
let packet = box None;
|
2013-11-25 18:08:31 -08:00
|
|
|
let packet2: *mut Option<T> = unsafe {
|
2014-06-25 12:47:34 -07:00
|
|
|
*mem::transmute::<&Box<Option<T>>, *const *mut Option<T>>(&packet)
|
2013-11-25 18:08:31 -08:00
|
|
|
};
|
2014-03-08 18:21:49 -08:00
|
|
|
let main = proc() unsafe { *packet2 = Some(main()); };
|
2014-04-25 01:08:02 -07:00
|
|
|
let native = unsafe { imp::create(stack, box main) };
|
2013-10-17 01:40:33 -07:00
|
|
|
|
2013-02-03 18:15:43 -08:00
|
|
|
Thread {
|
2013-11-05 14:13:02 +01:00
|
|
|
native: native,
|
2013-10-17 01:40:33 -07:00
|
|
|
joined: false,
|
2013-11-25 18:08:31 -08:00
|
|
|
packet: packet,
|
2013-02-03 18:15:43 -08:00
|
|
|
}
|
|
|
|
}
|
2013-07-27 12:05:15 -07:00
|
|
|
|
2013-11-25 18:08:31 -08:00
|
|
|
/// This will spawn a new thread, but it will not wait for the thread to
|
|
|
|
/// finish, nor is it possible to wait for the thread to finish.
|
|
|
|
///
|
|
|
|
/// This corresponds to creating threads in the 'detached' state on unix
|
|
|
|
/// systems. Note that platforms may not keep the main program alive even if
|
|
|
|
/// there are detached thread still running around.
|
2014-04-07 13:30:48 -07:00
|
|
|
pub fn spawn(main: proc():Send) {
|
2013-12-12 18:06:39 -08:00
|
|
|
Thread::spawn_stack(DEFAULT_STACK_SIZE, main)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Performs the same functionality as `spawn`, but explicitly specifies a
|
|
|
|
/// stack size for the new thread.
|
2014-04-07 13:30:48 -07:00
|
|
|
pub fn spawn_stack(stack: uint, main: proc():Send) {
|
2013-11-25 18:08:31 -08:00
|
|
|
unsafe {
|
2014-04-25 01:08:02 -07:00
|
|
|
let handle = imp::create(stack, box main);
|
2013-12-05 18:19:06 -08:00
|
|
|
imp::detach(handle);
|
2013-11-25 18:08:31 -08:00
|
|
|
}
|
|
|
|
}
|
2013-12-05 18:19:06 -08:00
|
|
|
|
|
|
|
/// Relinquishes the CPU slot that this OS-thread is currently using,
|
|
|
|
/// allowing another thread to run for awhile.
|
|
|
|
pub fn yield_now() {
|
|
|
|
unsafe { imp::yield_now(); }
|
|
|
|
}
|
2013-11-25 18:08:31 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: Send> Thread<T> {
|
|
|
|
/// Wait for this thread to finish, returning the result of the thread's
|
|
|
|
/// calculation.
|
|
|
|
pub fn join(mut self) -> T {
|
2013-07-27 12:05:15 -07:00
|
|
|
assert!(!self.joined);
|
2013-12-05 18:19:06 -08:00
|
|
|
unsafe { imp::join(self.native) };
|
2013-10-28 16:56:24 -07:00
|
|
|
self.joined = true;
|
2013-11-25 18:08:31 -08:00
|
|
|
assert!(self.packet.is_some());
|
2014-08-18 17:52:38 -07:00
|
|
|
self.packet.take().unwrap()
|
2013-07-27 12:05:15 -07:00
|
|
|
}
|
2013-02-03 18:15:43 -08:00
|
|
|
}
|
|
|
|
|
2013-11-25 18:08:31 -08:00
|
|
|
#[unsafe_destructor]
|
|
|
|
impl<T: Send> Drop for Thread<T> {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
// This is required for correctness. If this is not done then the thread
|
|
|
|
// would fill in a return box which no longer exists.
|
|
|
|
if !self.joined {
|
2013-12-05 18:19:06 -08:00
|
|
|
unsafe { imp::join(self.native) };
|
2013-11-25 18:08:31 -08:00
|
|
|
}
|
2013-11-05 14:13:02 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(windows)]
|
2014-10-23 07:29:41 +02:00
|
|
|
#[allow(non_snake_case)]
|
2013-12-05 18:19:06 -08:00
|
|
|
mod imp {
|
2014-06-07 11:13:26 -07:00
|
|
|
use core::prelude::*;
|
|
|
|
|
2014-07-10 14:19:17 -07:00
|
|
|
use alloc::boxed::Box;
|
2014-06-07 11:13:26 -07:00
|
|
|
use core::cmp;
|
|
|
|
use core::mem;
|
|
|
|
use core::ptr;
|
2013-12-15 18:17:43 -08:00
|
|
|
use libc;
|
2013-12-05 18:19:06 -08:00
|
|
|
use libc::types::os::arch::extra::{LPSECURITY_ATTRIBUTES, SIZE_T, BOOL,
|
|
|
|
LPVOID, DWORD, LPDWORD, HANDLE};
|
2014-06-07 11:13:26 -07:00
|
|
|
use stack::RED_ZONE;
|
2013-12-05 18:19:06 -08:00
|
|
|
|
|
|
|
pub type rust_thread = HANDLE;
|
|
|
|
pub type rust_thread_return = DWORD;
|
|
|
|
|
2014-10-23 07:29:41 +02:00
|
|
|
pub mod guard {
|
|
|
|
pub unsafe fn main() -> uint {
|
|
|
|
0
|
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn current() -> uint {
|
|
|
|
0
|
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn init() {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-05 18:56:44 -07:00
|
|
|
pub unsafe fn create(stack: uint, p: Box<proc():Send>) -> rust_thread {
|
core: Remove the cast module
This commit revisits the `cast` module in libcore and libstd, and scrutinizes
all functions inside of it. The result was to remove the `cast` module entirely,
folding all functionality into the `mem` module. Specifically, this is the fate
of each function in the `cast` module.
* transmute - This function was moved to `mem`, but it is now marked as
#[unstable]. This is due to planned changes to the `transmute`
function and how it can be invoked (see the #[unstable] comment).
For more information, see RFC 5 and #12898
* transmute_copy - This function was moved to `mem`, with clarification that is
is not an error to invoke it with T/U that are different
sizes, but rather that it is strongly discouraged. This
function is now #[stable]
* forget - This function was moved to `mem` and marked #[stable]
* bump_box_refcount - This function was removed due to the deprecation of
managed boxes as well as its questionable utility.
* transmute_mut - This function was previously deprecated, and removed as part
of this commit.
* transmute_mut_unsafe - This function doesn't serve much of a purpose when it
can be achieved with an `as` in safe code, so it was
removed.
* transmute_lifetime - This function was removed because it is likely a strong
indication that code is incorrect in the first place.
* transmute_mut_lifetime - This function was removed for the same reasons as
`transmute_lifetime`
* copy_lifetime - This function was moved to `mem`, but it is marked
`#[unstable]` now due to the likelihood of being removed in
the future if it is found to not be very useful.
* copy_mut_lifetime - This function was also moved to `mem`, but had the same
treatment as `copy_lifetime`.
* copy_lifetime_vec - This function was removed because it is not used today,
and its existence is not necessary with DST
(copy_lifetime will suffice).
In summary, the cast module was stripped down to these functions, and then the
functions were moved to the `mem` module.
transmute - #[unstable]
transmute_copy - #[stable]
forget - #[stable]
copy_lifetime - #[unstable]
copy_mut_lifetime - #[unstable]
[breaking-change]
2014-05-09 10:34:51 -07:00
|
|
|
let arg: *mut libc::c_void = mem::transmute(p);
|
2014-01-28 13:21:31 +01:00
|
|
|
// 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);
|
2014-09-14 20:27:36 -07:00
|
|
|
let ret = CreateThread(ptr::null_mut(), stack_size as libc::size_t,
|
|
|
|
super::thread_start, arg, 0, ptr::null_mut());
|
2014-04-18 10:36:16 -07:00
|
|
|
|
|
|
|
if ret as uint == 0 {
|
|
|
|
// be sure to not leak the closure
|
core: Remove the cast module
This commit revisits the `cast` module in libcore and libstd, and scrutinizes
all functions inside of it. The result was to remove the `cast` module entirely,
folding all functionality into the `mem` module. Specifically, this is the fate
of each function in the `cast` module.
* transmute - This function was moved to `mem`, but it is now marked as
#[unstable]. This is due to planned changes to the `transmute`
function and how it can be invoked (see the #[unstable] comment).
For more information, see RFC 5 and #12898
* transmute_copy - This function was moved to `mem`, with clarification that is
is not an error to invoke it with T/U that are different
sizes, but rather that it is strongly discouraged. This
function is now #[stable]
* forget - This function was moved to `mem` and marked #[stable]
* bump_box_refcount - This function was removed due to the deprecation of
managed boxes as well as its questionable utility.
* transmute_mut - This function was previously deprecated, and removed as part
of this commit.
* transmute_mut_unsafe - This function doesn't serve much of a purpose when it
can be achieved with an `as` in safe code, so it was
removed.
* transmute_lifetime - This function was removed because it is likely a strong
indication that code is incorrect in the first place.
* transmute_mut_lifetime - This function was removed for the same reasons as
`transmute_lifetime`
* copy_lifetime - This function was moved to `mem`, but it is marked
`#[unstable]` now due to the likelihood of being removed in
the future if it is found to not be very useful.
* copy_mut_lifetime - This function was also moved to `mem`, but had the same
treatment as `copy_lifetime`.
* copy_lifetime_vec - This function was removed because it is not used today,
and its existence is not necessary with DST
(copy_lifetime will suffice).
In summary, the cast module was stripped down to these functions, and then the
functions were moved to the `mem` module.
transmute - #[unstable]
transmute_copy - #[stable]
forget - #[stable]
copy_lifetime - #[unstable]
copy_mut_lifetime - #[unstable]
[breaking-change]
2014-05-09 10:34:51 -07:00
|
|
|
let _p: Box<proc():Send> = mem::transmute(arg);
|
2014-10-09 15:17:22 -04:00
|
|
|
panic!("failed to spawn native thread: {}", ret);
|
2014-04-18 10:36:16 -07:00
|
|
|
}
|
|
|
|
return ret;
|
2013-12-05 18:19:06 -08:00
|
|
|
}
|
2013-11-25 18:08:31 -08:00
|
|
|
|
2013-12-05 18:19:06 -08:00
|
|
|
pub unsafe fn join(native: rust_thread) {
|
|
|
|
use libc::consts::os::extra::INFINITE;
|
|
|
|
WaitForSingleObject(native, INFINITE);
|
|
|
|
}
|
2013-11-05 14:13:02 +01:00
|
|
|
|
2013-12-05 18:19:06 -08:00
|
|
|
pub unsafe fn detach(native: rust_thread) {
|
|
|
|
assert!(libc::CloseHandle(native) != 0);
|
|
|
|
}
|
2013-11-05 14:13:02 +01:00
|
|
|
|
2013-12-05 18:19:06 -08:00
|
|
|
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();
|
|
|
|
}
|
2013-11-05 14:13:02 +01:00
|
|
|
|
2014-07-19 00:45:17 +12:00
|
|
|
#[allow(non_snake_case)]
|
2013-12-05 18:19:06 -08:00
|
|
|
extern "system" {
|
|
|
|
fn CreateThread(lpThreadAttributes: LPSECURITY_ATTRIBUTES,
|
|
|
|
dwStackSize: SIZE_T,
|
|
|
|
lpStartAddress: super::StartFn,
|
|
|
|
lpParameter: LPVOID,
|
|
|
|
dwCreationFlags: DWORD,
|
|
|
|
lpThreadId: LPDWORD) -> HANDLE;
|
|
|
|
fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD;
|
|
|
|
fn SwitchToThread() -> BOOL;
|
|
|
|
}
|
2013-11-05 14:13:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(unix)]
|
2013-12-05 18:19:06 -08:00
|
|
|
mod imp {
|
2014-06-07 11:13:26 -07:00
|
|
|
use core::prelude::*;
|
|
|
|
|
2014-07-10 14:19:17 -07:00
|
|
|
use alloc::boxed::Box;
|
2014-06-07 11:13:26 -07:00
|
|
|
use core::cmp;
|
|
|
|
use core::mem;
|
|
|
|
use core::ptr;
|
2014-01-28 13:21:31 +01:00
|
|
|
use libc::consts::os::posix01::{PTHREAD_CREATE_JOINABLE, PTHREAD_STACK_MIN};
|
2013-12-05 18:19:06 -08:00
|
|
|
use libc;
|
2014-06-07 11:13:26 -07:00
|
|
|
|
|
|
|
use stack::RED_ZONE;
|
2013-11-05 14:13:02 +01:00
|
|
|
|
2013-12-05 18:19:06 -08:00
|
|
|
pub type rust_thread = libc::pthread_t;
|
2014-06-25 12:47:34 -07:00
|
|
|
pub type rust_thread_return = *mut u8;
|
2013-12-05 18:19:06 -08:00
|
|
|
|
2014-10-23 07:29:41 +02:00
|
|
|
#[cfg(all(not(target_os = "linux"), not(target_os = "macos")))]
|
|
|
|
pub mod guard {
|
|
|
|
pub unsafe fn current() -> uint {
|
|
|
|
0
|
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn main() -> uint {
|
|
|
|
0
|
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn init() {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
|
|
|
pub mod guard {
|
|
|
|
use super::*;
|
|
|
|
#[cfg(any(target_os = "linux", target_os = "android"))]
|
|
|
|
use core::mem;
|
|
|
|
#[cfg(any(target_os = "linux", target_os = "android"))]
|
|
|
|
use core::ptr;
|
|
|
|
use libc;
|
|
|
|
use libc::funcs::posix88::mman::{mmap};
|
|
|
|
use libc::consts::os::posix88::{PROT_NONE,
|
|
|
|
MAP_PRIVATE,
|
|
|
|
MAP_ANON,
|
|
|
|
MAP_FAILED,
|
|
|
|
MAP_FIXED};
|
|
|
|
|
|
|
|
// These are initialized in init() and only read from after
|
|
|
|
static mut PAGE_SIZE: uint = 0;
|
|
|
|
static mut GUARD_PAGE: uint = 0;
|
|
|
|
|
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
unsafe fn get_stack_start() -> *mut libc::c_void {
|
|
|
|
current() as *mut libc::c_void
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(any(target_os = "linux", target_os = "android"))]
|
|
|
|
unsafe fn get_stack_start() -> *mut libc::c_void {
|
|
|
|
let mut attr: libc::pthread_attr_t = mem::zeroed();
|
|
|
|
if pthread_getattr_np(pthread_self(), &mut attr) != 0 {
|
2014-10-09 15:17:22 -04:00
|
|
|
panic!("failed to get thread attributes");
|
2014-10-23 07:29:41 +02:00
|
|
|
}
|
|
|
|
let mut stackaddr = ptr::null_mut();
|
|
|
|
let mut stacksize = 0;
|
|
|
|
if pthread_attr_getstack(&attr, &mut stackaddr, &mut stacksize) != 0 {
|
2014-10-09 15:17:22 -04:00
|
|
|
panic!("failed to get stack information");
|
2014-10-23 07:29:41 +02:00
|
|
|
}
|
|
|
|
if pthread_attr_destroy(&mut attr) != 0 {
|
2014-10-09 15:17:22 -04:00
|
|
|
panic!("failed to destroy thread attributes");
|
2014-10-23 07:29:41 +02:00
|
|
|
}
|
|
|
|
stackaddr
|
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn init() {
|
|
|
|
let psize = libc::sysconf(libc::consts::os::sysconf::_SC_PAGESIZE);
|
|
|
|
if psize == -1 {
|
2014-10-09 15:17:22 -04:00
|
|
|
panic!("failed to get page size");
|
2014-10-23 07:29:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
PAGE_SIZE = psize as uint;
|
|
|
|
|
|
|
|
let stackaddr = get_stack_start();
|
|
|
|
|
|
|
|
// Rellocate the last page of the stack.
|
|
|
|
// This ensures SIGBUS will be raised on
|
|
|
|
// stack overflow.
|
|
|
|
let result = mmap(stackaddr,
|
|
|
|
PAGE_SIZE as libc::size_t,
|
|
|
|
PROT_NONE,
|
|
|
|
MAP_PRIVATE | MAP_ANON | MAP_FIXED,
|
|
|
|
-1,
|
|
|
|
0);
|
|
|
|
|
|
|
|
if result != stackaddr || result == MAP_FAILED {
|
2014-10-09 15:17:22 -04:00
|
|
|
panic!("failed to allocate a guard page");
|
2014-10-23 07:29:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
let offset = if cfg!(target_os = "linux") {
|
|
|
|
2
|
|
|
|
} else {
|
|
|
|
1
|
|
|
|
};
|
|
|
|
|
|
|
|
GUARD_PAGE = stackaddr as uint + offset * PAGE_SIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn main() -> uint {
|
|
|
|
GUARD_PAGE
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
pub unsafe fn current() -> uint {
|
|
|
|
(pthread_get_stackaddr_np(pthread_self()) as libc::size_t -
|
|
|
|
pthread_get_stacksize_np(pthread_self())) as uint
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(any(target_os = "linux", target_os = "android"))]
|
|
|
|
pub unsafe fn current() -> uint {
|
|
|
|
let mut attr: libc::pthread_attr_t = mem::zeroed();
|
|
|
|
if pthread_getattr_np(pthread_self(), &mut attr) != 0 {
|
2014-10-09 15:17:22 -04:00
|
|
|
panic!("failed to get thread attributes");
|
2014-10-23 07:29:41 +02:00
|
|
|
}
|
|
|
|
let mut guardsize = 0;
|
|
|
|
if pthread_attr_getguardsize(&attr, &mut guardsize) != 0 {
|
2014-10-09 15:17:22 -04:00
|
|
|
panic!("failed to get stack guard page");
|
2014-10-23 07:29:41 +02:00
|
|
|
}
|
|
|
|
if guardsize == 0 {
|
2014-10-09 15:17:22 -04:00
|
|
|
panic!("there is no guard page");
|
2014-10-23 07:29:41 +02:00
|
|
|
}
|
|
|
|
let mut stackaddr = ptr::null_mut();
|
|
|
|
let mut stacksize = 0;
|
|
|
|
if pthread_attr_getstack(&attr, &mut stackaddr, &mut stacksize) != 0 {
|
2014-10-09 15:17:22 -04:00
|
|
|
panic!("failed to get stack information");
|
2014-10-23 07:29:41 +02:00
|
|
|
}
|
|
|
|
if pthread_attr_destroy(&mut attr) != 0 {
|
2014-10-09 15:17:22 -04:00
|
|
|
panic!("failed to destroy thread attributes");
|
2014-10-23 07:29:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
stackaddr as uint + guardsize as uint
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-05 18:56:44 -07:00
|
|
|
pub unsafe fn create(stack: uint, p: Box<proc():Send>) -> rust_thread {
|
2014-05-23 20:53:56 -07:00
|
|
|
let mut native: libc::pthread_t = mem::zeroed();
|
|
|
|
let mut attr: libc::pthread_attr_t = mem::zeroed();
|
2013-12-05 18:19:06 -08:00
|
|
|
assert_eq!(pthread_attr_init(&mut attr), 0);
|
|
|
|
assert_eq!(pthread_attr_setdetachstate(&mut attr,
|
|
|
|
PTHREAD_CREATE_JOINABLE), 0);
|
|
|
|
|
2014-01-28 13:21:31 +01:00
|
|
|
// Reserve room for the red zone, the runtime's stack of last resort.
|
2014-02-25 16:15:10 -08:00
|
|
|
let stack_size = cmp::max(stack, RED_ZONE + min_stack_size(&attr) as uint);
|
2014-01-28 13:21:31 +01:00
|
|
|
match pthread_attr_setstacksize(&mut attr, stack_size as libc::size_t) {
|
|
|
|
0 => {
|
|
|
|
},
|
|
|
|
libc::EINVAL => {
|
|
|
|
// EINVAL means |stack_size| is either too small or not a
|
|
|
|
// multiple of the system page size. Because it's definitely
|
|
|
|
// >= PTHREAD_STACK_MIN, it must be an alignment issue.
|
2014-07-02 21:27:07 -04:00
|
|
|
// Round up to the nearest page and try again.
|
2014-06-07 11:13:26 -07:00
|
|
|
let page_size = libc::sysconf(libc::_SC_PAGESIZE) as uint;
|
|
|
|
let stack_size = (stack_size + page_size - 1) &
|
|
|
|
(-(page_size as int - 1) as uint - 1);
|
2014-01-28 13:21:31 +01:00
|
|
|
assert_eq!(pthread_attr_setstacksize(&mut attr, stack_size as libc::size_t), 0);
|
|
|
|
},
|
|
|
|
errno => {
|
|
|
|
// This cannot really happen.
|
2014-10-09 15:17:22 -04:00
|
|
|
panic!("pthread_attr_setstacksize() error: {}", errno);
|
2014-01-28 13:21:31 +01:00
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2014-06-25 12:47:34 -07:00
|
|
|
let arg: *mut libc::c_void = mem::transmute(p);
|
2014-04-18 10:36:16 -07:00
|
|
|
let ret = pthread_create(&mut native, &attr, super::thread_start, arg);
|
2014-04-10 22:38:05 -07:00
|
|
|
assert_eq!(pthread_attr_destroy(&mut attr), 0);
|
2014-04-18 10:36:16 -07:00
|
|
|
|
|
|
|
if ret != 0 {
|
|
|
|
// be sure to not leak the closure
|
core: Remove the cast module
This commit revisits the `cast` module in libcore and libstd, and scrutinizes
all functions inside of it. The result was to remove the `cast` module entirely,
folding all functionality into the `mem` module. Specifically, this is the fate
of each function in the `cast` module.
* transmute - This function was moved to `mem`, but it is now marked as
#[unstable]. This is due to planned changes to the `transmute`
function and how it can be invoked (see the #[unstable] comment).
For more information, see RFC 5 and #12898
* transmute_copy - This function was moved to `mem`, with clarification that is
is not an error to invoke it with T/U that are different
sizes, but rather that it is strongly discouraged. This
function is now #[stable]
* forget - This function was moved to `mem` and marked #[stable]
* bump_box_refcount - This function was removed due to the deprecation of
managed boxes as well as its questionable utility.
* transmute_mut - This function was previously deprecated, and removed as part
of this commit.
* transmute_mut_unsafe - This function doesn't serve much of a purpose when it
can be achieved with an `as` in safe code, so it was
removed.
* transmute_lifetime - This function was removed because it is likely a strong
indication that code is incorrect in the first place.
* transmute_mut_lifetime - This function was removed for the same reasons as
`transmute_lifetime`
* copy_lifetime - This function was moved to `mem`, but it is marked
`#[unstable]` now due to the likelihood of being removed in
the future if it is found to not be very useful.
* copy_mut_lifetime - This function was also moved to `mem`, but had the same
treatment as `copy_lifetime`.
* copy_lifetime_vec - This function was removed because it is not used today,
and its existence is not necessary with DST
(copy_lifetime will suffice).
In summary, the cast module was stripped down to these functions, and then the
functions were moved to the `mem` module.
transmute - #[unstable]
transmute_copy - #[stable]
forget - #[stable]
copy_lifetime - #[unstable]
copy_mut_lifetime - #[unstable]
[breaking-change]
2014-05-09 10:34:51 -07:00
|
|
|
let _p: Box<proc():Send> = mem::transmute(arg);
|
2014-10-09 15:17:22 -04:00
|
|
|
panic!("failed to spawn native thread: {}", ret);
|
2014-04-18 10:36:16 -07:00
|
|
|
}
|
2013-12-05 18:19:06 -08:00
|
|
|
native
|
|
|
|
}
|
2013-02-03 18:15:43 -08:00
|
|
|
|
2013-12-05 18:19:06 -08:00
|
|
|
pub unsafe fn join(native: rust_thread) {
|
2014-09-14 20:27:36 -07:00
|
|
|
assert_eq!(pthread_join(native, ptr::null_mut()), 0);
|
2013-12-05 18:19:06 -08:00
|
|
|
}
|
2013-11-05 14:13:02 +01:00
|
|
|
|
2013-12-05 18:19:06 -08:00
|
|
|
pub unsafe fn detach(native: rust_thread) {
|
|
|
|
assert_eq!(pthread_detach(native), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn yield_now() { assert_eq!(sched_yield(), 0); }
|
2014-01-29 18:19:23 +01:00
|
|
|
// glibc >= 2.15 has a __pthread_get_minstack() function that returns
|
|
|
|
// PTHREAD_STACK_MIN plus however many bytes are needed for thread-local
|
|
|
|
// storage. We need that information to avoid blowing up when a small stack
|
|
|
|
// is created in an application with big thread-local storage requirements.
|
|
|
|
// See #6233 for rationale and details.
|
|
|
|
//
|
2014-02-25 16:15:10 -08:00
|
|
|
// Link weakly to the symbol for compatibility with older versions of glibc.
|
|
|
|
// Assumes that we've been dynamically linked to libpthread but that is
|
|
|
|
// currently always the case. Note that you need to check that the symbol
|
|
|
|
// is non-null before calling it!
|
2014-03-19 23:04:25 -07:00
|
|
|
#[cfg(target_os = "linux")]
|
2014-06-25 12:47:34 -07:00
|
|
|
fn min_stack_size(attr: *const libc::pthread_attr_t) -> libc::size_t {
|
|
|
|
type F = unsafe extern "C" fn(*const libc::pthread_attr_t) -> libc::size_t;
|
2014-02-25 16:15:10 -08:00
|
|
|
extern {
|
|
|
|
#[linkage = "extern_weak"]
|
2014-06-25 12:47:34 -07:00
|
|
|
static __pthread_get_minstack: *const ();
|
2014-02-25 16:15:10 -08:00
|
|
|
}
|
|
|
|
if __pthread_get_minstack.is_null() {
|
|
|
|
PTHREAD_STACK_MIN
|
|
|
|
} else {
|
2014-06-25 12:47:34 -07:00
|
|
|
unsafe { mem::transmute::<*const (), F>(__pthread_get_minstack)(attr) }
|
2014-01-29 18:19:23 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-25 16:15:10 -08:00
|
|
|
// __pthread_get_minstack() is marked as weak but extern_weak linkage is
|
|
|
|
// not supported on OS X, hence this kludge...
|
|
|
|
#[cfg(not(target_os = "linux"))]
|
2014-06-25 12:47:34 -07:00
|
|
|
fn min_stack_size(_: *const libc::pthread_attr_t) -> libc::size_t {
|
2014-02-25 16:15:10 -08:00
|
|
|
PTHREAD_STACK_MIN
|
|
|
|
}
|
|
|
|
|
2014-10-23 07:29:41 +02:00
|
|
|
#[cfg(any(target_os = "linux"))]
|
|
|
|
extern {
|
|
|
|
pub fn pthread_self() -> libc::pthread_t;
|
|
|
|
pub fn pthread_getattr_np(native: libc::pthread_t,
|
|
|
|
attr: *mut libc::pthread_attr_t) -> libc::c_int;
|
|
|
|
pub fn pthread_attr_getguardsize(attr: *const libc::pthread_attr_t,
|
|
|
|
guardsize: *mut libc::size_t) -> libc::c_int;
|
|
|
|
pub fn pthread_attr_getstack(attr: *const libc::pthread_attr_t,
|
|
|
|
stackaddr: *mut *mut libc::c_void,
|
|
|
|
stacksize: *mut libc::size_t) -> libc::c_int;
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
extern {
|
|
|
|
pub fn pthread_self() -> libc::pthread_t;
|
|
|
|
pub fn pthread_get_stackaddr_np(thread: libc::pthread_t) -> *mut libc::c_void;
|
|
|
|
pub fn pthread_get_stacksize_np(thread: libc::pthread_t) -> libc::size_t;
|
|
|
|
}
|
|
|
|
|
2013-12-05 18:19:06 -08:00
|
|
|
extern {
|
|
|
|
fn pthread_create(native: *mut libc::pthread_t,
|
2014-06-25 12:47:34 -07:00
|
|
|
attr: *const libc::pthread_attr_t,
|
2013-12-05 18:19:06 -08:00
|
|
|
f: super::StartFn,
|
2014-06-25 12:47:34 -07:00
|
|
|
value: *mut libc::c_void) -> libc::c_int;
|
2013-12-05 18:19:06 -08:00
|
|
|
fn pthread_join(native: libc::pthread_t,
|
2014-06-25 12:47:34 -07:00
|
|
|
value: *mut *mut libc::c_void) -> libc::c_int;
|
2013-12-05 18:19:06 -08:00
|
|
|
fn pthread_attr_init(attr: *mut libc::pthread_attr_t) -> libc::c_int;
|
2014-10-23 07:29:41 +02:00
|
|
|
pub fn pthread_attr_destroy(attr: *mut libc::pthread_attr_t) -> libc::c_int;
|
2013-12-05 18:19:06 -08:00
|
|
|
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;
|
|
|
|
fn pthread_detach(thread: libc::pthread_t) -> libc::c_int;
|
|
|
|
fn sched_yield() -> libc::c_int;
|
|
|
|
}
|
2013-11-25 18:08:31 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::Thread;
|
|
|
|
|
|
|
|
#[test]
|
2014-01-26 22:42:26 -05:00
|
|
|
fn smoke() { Thread::start(proc (){}).join(); }
|
2013-11-25 18:08:31 -08:00
|
|
|
|
|
|
|
#[test]
|
2014-04-21 17:58:52 -04:00
|
|
|
fn data() { assert_eq!(Thread::start(proc () { 1i }).join(), 1); }
|
2013-11-25 18:08:31 -08:00
|
|
|
|
|
|
|
#[test]
|
2014-01-26 22:42:26 -05:00
|
|
|
fn detached() { Thread::spawn(proc () {}) }
|
2014-01-28 13:21:31 +01:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn small_stacks() {
|
2014-04-21 17:58:52 -04:00
|
|
|
assert_eq!(42i, Thread::start_stack(0, proc () 42i).join());
|
|
|
|
assert_eq!(42i, Thread::start_stack(1, proc () 42i).join());
|
2014-01-28 13:21:31 +01:00
|
|
|
}
|
2013-02-03 18:15:43 -08:00
|
|
|
}
|