1 // Copyright 2013 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)];
23 use option::{Option, Some, None};
26 type StartFn = extern "C" fn(*libc::c_void) -> imp::rust_thread_return;
28 /// This struct represents a native thread's state. This is used to join on an
29 /// existing thread created in the join-able state.
30 pub struct Thread<T> {
31 priv native: imp::rust_thread,
33 priv packet: ~Option<T>,
36 static DEFAULT_STACK_SIZE: uint = 1024 * 1024;
38 // This is the starting point of rust os threads. The first thing we do
39 // is make sure that we don't trigger __morestack (also why this has a
40 // no_split_stack annotation), and then we extract the main function
43 extern fn thread_start(main: *libc::c_void) -> imp::rust_thread_return {
46 stack::record_stack_bounds(0, uint::max_value);
47 let f: ~proc() = cast::transmute(main);
49 cast::transmute(0 as imp::rust_thread_return)
53 // There are two impl blocks b/c if T were specified at the top then it's just a
54 // pain to specify a type parameter on Thread::spawn (which doesn't need the
58 /// Starts execution of a new OS thread.
60 /// This function will not wait for the thread to join, but a handle to the
61 /// thread will be returned.
63 /// Note that the handle returned is used to acquire the return value of the
64 /// procedure `main`. The `join` function will wait for the thread to finish
65 /// and return the value that `main` generated.
67 /// Also note that the `Thread` returned will *always* wait for the thread
68 /// to finish executing. This means that even if `join` is not explicitly
69 /// called, when the `Thread` falls out of scope its destructor will block
70 /// waiting for the OS thread.
71 pub fn start<T: Send>(main: proc() -> T) -> Thread<T> {
72 Thread::start_stack(DEFAULT_STACK_SIZE, main)
75 /// Performs the same functionality as `start`, but specifies an explicit
76 /// stack size for the new thread.
77 pub fn start_stack<T: Send>(stack: uint, main: proc() -> T) -> Thread<T> {
79 // We need the address of the packet to fill in to be stable so when
80 // `main` fills it in it's still valid, so allocate an extra ~ box to do
83 let packet2: *mut Option<T> = unsafe {
84 *cast::transmute::<&~Option<T>, **mut Option<T>>(&packet)
86 let main: proc() = proc() unsafe { *packet2 = Some(main()); };
87 let native = unsafe { imp::create(stack, ~main) };
96 /// This will spawn a new thread, but it will not wait for the thread to
97 /// finish, nor is it possible to wait for the thread to finish.
99 /// This corresponds to creating threads in the 'detached' state on unix
100 /// systems. Note that platforms may not keep the main program alive even if
101 /// there are detached thread still running around.
102 pub fn spawn(main: proc()) {
103 Thread::spawn_stack(DEFAULT_STACK_SIZE, main)
106 /// Performs the same functionality as `spawn`, but explicitly specifies a
107 /// stack size for the new thread.
108 pub fn spawn_stack(stack: uint, main: proc()) {
110 let handle = imp::create(stack, ~main);
115 /// Relinquishes the CPU slot that this OS-thread is currently using,
116 /// allowing another thread to run for awhile.
118 unsafe { imp::yield_now(); }
122 impl<T: Send> Thread<T> {
123 /// Wait for this thread to finish, returning the result of the thread's
125 pub fn join(mut self) -> T {
126 assert!(!self.joined);
127 unsafe { imp::join(self.native) };
129 assert!(self.packet.is_some());
130 self.packet.take_unwrap()
135 impl<T: Send> Drop for Thread<T> {
137 // This is required for correctness. If this is not done then the thread
138 // would fill in a return box which no longer exists.
140 unsafe { imp::join(self.native) };
149 use libc::types::os::arch::extra::{LPSECURITY_ATTRIBUTES, SIZE_T, BOOL,
150 LPVOID, DWORD, LPDWORD, HANDLE};
153 pub type rust_thread = HANDLE;
154 pub type rust_thread_return = DWORD;
156 pub unsafe fn create(stack: uint, p: ~proc()) -> rust_thread {
157 let arg: *mut libc::c_void = cast::transmute(p);
158 CreateThread(ptr::mut_null(), stack as libc::size_t, super::thread_start,
159 arg, 0, ptr::mut_null())
162 pub unsafe fn join(native: rust_thread) {
163 use libc::consts::os::extra::INFINITE;
164 WaitForSingleObject(native, INFINITE);
167 pub unsafe fn detach(native: rust_thread) {
168 assert!(libc::CloseHandle(native) != 0);
171 pub unsafe fn yield_now() {
172 // This function will return 0 if there are no other threads to execute,
173 // but this also means that the yield was useless so this isn't really a
174 // case that needs to be worried about.
179 fn CreateThread(lpThreadAttributes: LPSECURITY_ATTRIBUTES,
181 lpStartAddress: super::StartFn,
183 dwCreationFlags: DWORD,
184 lpThreadId: LPDWORD) -> HANDLE;
185 fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD;
186 fn SwitchToThread() -> BOOL;
193 use libc::consts::os::posix01::PTHREAD_CREATE_JOINABLE;
196 use unstable::intrinsics;
198 pub type rust_thread = libc::pthread_t;
199 pub type rust_thread_return = *libc::c_void;
201 pub unsafe fn create(stack: uint, p: ~proc()) -> rust_thread {
202 let mut native: libc::pthread_t = intrinsics::uninit();
203 let mut attr: libc::pthread_attr_t = intrinsics::uninit();
204 assert_eq!(pthread_attr_init(&mut attr), 0);
205 assert_eq!(pthread_attr_setstacksize(&mut attr,
206 stack as libc::size_t), 0);
207 assert_eq!(pthread_attr_setdetachstate(&mut attr,
208 PTHREAD_CREATE_JOINABLE), 0);
210 let arg: *libc::c_void = cast::transmute(p);
211 assert_eq!(pthread_create(&mut native, &attr,
212 super::thread_start, arg), 0);
216 pub unsafe fn join(native: rust_thread) {
217 assert_eq!(pthread_join(native, ptr::null()), 0);
220 pub unsafe fn detach(native: rust_thread) {
221 assert_eq!(pthread_detach(native), 0);
224 #[cfg(target_os = "macos")]
225 #[cfg(target_os = "android")]
226 pub unsafe fn yield_now() { assert_eq!(sched_yield(), 0); }
228 #[cfg(not(target_os = "macos"), not(target_os = "android"))]
229 pub unsafe fn yield_now() { assert_eq!(pthread_yield(), 0); }
232 fn pthread_create(native: *mut libc::pthread_t,
233 attr: *libc::pthread_attr_t,
235 value: *libc::c_void) -> libc::c_int;
236 fn pthread_join(native: libc::pthread_t,
237 value: **libc::c_void) -> libc::c_int;
238 fn pthread_attr_init(attr: *mut libc::pthread_attr_t) -> libc::c_int;
239 fn pthread_attr_setstacksize(attr: *mut libc::pthread_attr_t,
240 stack_size: libc::size_t) -> libc::c_int;
241 fn pthread_attr_setdetachstate(attr: *mut libc::pthread_attr_t,
242 state: libc::c_int) -> libc::c_int;
243 fn pthread_detach(thread: libc::pthread_t) -> libc::c_int;
245 #[cfg(target_os = "macos")]
246 #[cfg(target_os = "android")]
247 fn sched_yield() -> libc::c_int;
248 #[cfg(not(target_os = "macos"), not(target_os = "android"))]
249 fn pthread_yield() -> libc::c_int;
258 fn smoke() { do Thread::start {}.join(); }
261 fn data() { assert_eq!(do Thread::start { 1 }.join(), 1); }
264 fn detached() { do Thread::spawn {} }