Auto merge of #23330 - alexcrichton:thread-sleep, r=aturon
This function is the current replacement for `std::old_io::timer` which will soon be deprecated. This function is unstable and has its own feature gate as it does not yet have an RFC nor has it existed for very long.
This commit is contained in:
commit
bfac337daa
4 changed files with 197 additions and 221 deletions
|
@ -8,28 +8,23 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use core::prelude::*;
|
||||
use prelude::v1::*;
|
||||
|
||||
use boxed::Box;
|
||||
use mem;
|
||||
use usize;
|
||||
use libc;
|
||||
use thunk::Thunk;
|
||||
use sys_common::stack;
|
||||
use sys::{thread, stack_overflow};
|
||||
use sys::stack_overflow;
|
||||
|
||||
// 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_stack_check annotation), and then we extract the main function
|
||||
// and invoke it.
|
||||
#[no_stack_check]
|
||||
pub fn start_thread(main: *mut libc::c_void) -> thread::rust_thread_return {
|
||||
pub fn start_thread(main: *mut libc::c_void) {
|
||||
unsafe {
|
||||
stack::record_os_managed_stack_bounds(0, usize::MAX);
|
||||
let handler = stack_overflow::Handler::new();
|
||||
let f: Box<Thunk> = Box::from_raw(main as *mut Thunk);
|
||||
f.invoke(());
|
||||
drop(handler);
|
||||
mem::transmute(0 as thread::rust_thread_return)
|
||||
let _handler = stack_overflow::Handler::new();
|
||||
Box::from_raw(main as *mut Thunk).invoke(());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,44 +12,30 @@
|
|||
|
||||
use core::prelude::*;
|
||||
|
||||
use io;
|
||||
use boxed;
|
||||
use boxed::Box;
|
||||
use cmp;
|
||||
use ffi::CString;
|
||||
use io;
|
||||
use libc::consts::os::posix01::PTHREAD_STACK_MIN;
|
||||
use libc;
|
||||
use mem;
|
||||
use ptr;
|
||||
use libc::consts::os::posix01::{PTHREAD_CREATE_JOINABLE, PTHREAD_STACK_MIN};
|
||||
use libc;
|
||||
use sys::os;
|
||||
use thunk::Thunk;
|
||||
use ffi::CString;
|
||||
use time::Duration;
|
||||
|
||||
use sys_common::stack::RED_ZONE;
|
||||
use sys_common::thread::*;
|
||||
|
||||
pub type rust_thread = libc::pthread_t;
|
||||
pub type rust_thread_return = *mut u8;
|
||||
pub type StartFn = extern "C" fn(*mut libc::c_void) -> rust_thread_return;
|
||||
|
||||
#[no_stack_check]
|
||||
pub extern fn thread_start(main: *mut libc::c_void) -> rust_thread_return {
|
||||
return start_thread(main);
|
||||
}
|
||||
|
||||
#[cfg(all(not(target_os = "linux"),
|
||||
not(target_os = "macos"),
|
||||
not(target_os = "bitrig"),
|
||||
not(target_os = "openbsd")))]
|
||||
pub mod guard {
|
||||
pub unsafe fn current() -> uint {
|
||||
0
|
||||
}
|
||||
|
||||
pub unsafe fn main() -> uint {
|
||||
0
|
||||
}
|
||||
|
||||
pub unsafe fn init() {
|
||||
}
|
||||
pub unsafe fn current() -> usize { 0 }
|
||||
pub unsafe fn main() -> usize { 0 }
|
||||
pub unsafe fn init() {}
|
||||
}
|
||||
|
||||
|
||||
|
@ -57,26 +43,22 @@ pub mod guard {
|
|||
target_os = "macos",
|
||||
target_os = "bitrig",
|
||||
target_os = "openbsd"))]
|
||||
#[allow(unused_imports)]
|
||||
pub mod guard {
|
||||
use super::*;
|
||||
#[cfg(any(target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "bitrig",
|
||||
target_os = "openbsd"))]
|
||||
use mem;
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
use ptr;
|
||||
use libc;
|
||||
use libc::funcs::posix88::mman::{mmap};
|
||||
use libc::{self, pthread_t};
|
||||
use libc::funcs::posix88::mman::mmap;
|
||||
use libc::consts::os::posix88::{PROT_NONE,
|
||||
MAP_PRIVATE,
|
||||
MAP_ANON,
|
||||
MAP_FAILED,
|
||||
MAP_FIXED};
|
||||
use mem;
|
||||
use ptr;
|
||||
use super::{pthread_self, pthread_attr_destroy};
|
||||
use sys::os;
|
||||
|
||||
// These are initialized in init() and only read from after
|
||||
static mut PAGE_SIZE: uint = 0;
|
||||
static mut GUARD_PAGE: uint = 0;
|
||||
static mut GUARD_PAGE: usize = 0;
|
||||
|
||||
#[cfg(any(target_os = "macos",
|
||||
target_os = "bitrig",
|
||||
|
@ -88,28 +70,16 @@ pub mod guard {
|
|||
#[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 {
|
||||
panic!("failed to get thread attributes");
|
||||
}
|
||||
assert_eq!(pthread_getattr_np(pthread_self(), &mut attr), 0);
|
||||
let mut stackaddr = ptr::null_mut();
|
||||
let mut stacksize = 0;
|
||||
if pthread_attr_getstack(&attr, &mut stackaddr, &mut stacksize) != 0 {
|
||||
panic!("failed to get stack information");
|
||||
}
|
||||
if pthread_attr_destroy(&mut attr) != 0 {
|
||||
panic!("failed to destroy thread attributes");
|
||||
}
|
||||
assert_eq!(pthread_attr_getstack(&attr, &mut stackaddr, &mut stacksize), 0);
|
||||
assert_eq!(pthread_attr_destroy(&mut attr), 0);
|
||||
stackaddr
|
||||
}
|
||||
|
||||
pub unsafe fn init() {
|
||||
let psize = libc::sysconf(libc::consts::os::sysconf::_SC_PAGESIZE);
|
||||
if psize == -1 {
|
||||
panic!("failed to get page size");
|
||||
}
|
||||
|
||||
PAGE_SIZE = psize as uint;
|
||||
|
||||
let psize = os::page_size();
|
||||
let mut stackaddr = get_stack_start();
|
||||
|
||||
// Ensure stackaddr is page aligned! A parent process might
|
||||
|
@ -118,9 +88,9 @@ pub mod guard {
|
|||
// stackaddr < stackaddr + stacksize, so if stackaddr is not
|
||||
// page-aligned, calculate the fix such that stackaddr <
|
||||
// new_page_aligned_stackaddr < stackaddr + stacksize
|
||||
let remainder = (stackaddr as usize) % (PAGE_SIZE as usize);
|
||||
let remainder = (stackaddr as usize) % psize;
|
||||
if remainder != 0 {
|
||||
stackaddr = ((stackaddr as usize) + (PAGE_SIZE as usize) - remainder)
|
||||
stackaddr = ((stackaddr as usize) + psize - remainder)
|
||||
as *mut libc::c_void;
|
||||
}
|
||||
|
||||
|
@ -128,7 +98,7 @@ pub mod guard {
|
|||
// This ensures SIGBUS will be raised on
|
||||
// stack overflow.
|
||||
let result = mmap(stackaddr,
|
||||
PAGE_SIZE as libc::size_t,
|
||||
psize as libc::size_t,
|
||||
PROT_NONE,
|
||||
MAP_PRIVATE | MAP_ANON | MAP_FIXED,
|
||||
-1,
|
||||
|
@ -138,124 +108,119 @@ pub mod guard {
|
|||
panic!("failed to allocate a guard page");
|
||||
}
|
||||
|
||||
let offset = if cfg!(target_os = "linux") {
|
||||
2
|
||||
} else {
|
||||
1
|
||||
};
|
||||
let offset = if cfg!(target_os = "linux") {2} else {1};
|
||||
|
||||
GUARD_PAGE = stackaddr as uint + offset * PAGE_SIZE;
|
||||
GUARD_PAGE = stackaddr as usize + offset * psize;
|
||||
}
|
||||
|
||||
pub unsafe fn main() -> uint {
|
||||
pub unsafe fn main() -> usize {
|
||||
GUARD_PAGE
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
pub unsafe fn current() -> uint {
|
||||
pub unsafe fn current() -> usize {
|
||||
extern {
|
||||
fn pthread_get_stackaddr_np(thread: pthread_t) -> *mut libc::c_void;
|
||||
fn pthread_get_stacksize_np(thread: pthread_t) -> libc::size_t;
|
||||
}
|
||||
(pthread_get_stackaddr_np(pthread_self()) as libc::size_t -
|
||||
pthread_get_stacksize_np(pthread_self())) as uint
|
||||
pthread_get_stacksize_np(pthread_self())) as usize
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "openbsd", target_os = "bitrig"))]
|
||||
pub unsafe fn current() -> usize {
|
||||
#[repr(C)]
|
||||
pub struct stack_t {
|
||||
ss_sp: *mut libc::c_void,
|
||||
ss_size: libc::size_t,
|
||||
ss_flags: libc::c_int,
|
||||
}
|
||||
extern {
|
||||
fn pthread_stackseg_np(thread: pthread_t,
|
||||
sinfo: *mut stack_t) -> libc::c_uint;
|
||||
}
|
||||
|
||||
#[cfg(target_os = "openbsd")]
|
||||
pub unsafe fn current() -> uint {
|
||||
let mut current_stack: stack_t = mem::zeroed();
|
||||
if pthread_stackseg_np(pthread_self(), &mut current_stack) != 0 {
|
||||
panic!("failed to get current stack: pthread_stackseg_np")
|
||||
}
|
||||
assert_eq!(pthread_stackseg_np(pthread_self(), &mut current_stack), 0);
|
||||
|
||||
let extra = if cfg!(target_os = "bitrig") {3} else {1} * os::page_size();
|
||||
if pthread_main_np() == 1 {
|
||||
// main thread
|
||||
current_stack.ss_sp as uint - current_stack.ss_size as uint + PAGE_SIZE as uint
|
||||
|
||||
current_stack.ss_sp as usize - current_stack.ss_size as usize + extra
|
||||
} else {
|
||||
// new thread
|
||||
current_stack.ss_sp as uint - current_stack.ss_size as uint
|
||||
current_stack.ss_sp as usize - current_stack.ss_size as usize
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
pub unsafe fn current() -> uint {
|
||||
pub unsafe fn current() -> usize {
|
||||
let mut attr: libc::pthread_attr_t = mem::zeroed();
|
||||
if pthread_getattr_np(pthread_self(), &mut attr) != 0 {
|
||||
panic!("failed to get thread attributes");
|
||||
}
|
||||
assert_eq!(pthread_getattr_np(pthread_self(), &mut attr), 0);
|
||||
let mut guardsize = 0;
|
||||
if pthread_attr_getguardsize(&attr, &mut guardsize) != 0 {
|
||||
panic!("failed to get stack guard page");
|
||||
}
|
||||
assert_eq!(pthread_attr_getguardsize(&attr, &mut guardsize), 0);
|
||||
if guardsize == 0 {
|
||||
panic!("there is no guard page");
|
||||
}
|
||||
let mut stackaddr = ptr::null_mut();
|
||||
let mut stacksize = 0;
|
||||
if pthread_attr_getstack(&attr, &mut stackaddr, &mut stacksize) != 0 {
|
||||
panic!("failed to get stack information");
|
||||
}
|
||||
if pthread_attr_destroy(&mut attr) != 0 {
|
||||
panic!("failed to destroy thread attributes");
|
||||
let mut size = 0;
|
||||
assert_eq!(pthread_attr_getstack(&attr, &mut stackaddr, &mut size), 0);
|
||||
assert_eq!(pthread_attr_destroy(&mut attr), 0);
|
||||
|
||||
stackaddr as usize + guardsize as usize
|
||||
}
|
||||
|
||||
stackaddr as uint + guardsize as uint
|
||||
}
|
||||
|
||||
#[cfg(target_os = "bitrig")]
|
||||
pub unsafe fn current() -> uint {
|
||||
let mut current_stack: stack_t = mem::zeroed();
|
||||
if pthread_stackseg_np(pthread_self(), &mut current_stack) != 0 {
|
||||
panic!("failed to get current stack: pthread_stackseg_np")
|
||||
}
|
||||
|
||||
if pthread_main_np() == 1 {
|
||||
// main thread
|
||||
current_stack.ss_sp as uint - current_stack.ss_size as uint + 3 * PAGE_SIZE as uint
|
||||
} else {
|
||||
// new thread
|
||||
current_stack.ss_sp as uint - current_stack.ss_size as uint
|
||||
}
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
extern {
|
||||
fn pthread_getattr_np(native: libc::pthread_t,
|
||||
attr: *mut libc::pthread_attr_t) -> libc::c_int;
|
||||
fn pthread_attr_getguardsize(attr: *const libc::pthread_attr_t,
|
||||
guardsize: *mut libc::size_t) -> libc::c_int;
|
||||
fn pthread_attr_getstack(attr: *const libc::pthread_attr_t,
|
||||
stackaddr: *mut *mut libc::c_void,
|
||||
stacksize: *mut libc::size_t) -> libc::c_int;
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn create(stack: uint, p: Thunk) -> io::Result<rust_thread> {
|
||||
pub unsafe fn create(stack: usize, p: Thunk) -> io::Result<rust_thread> {
|
||||
let p = box p;
|
||||
let mut native: libc::pthread_t = mem::zeroed();
|
||||
let mut attr: libc::pthread_attr_t = mem::zeroed();
|
||||
assert_eq!(pthread_attr_init(&mut attr), 0);
|
||||
assert_eq!(pthread_attr_setdetachstate(&mut attr,
|
||||
PTHREAD_CREATE_JOINABLE), 0);
|
||||
|
||||
// Reserve room for the red zone, the runtime's stack of last resort.
|
||||
let stack_size = cmp::max(stack, RED_ZONE + min_stack_size(&attr) as uint);
|
||||
let stack_size = cmp::max(stack, RED_ZONE + min_stack_size(&attr) as usize);
|
||||
match pthread_attr_setstacksize(&mut attr, stack_size as libc::size_t) {
|
||||
0 => {
|
||||
},
|
||||
libc::EINVAL => {
|
||||
0 => {}
|
||||
n => {
|
||||
assert_eq!(n, 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.
|
||||
// Round up to the nearest page and try again.
|
||||
let page_size = libc::sysconf(libc::_SC_PAGESIZE) as uint;
|
||||
let page_size = os::page_size();
|
||||
let stack_size = (stack_size + page_size - 1) &
|
||||
(-(page_size as int - 1) as uint - 1);
|
||||
assert_eq!(pthread_attr_setstacksize(&mut attr, stack_size as libc::size_t), 0);
|
||||
},
|
||||
errno => {
|
||||
// This cannot really happen.
|
||||
panic!("pthread_attr_setstacksize() error: {}", errno);
|
||||
},
|
||||
(-(page_size as isize - 1) as usize - 1);
|
||||
assert_eq!(pthread_attr_setstacksize(&mut attr,
|
||||
stack_size as libc::size_t), 0);
|
||||
}
|
||||
};
|
||||
|
||||
// must box since sizeof(p)=2*uint
|
||||
let raw_p = boxed::into_raw(box p);
|
||||
let arg = raw_p as *mut libc::c_void;
|
||||
let ret = pthread_create(&mut native, &attr, thread_start, arg);
|
||||
let ret = pthread_create(&mut native, &attr, thread_start,
|
||||
&*p as *const _ as *mut _);
|
||||
assert_eq!(pthread_attr_destroy(&mut attr), 0);
|
||||
|
||||
if ret != 0 {
|
||||
// be sure to not leak the closure
|
||||
let _p: Box<Thunk> = Box::from_raw(raw_p);
|
||||
return if ret != 0 {
|
||||
Err(io::Error::from_os_error(ret))
|
||||
} else {
|
||||
mem::forget(p); // ownership passed to pthread_create
|
||||
Ok(native)
|
||||
};
|
||||
|
||||
#[no_stack_check]
|
||||
extern fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void {
|
||||
start_thread(main);
|
||||
0 as *mut _
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -263,14 +228,14 @@ pub unsafe fn create(stack: uint, p: Thunk) -> io::Result<rust_thread> {
|
|||
pub unsafe fn set_name(name: &str) {
|
||||
// pthread_setname_np() since glibc 2.12
|
||||
// availability autodetected via weak linkage
|
||||
let cname = CString::new(name).unwrap();
|
||||
type F = unsafe extern "C" fn(libc::pthread_t, *const libc::c_char)
|
||||
type F = unsafe extern fn(libc::pthread_t, *const libc::c_char)
|
||||
-> libc::c_int;
|
||||
extern {
|
||||
#[linkage = "extern_weak"]
|
||||
static pthread_setname_np: *const ();
|
||||
}
|
||||
if !pthread_setname_np.is_null() {
|
||||
let cname = CString::new(name).unwrap();
|
||||
mem::transmute::<*const (), F>(pthread_setname_np)(pthread_self(),
|
||||
cname.as_ptr());
|
||||
}
|
||||
|
@ -281,14 +246,18 @@ pub unsafe fn set_name(name: &str) {
|
|||
target_os = "bitrig",
|
||||
target_os = "openbsd"))]
|
||||
pub unsafe fn set_name(name: &str) {
|
||||
// pthread_set_name_np() since almost forever on all BSDs
|
||||
extern {
|
||||
fn pthread_set_name_np(tid: libc::pthread_t, name: *const libc::c_char);
|
||||
}
|
||||
let cname = CString::new(name).unwrap();
|
||||
pthread_set_name_np(pthread_self(), cname.as_ptr());
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
pub unsafe fn set_name(name: &str) {
|
||||
// pthread_setname_np() since OS X 10.6 and iOS 3.2
|
||||
extern {
|
||||
fn pthread_setname_np(name: *const libc::c_char) -> libc::c_int;
|
||||
}
|
||||
let cname = CString::new(name).unwrap();
|
||||
pthread_setname_np(cname.as_ptr());
|
||||
}
|
||||
|
@ -301,7 +270,42 @@ pub unsafe fn detach(native: rust_thread) {
|
|||
assert_eq!(pthread_detach(native), 0);
|
||||
}
|
||||
|
||||
pub unsafe fn yield_now() { assert_eq!(sched_yield(), 0); }
|
||||
pub unsafe fn yield_now() {
|
||||
assert_eq!(sched_yield(), 0);
|
||||
}
|
||||
|
||||
pub fn sleep(dur: Duration) {
|
||||
unsafe {
|
||||
if dur < Duration::zero() {
|
||||
return yield_now()
|
||||
}
|
||||
let seconds = dur.num_seconds();
|
||||
let ns = dur - Duration::seconds(seconds);
|
||||
let mut ts = libc::timespec {
|
||||
tv_sec: seconds as libc::time_t,
|
||||
tv_nsec: ns.num_nanoseconds().unwrap() as libc::c_long,
|
||||
};
|
||||
// If we're awoken with a signal then the return value will be -1 and
|
||||
// nanosleep will fill in `ts` with the remaining time.
|
||||
while dosleep(&mut ts) == -1 {
|
||||
assert_eq!(os::errno(), libc::EINTR);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
unsafe fn dosleep(ts: *mut libc::timespec) -> libc::c_int {
|
||||
extern {
|
||||
fn clock_nanosleep(clock_id: libc::c_int, flags: libc::c_int,
|
||||
request: *const libc::timespec,
|
||||
remain: *mut libc::timespec) -> libc::c_int;
|
||||
}
|
||||
clock_nanosleep(libc::CLOCK_MONOTONIC, 0, ts, ts)
|
||||
}
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
unsafe fn dosleep(ts: *mut libc::timespec) -> libc::c_int {
|
||||
libc::nanosleep(ts, ts)
|
||||
}
|
||||
}
|
||||
|
||||
// glibc >= 2.15 has a __pthread_get_minstack() function that returns
|
||||
// PTHREAD_STACK_MIN plus however many bytes are needed for thread-local
|
||||
|
@ -334,67 +338,19 @@ fn min_stack_size(_: *const libc::pthread_attr_t) -> libc::size_t {
|
|||
PTHREAD_STACK_MIN
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
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(any(target_os = "bitrig", target_os = "openbsd"))]
|
||||
fn pthread_main_np() -> libc::c_uint;
|
||||
|
||||
#[cfg(any(target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "openbsd"))]
|
||||
extern {
|
||||
pub fn pthread_self() -> libc::pthread_t;
|
||||
fn pthread_set_name_np(tid: libc::pthread_t, name: *const libc::c_char);
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
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;
|
||||
fn pthread_setname_np(name: *const libc::c_char) -> libc::c_int;
|
||||
}
|
||||
|
||||
#[cfg(target_os = "bitrig")]
|
||||
extern {
|
||||
pub fn pthread_self() -> libc::pthread_t;
|
||||
pub fn pthread_stackseg_np(thread: libc::pthread_t,
|
||||
sinfo: *mut stack_t) -> libc::c_uint;
|
||||
pub fn pthread_main_np() -> libc::c_uint;
|
||||
fn pthread_set_name_np(tid: libc::pthread_t, name: *const libc::c_char);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "openbsd")]
|
||||
extern {
|
||||
pub fn pthread_stackseg_np(thread: libc::pthread_t,
|
||||
sinfo: *mut stack_t) -> libc::c_uint;
|
||||
pub fn pthread_main_np() -> libc::c_uint;
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "bitrig", target_os = "openbsd"))]
|
||||
#[repr(C)]
|
||||
pub struct stack_t {
|
||||
pub ss_sp: *mut libc::c_void,
|
||||
pub ss_size: libc::size_t,
|
||||
pub ss_flags: libc::c_int,
|
||||
}
|
||||
|
||||
extern {
|
||||
fn pthread_self() -> libc::pthread_t;
|
||||
fn pthread_create(native: *mut libc::pthread_t,
|
||||
attr: *const libc::pthread_attr_t,
|
||||
f: StartFn,
|
||||
f: extern fn(*mut libc::c_void) -> *mut libc::c_void,
|
||||
value: *mut libc::c_void) -> libc::c_int;
|
||||
fn pthread_join(native: libc::pthread_t,
|
||||
value: *mut *mut libc::c_void) -> libc::c_int;
|
||||
fn pthread_attr_init(attr: *mut libc::pthread_attr_t) -> libc::c_int;
|
||||
pub fn pthread_attr_destroy(attr: *mut libc::pthread_attr_t) -> libc::c_int;
|
||||
fn pthread_attr_destroy(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,
|
||||
|
|
|
@ -10,43 +10,28 @@
|
|||
|
||||
use prelude::v1::*;
|
||||
|
||||
use boxed;
|
||||
use cmp;
|
||||
use io;
|
||||
use ptr;
|
||||
use libc;
|
||||
use libc::{self, c_void};
|
||||
use libc::types::os::arch::extra::{LPSECURITY_ATTRIBUTES, SIZE_T, BOOL,
|
||||
LPVOID, DWORD, LPDWORD, HANDLE};
|
||||
use thunk::Thunk;
|
||||
use mem;
|
||||
use ptr;
|
||||
use sys_common::stack::RED_ZONE;
|
||||
use sys_common::thread::*;
|
||||
use thunk::Thunk;
|
||||
use time::Duration;
|
||||
|
||||
pub type rust_thread = HANDLE;
|
||||
pub type rust_thread_return = DWORD;
|
||||
|
||||
pub type StartFn = extern "system" fn(*mut libc::c_void) -> rust_thread_return;
|
||||
|
||||
#[no_stack_check]
|
||||
pub extern "system" fn thread_start(main: *mut libc::c_void) -> rust_thread_return {
|
||||
return start_thread(main);
|
||||
}
|
||||
|
||||
pub mod guard {
|
||||
pub unsafe fn main() -> uint {
|
||||
0
|
||||
}
|
||||
|
||||
pub unsafe fn current() -> uint {
|
||||
0
|
||||
}
|
||||
|
||||
pub unsafe fn init() {
|
||||
}
|
||||
pub unsafe fn main() -> uint { 0 }
|
||||
pub unsafe fn current() -> uint { 0 }
|
||||
pub unsafe fn init() {}
|
||||
}
|
||||
|
||||
pub unsafe fn create(stack: uint, p: Thunk) -> io::Result<rust_thread> {
|
||||
let raw_p = boxed::into_raw(box p);
|
||||
let arg = raw_p as *mut libc::c_void;
|
||||
pub unsafe fn create(stack: usize, p: Thunk) -> io::Result<rust_thread> {
|
||||
let p = box p;
|
||||
// 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
|
||||
|
@ -58,14 +43,20 @@ pub unsafe fn create(stack: uint, p: Thunk) -> io::Result<rust_thread> {
|
|||
// 20 kB red zone, that makes for a 64 kB minimum stack.
|
||||
let stack_size = (cmp::max(stack, RED_ZONE) + 0xfffe) & (-0xfffe - 1);
|
||||
let ret = CreateThread(ptr::null_mut(), stack_size as libc::size_t,
|
||||
thread_start, arg, 0, ptr::null_mut());
|
||||
thread_start, &*p as *const _ as *mut _,
|
||||
0, ptr::null_mut());
|
||||
|
||||
if ret as uint == 0 {
|
||||
// be sure to not leak the closure
|
||||
let _p: Box<Thunk> = Box::from_raw(raw_p);
|
||||
return if ret as usize == 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
mem::forget(p); // ownership passed to CreateThread
|
||||
Ok(ret)
|
||||
};
|
||||
|
||||
#[no_stack_check]
|
||||
extern "system" fn thread_start(main: *mut libc::c_void) -> DWORD {
|
||||
start_thread(main);
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,14 +83,29 @@ pub unsafe fn yield_now() {
|
|||
SwitchToThread();
|
||||
}
|
||||
|
||||
pub fn sleep(dur: Duration) {
|
||||
unsafe {
|
||||
if dur < Duration::zero() {
|
||||
return yield_now()
|
||||
}
|
||||
let ms = dur.num_milliseconds();
|
||||
// if we have a fractional number of milliseconds then add an extra
|
||||
// millisecond to sleep for
|
||||
let extra = dur - Duration::milliseconds(ms);
|
||||
let ms = ms + if extra.is_zero() {0} else {1};
|
||||
Sleep(ms as DWORD);
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
extern "system" {
|
||||
fn CreateThread(lpThreadAttributes: LPSECURITY_ATTRIBUTES,
|
||||
dwStackSize: SIZE_T,
|
||||
lpStartAddress: StartFn,
|
||||
lpStartAddress: extern "system" fn(*mut c_void) -> DWORD,
|
||||
lpParameter: LPVOID,
|
||||
dwCreationFlags: DWORD,
|
||||
lpThreadId: LPDWORD) -> HANDLE;
|
||||
fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD;
|
||||
fn SwitchToThread() -> BOOL;
|
||||
fn Sleep(dwMilliseconds: DWORD);
|
||||
}
|
||||
|
|
|
@ -379,6 +379,19 @@ pub fn panicking() -> bool {
|
|||
unwind::panicking()
|
||||
}
|
||||
|
||||
/// Put the current thread to sleep for the specified amount of time.
|
||||
///
|
||||
/// The thread may sleep longer than the duration specified due to scheduling
|
||||
/// specifics or platform-dependent functionality. Note that on unix platforms
|
||||
/// this function will not return early due to a signal being received or a
|
||||
/// spurious wakeup.
|
||||
#[unstable(feature = "thread_sleep",
|
||||
reason = "recently added, needs an RFC, and `Duration` itself is \
|
||||
unstable")]
|
||||
pub fn sleep(dur: Duration) {
|
||||
imp::sleep(dur)
|
||||
}
|
||||
|
||||
/// Block unless or until the current thread's token is made available (may wake spuriously).
|
||||
///
|
||||
/// See the module doc for more detail.
|
||||
|
@ -935,6 +948,12 @@ mod test {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sleep_smoke() {
|
||||
thread::sleep(Duration::milliseconds(2));
|
||||
thread::sleep(Duration::milliseconds(-2));
|
||||
}
|
||||
|
||||
// NOTE: the corresponding test for stderr is in run-pass/task-stderr, due
|
||||
// to the test harness apparently interfering with stderr configuration.
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue