1 // Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! Native os-thread management
13 //! This modules contains bindings necessary for managing OS-level threads.
14 //! These functions operate outside of the rust runtime, creating threads
15 //! which are not used for scheduling in any way.
17 #![allow(non_camel_case_types)]
21 use alloc::boxed::Box;
29 pub unsafe fn init() {
31 stack_overflow::init();
34 pub unsafe fn cleanup() {
35 stack_overflow::cleanup();
38 #[cfg(target_os = "windows")]
39 type StartFn = extern "system" fn(*mut libc::c_void) -> imp::rust_thread_return;
41 #[cfg(not(target_os = "windows"))]
42 type StartFn = extern "C" fn(*mut libc::c_void) -> imp::rust_thread_return;
44 /// This struct represents a native thread's state. This is used to join on an
45 /// existing thread created in the join-able state.
46 pub struct Thread<T> {
47 native: imp::rust_thread,
49 packet: Box<Option<T>>,
52 static DEFAULT_STACK_SIZE: uint = 1024 * 1024;
54 // This is the starting point of rust os threads. The first thing we do
55 // is make sure that we don't trigger __morestack (also why this has a
56 // no_stack_check annotation), and then we extract the main function
59 fn start_thread(main: *mut libc::c_void) -> imp::rust_thread_return {
61 stack::record_os_managed_stack_bounds(0, uint::MAX);
62 let handler = stack_overflow::Handler::new();
63 let f: Box<proc()> = mem::transmute(main);
66 mem::transmute(0 as imp::rust_thread_return)
71 #[cfg(target_os = "windows")]
72 extern "system" fn thread_start(main: *mut libc::c_void) -> imp::rust_thread_return {
73 return start_thread(main);
77 #[cfg(not(target_os = "windows"))]
78 extern fn thread_start(main: *mut libc::c_void) -> imp::rust_thread_return {
79 return start_thread(main);
82 /// Returns the last writable byte of the main thread's stack next to the guard
83 /// page. Must be called from the main thread.
84 pub fn main_guard_page() -> uint {
90 /// Returns the last writable byte of the current thread's stack next to the
91 /// guard page. Must not be called from the main thread.
92 pub fn current_guard_page() -> uint {
98 // There are two impl blocks b/c if T were specified at the top then it's just a
99 // pain to specify a type parameter on Thread::spawn (which doesn't need the
103 /// Starts execution of a new OS thread.
105 /// This function will not wait for the thread to join, but a handle to the
106 /// thread will be returned.
108 /// Note that the handle returned is used to acquire the return value of the
109 /// procedure `main`. The `join` function will wait for the thread to finish
110 /// and return the value that `main` generated.
112 /// Also note that the `Thread` returned will *always* wait for the thread
113 /// to finish executing. This means that even if `join` is not explicitly
114 /// called, when the `Thread` falls out of scope its destructor will block
115 /// waiting for the OS thread.
116 pub fn start<T: Send>(main: proc():Send -> T) -> Thread<T> {
117 Thread::start_stack(DEFAULT_STACK_SIZE, main)
120 /// Performs the same functionality as `start`, but specifies an explicit
121 /// stack size for the new thread.
122 pub fn start_stack<T: Send>(stack: uint, main: proc():Send -> T) -> Thread<T> {
124 // We need the address of the packet to fill in to be stable so when
125 // `main` fills it in it's still valid, so allocate an extra box to do
127 let packet = box None;
128 let packet2: *mut Option<T> = unsafe {
129 *mem::transmute::<&Box<Option<T>>, *const *mut Option<T>>(&packet)
131 let main = proc() unsafe { *packet2 = Some(main()); };
132 let native = unsafe { imp::create(stack, box main) };
141 /// This will spawn a new thread, but it will not wait for the thread to
142 /// finish, nor is it possible to wait for the thread to finish.
144 /// This corresponds to creating threads in the 'detached' state on unix
145 /// systems. Note that platforms may not keep the main program alive even if
146 /// there are detached thread still running around.
147 pub fn spawn(main: proc():Send) {
148 Thread::spawn_stack(DEFAULT_STACK_SIZE, main)
151 /// Performs the same functionality as `spawn`, but explicitly specifies a
152 /// stack size for the new thread.
153 pub fn spawn_stack(stack: uint, main: proc():Send) {
155 let handle = imp::create(stack, box main);
160 /// Relinquishes the CPU slot that this OS-thread is currently using,
161 /// allowing another thread to run for awhile.
163 unsafe { imp::yield_now(); }
167 impl<T: Send> Thread<T> {
168 /// Wait for this thread to finish, returning the result of the thread's
170 pub fn join(mut self) -> T {
171 assert!(!self.joined);
172 unsafe { imp::join(self.native) };
174 assert!(self.packet.is_some());
175 self.packet.take().unwrap()
180 impl<T: Send> Drop for Thread<T> {
182 // This is required for correctness. If this is not done then the thread
183 // would fill in a return box which no longer exists.
185 unsafe { imp::join(self.native) };
191 #[allow(non_snake_case)]
193 use core::prelude::*;
195 use alloc::boxed::Box;
200 use libc::types::os::arch::extra::{LPSECURITY_ATTRIBUTES, SIZE_T, BOOL,
201 LPVOID, DWORD, LPDWORD, HANDLE};
204 pub type rust_thread = HANDLE;
205 pub type rust_thread_return = DWORD;
208 pub unsafe fn main() -> uint {
212 pub unsafe fn current() -> uint {
216 pub unsafe fn init() {
220 pub unsafe fn create(stack: uint, p: Box<proc():Send>) -> rust_thread {
221 let arg: *mut libc::c_void = mem::transmute(p);
222 // FIXME On UNIX, we guard against stack sizes that are too small but
223 // that's because pthreads enforces that stacks are at least
224 // PTHREAD_STACK_MIN bytes big. Windows has no such lower limit, it's
225 // just that below a certain threshold you can't do anything useful.
226 // That threshold is application and architecture-specific, however.
227 // For now, the only requirement is that it's big enough to hold the
228 // red zone. Round up to the next 64 kB because that's what the NT
229 // kernel does, might as well make it explicit. With the current
230 // 20 kB red zone, that makes for a 64 kB minimum stack.
231 let stack_size = (cmp::max(stack, RED_ZONE) + 0xfffe) & (-0xfffe - 1);
232 let ret = CreateThread(ptr::null_mut(), stack_size as libc::size_t,
233 super::thread_start, arg, 0, ptr::null_mut());
235 if ret as uint == 0 {
236 // be sure to not leak the closure
237 let _p: Box<proc():Send> = mem::transmute(arg);
238 fail!("failed to spawn native thread: {}", ret);
243 pub unsafe fn join(native: rust_thread) {
244 use libc::consts::os::extra::INFINITE;
245 WaitForSingleObject(native, INFINITE);
248 pub unsafe fn detach(native: rust_thread) {
249 assert!(libc::CloseHandle(native) != 0);
252 pub unsafe fn yield_now() {
253 // This function will return 0 if there are no other threads to execute,
254 // but this also means that the yield was useless so this isn't really a
255 // case that needs to be worried about.
259 #[allow(non_snake_case)]
261 fn CreateThread(lpThreadAttributes: LPSECURITY_ATTRIBUTES,
263 lpStartAddress: super::StartFn,
265 dwCreationFlags: DWORD,
266 lpThreadId: LPDWORD) -> HANDLE;
267 fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD;
268 fn SwitchToThread() -> BOOL;
274 use core::prelude::*;
276 use alloc::boxed::Box;
280 use libc::consts::os::posix01::{PTHREAD_CREATE_JOINABLE, PTHREAD_STACK_MIN};
285 pub type rust_thread = libc::pthread_t;
286 pub type rust_thread_return = *mut u8;
288 #[cfg(all(not(target_os = "linux"), not(target_os = "macos")))]
290 pub unsafe fn current() -> uint {
294 pub unsafe fn main() -> uint {
298 pub unsafe fn init() {
302 #[cfg(any(target_os = "linux", target_os = "macos"))]
305 #[cfg(any(target_os = "linux", target_os = "android"))]
307 #[cfg(any(target_os = "linux", target_os = "android"))]
310 use libc::funcs::posix88::mman::{mmap};
311 use libc::consts::os::posix88::{PROT_NONE,
317 // These are initialized in init() and only read from after
318 static mut PAGE_SIZE: uint = 0;
319 static mut GUARD_PAGE: uint = 0;
321 #[cfg(target_os = "macos")]
322 unsafe fn get_stack_start() -> *mut libc::c_void {
323 current() as *mut libc::c_void
326 #[cfg(any(target_os = "linux", target_os = "android"))]
327 unsafe fn get_stack_start() -> *mut libc::c_void {
328 let mut attr: libc::pthread_attr_t = mem::zeroed();
329 if pthread_getattr_np(pthread_self(), &mut attr) != 0 {
330 fail!("failed to get thread attributes");
332 let mut stackaddr = ptr::null_mut();
333 let mut stacksize = 0;
334 if pthread_attr_getstack(&attr, &mut stackaddr, &mut stacksize) != 0 {
335 fail!("failed to get stack information");
337 if pthread_attr_destroy(&mut attr) != 0 {
338 fail!("failed to destroy thread attributes");
343 pub unsafe fn init() {
344 let psize = libc::sysconf(libc::consts::os::sysconf::_SC_PAGESIZE);
346 fail!("failed to get page size");
349 PAGE_SIZE = psize as uint;
351 let stackaddr = get_stack_start();
353 // Rellocate the last page of the stack.
354 // This ensures SIGBUS will be raised on
356 let result = mmap(stackaddr,
357 PAGE_SIZE as libc::size_t,
359 MAP_PRIVATE | MAP_ANON | MAP_FIXED,
363 if result != stackaddr || result == MAP_FAILED {
364 fail!("failed to allocate a guard page");
367 let offset = if cfg!(target_os = "linux") {
373 GUARD_PAGE = stackaddr as uint + offset * PAGE_SIZE;
376 pub unsafe fn main() -> uint {
380 #[cfg(target_os = "macos")]
381 pub unsafe fn current() -> uint {
382 (pthread_get_stackaddr_np(pthread_self()) as libc::size_t -
383 pthread_get_stacksize_np(pthread_self())) as uint
386 #[cfg(any(target_os = "linux", target_os = "android"))]
387 pub unsafe fn current() -> uint {
388 let mut attr: libc::pthread_attr_t = mem::zeroed();
389 if pthread_getattr_np(pthread_self(), &mut attr) != 0 {
390 fail!("failed to get thread attributes");
392 let mut guardsize = 0;
393 if pthread_attr_getguardsize(&attr, &mut guardsize) != 0 {
394 fail!("failed to get stack guard page");
397 fail!("there is no guard page");
399 let mut stackaddr = ptr::null_mut();
400 let mut stacksize = 0;
401 if pthread_attr_getstack(&attr, &mut stackaddr, &mut stacksize) != 0 {
402 fail!("failed to get stack information");
404 if pthread_attr_destroy(&mut attr) != 0 {
405 fail!("failed to destroy thread attributes");
408 stackaddr as uint + guardsize as uint
412 pub unsafe fn create(stack: uint, p: Box<proc():Send>) -> rust_thread {
413 let mut native: libc::pthread_t = mem::zeroed();
414 let mut attr: libc::pthread_attr_t = mem::zeroed();
415 assert_eq!(pthread_attr_init(&mut attr), 0);
416 assert_eq!(pthread_attr_setdetachstate(&mut attr,
417 PTHREAD_CREATE_JOINABLE), 0);
419 // Reserve room for the red zone, the runtime's stack of last resort.
420 let stack_size = cmp::max(stack, RED_ZONE + min_stack_size(&attr) as uint);
421 match pthread_attr_setstacksize(&mut attr, stack_size as libc::size_t) {
425 // EINVAL means |stack_size| is either too small or not a
426 // multiple of the system page size. Because it's definitely
427 // >= PTHREAD_STACK_MIN, it must be an alignment issue.
428 // Round up to the nearest page and try again.
429 let page_size = libc::sysconf(libc::_SC_PAGESIZE) as uint;
430 let stack_size = (stack_size + page_size - 1) &
431 (-(page_size as int - 1) as uint - 1);
432 assert_eq!(pthread_attr_setstacksize(&mut attr, stack_size as libc::size_t), 0);
435 // This cannot really happen.
436 fail!("pthread_attr_setstacksize() error: {}", errno);
440 let arg: *mut libc::c_void = mem::transmute(p);
441 let ret = pthread_create(&mut native, &attr, super::thread_start, arg);
442 assert_eq!(pthread_attr_destroy(&mut attr), 0);
445 // be sure to not leak the closure
446 let _p: Box<proc():Send> = mem::transmute(arg);
447 fail!("failed to spawn native thread: {}", ret);
452 pub unsafe fn join(native: rust_thread) {
453 assert_eq!(pthread_join(native, ptr::null_mut()), 0);
456 pub unsafe fn detach(native: rust_thread) {
457 assert_eq!(pthread_detach(native), 0);
460 pub unsafe fn yield_now() { assert_eq!(sched_yield(), 0); }
461 // glibc >= 2.15 has a __pthread_get_minstack() function that returns
462 // PTHREAD_STACK_MIN plus however many bytes are needed for thread-local
463 // storage. We need that information to avoid blowing up when a small stack
464 // is created in an application with big thread-local storage requirements.
465 // See #6233 for rationale and details.
467 // Link weakly to the symbol for compatibility with older versions of glibc.
468 // Assumes that we've been dynamically linked to libpthread but that is
469 // currently always the case. Note that you need to check that the symbol
470 // is non-null before calling it!
471 #[cfg(target_os = "linux")]
472 fn min_stack_size(attr: *const libc::pthread_attr_t) -> libc::size_t {
473 type F = unsafe extern "C" fn(*const libc::pthread_attr_t) -> libc::size_t;
475 #[linkage = "extern_weak"]
476 static __pthread_get_minstack: *const ();
478 if __pthread_get_minstack.is_null() {
481 unsafe { mem::transmute::<*const (), F>(__pthread_get_minstack)(attr) }
485 // __pthread_get_minstack() is marked as weak but extern_weak linkage is
486 // not supported on OS X, hence this kludge...
487 #[cfg(not(target_os = "linux"))]
488 fn min_stack_size(_: *const libc::pthread_attr_t) -> libc::size_t {
492 #[cfg(any(target_os = "linux"))]
494 pub fn pthread_self() -> libc::pthread_t;
495 pub fn pthread_getattr_np(native: libc::pthread_t,
496 attr: *mut libc::pthread_attr_t) -> libc::c_int;
497 pub fn pthread_attr_getguardsize(attr: *const libc::pthread_attr_t,
498 guardsize: *mut libc::size_t) -> libc::c_int;
499 pub fn pthread_attr_getstack(attr: *const libc::pthread_attr_t,
500 stackaddr: *mut *mut libc::c_void,
501 stacksize: *mut libc::size_t) -> libc::c_int;
504 #[cfg(target_os = "macos")]
506 pub fn pthread_self() -> libc::pthread_t;
507 pub fn pthread_get_stackaddr_np(thread: libc::pthread_t) -> *mut libc::c_void;
508 pub fn pthread_get_stacksize_np(thread: libc::pthread_t) -> libc::size_t;
512 fn pthread_create(native: *mut libc::pthread_t,
513 attr: *const libc::pthread_attr_t,
515 value: *mut libc::c_void) -> libc::c_int;
516 fn pthread_join(native: libc::pthread_t,
517 value: *mut *mut libc::c_void) -> libc::c_int;
518 fn pthread_attr_init(attr: *mut libc::pthread_attr_t) -> libc::c_int;
519 pub fn pthread_attr_destroy(attr: *mut libc::pthread_attr_t) -> libc::c_int;
520 fn pthread_attr_setstacksize(attr: *mut libc::pthread_attr_t,
521 stack_size: libc::size_t) -> libc::c_int;
522 fn pthread_attr_setdetachstate(attr: *mut libc::pthread_attr_t,
523 state: libc::c_int) -> libc::c_int;
524 fn pthread_detach(thread: libc::pthread_t) -> libc::c_int;
525 fn sched_yield() -> libc::c_int;
534 fn smoke() { Thread::start(proc (){}).join(); }
537 fn data() { assert_eq!(Thread::start(proc () { 1i }).join(), 1); }
540 fn detached() { Thread::spawn(proc () {}) }
544 assert_eq!(42i, Thread::start_stack(0, proc () 42i).join());
545 assert_eq!(42i, Thread::start_stack(1, proc () 42i).join());