Skip to content

Commit

Permalink
Only box the function once when creating threads.
Browse files Browse the repository at this point in the history
  • Loading branch information
rphmeier committed Feb 15, 2016
1 parent 0c4d81f commit 9fd687b
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 49 deletions.
1 change: 0 additions & 1 deletion src/libstd/sys/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ pub mod net;
pub mod poison;
pub mod remutex;
pub mod rwlock;
pub mod thread;
pub mod thread_info;
pub mod thread_local;
pub mod unwind;
Expand Down
24 changes: 0 additions & 24 deletions src/libstd/sys/common/thread.rs

This file was deleted.

47 changes: 34 additions & 13 deletions src/libstd/sys/unix/thread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@

use prelude::v1::*;

use alloc::boxed::FnBox;
use cmp;
#[cfg(not(any(target_env = "newlib", target_os = "solaris")))]
use ffi::CString;
Expand All @@ -19,10 +18,9 @@ use libc;
use mem;
use ptr;
use sys::os;
use sys::stack_overflow;
use time::Duration;

use sys_common::thread::*;

pub struct Thread {
id: libc::pthread_t,
}
Expand All @@ -33,9 +31,38 @@ unsafe impl Send for Thread {}
unsafe impl Sync for Thread {}

impl Thread {
pub unsafe fn new<'a>(stack: usize, p: Box<FnBox() + 'a>)
pub unsafe fn new<F: FnOnce()>(stack: usize, p: F)
-> io::Result<Thread> {

extern fn thread_start<F: FnOnce()>(main: *mut libc::c_void)
-> *mut libc::c_void {
unsafe {
let main = Box::from_raw(main as *mut F);
// Next, set up our stack overflow handler which may get triggered if we run
// out of stack.
let _handler = stack_overflow::Handler::new();

// Finally, let's run some code.
main();
}
ptr::null_mut()
}

let p = box p;

match Thread::new_inner(stack, &*p as *const _ as *const _, thread_start::<F>) {
Ok(thread) => {
mem::forget(p); // ownership passed to pthread_create
Ok(thread)
}

Err(e) => Err(e),
}
}

unsafe fn new_inner(stack: usize, p: *const libc::c_void,
f: extern fn(*mut libc::c_void) -> *mut libc::c_void)
-> io::Result<Thread> {
let mut native: libc::pthread_t = mem::zeroed();
let mut attr: libc::pthread_attr_t = mem::zeroed();
assert_eq!(libc::pthread_attr_init(&mut attr), 0);
Expand All @@ -59,20 +86,14 @@ impl Thread {
}
};

let ret = libc::pthread_create(&mut native, &attr, thread_start,
&*p as *const _ as *mut _);
let ret = libc::pthread_create(&mut native, &attr, f,
p as *mut _);
assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);

return if ret != 0 {
if ret != 0 {
Err(io::Error::from_raw_os_error(ret))
} else {
mem::forget(p); // ownership passed to pthread_create
Ok(Thread { id: native })
};

extern fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void {
unsafe { start_thread(main); }
ptr::null_mut()
}
}

Expand Down
41 changes: 31 additions & 10 deletions src/libstd/sys/windows/thread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,45 @@ use libc::c_void;
use ptr;
use sys::c;
use sys::handle::Handle;
use sys_common::thread::*;
use sys::stack_overflow;
use time::Duration;

pub struct Thread {
handle: Handle
}

impl Thread {
pub unsafe fn new<'a>(stack: usize, p: Box<FnBox() + 'a>)
pub unsafe fn new<F: FnOnce()>(stack: usize, p: F)
-> io::Result<Thread> {
extern "system" fn thread_start<F: FnOnce()>(main: *mut c_void)
-> c::DWORD {
unsafe {
let main = Box::from_raw(main as *mut F);

// Next, set up our stack overflow handler which may get triggered if we run
// out of stack.
let _handler = stack_overflow::Handler::new();

// Finally, let's run some code.
main();
}
0
}

let p = box p;

match Thread::new_inner(stack, &*p as *const _ as *const _, thread_start::<F>) {
Ok(thread) => {
mem::forget(p); // ownership passed to CreateThread
Ok(thread)
}
Err(e) => Err(e),
}
}

unsafe fn new_inner(stack: usize, p: *const c_void,
f: extern "system" fn(*mut c_void) -> *mut c::DWORD)
-> io::Result<Thread> {
// 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
Expand All @@ -37,21 +64,15 @@ impl Thread {
// Round up to the next 64 kB because that's what the NT kernel does,
// might as well make it explicit.
let stack_size = (stack + 0xfffe) & (!0xfffe);
let ret = c::CreateThread(ptr::null_mut(), stack_size,
thread_start, &*p as *const _ as *mut _,
let ret = c::CreateThread(ptr::null_mut(), stack,
f, p as *mut _,
0, ptr::null_mut());

return if ret as usize == 0 {
Err(io::Error::last_os_error())
} else {
mem::forget(p); // ownership passed to CreateThread
Ok(Thread { handle: Handle::new(ret) })
};

extern "system" fn thread_start(main: *mut c_void) -> c::DWORD {
unsafe { start_thread(main); }
0
}
}

pub fn set_name(_name: &str) {
Expand Down
2 changes: 1 addition & 1 deletion src/libstd/thread/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ impl Builder {

Ok(JoinHandle(JoinInner {
native: unsafe {
Some(try!(imp::Thread::new(stack_size, Box::new(main))))
Some(try!(imp::Thread::new(stack_size, main)))
},
thread: my_thread,
packet: Packet(my_packet),
Expand Down

0 comments on commit 9fd687b

Please sign in to comment.