]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | // Copyright 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. | |
4 | // | |
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. | |
10 | ||
54a0048b | 11 | //! Native threads. |
1a4d82fc JJ |
12 | //! |
13 | //! ## The threading model | |
14 | //! | |
15 | //! An executing Rust program consists of a collection of native OS threads, | |
a7813a04 XL |
16 | //! each with their own stack and local state. Threads can be named, and |
17 | //! provide some built-in support for low-level synchronization. | |
1a4d82fc JJ |
18 | //! |
19 | //! Communication between threads can be done through | |
476ff2be | 20 | //! [channels], Rust's message-passing types, along with [other forms of thread |
1a4d82fc JJ |
21 | //! synchronization](../../std/sync/index.html) and shared-memory data |
22 | //! structures. In particular, types that are guaranteed to be | |
23 | //! threadsafe are easily shared between threads using the | |
476ff2be | 24 | //! atomically-reference-counted container, [`Arc`]. |
1a4d82fc JJ |
25 | //! |
26 | //! Fatal logic errors in Rust cause *thread panic*, during which | |
27 | //! a thread will unwind the stack, running destructors and freeing | |
abe05a73 XL |
28 | //! owned resources. While not meant as a 'try/catch' mechanism, panics |
29 | //! in Rust can nonetheless be caught (unless compiling with `panic=abort`) with | |
30 | //! [`catch_unwind`](../../std/panic/fn.catch_unwind.html) and recovered | |
31 | //! from, or alternatively be resumed with | |
32 | //! [`resume_unwind`](../../std/panic/fn.resume_unwind.html). If the panic | |
33 | //! is not caught the thread will exit, but the panic may optionally be | |
34 | //! detected from a different thread with [`join`]. If the main thread panics | |
35 | //! without the panic being caught, the application will exit with a | |
36 | //! non-zero exit code. | |
1a4d82fc JJ |
37 | //! |
38 | //! When the main thread of a Rust program terminates, the entire program shuts | |
39 | //! down, even if other threads are still running. However, this module provides | |
40 | //! convenient facilities for automatically waiting for the termination of a | |
c34b1796 | 41 | //! child thread (i.e., join). |
1a4d82fc | 42 | //! |
1a4d82fc JJ |
43 | //! ## Spawning a thread |
44 | //! | |
476ff2be | 45 | //! A new thread can be spawned using the [`thread::spawn`][`spawn`] function: |
1a4d82fc JJ |
46 | //! |
47 | //! ```rust | |
85aaf69f | 48 | //! use std::thread; |
1a4d82fc | 49 | //! |
85aaf69f | 50 | //! thread::spawn(move || { |
c34b1796 | 51 | //! // some work here |
1a4d82fc JJ |
52 | //! }); |
53 | //! ``` | |
54 | //! | |
85aaf69f | 55 | //! In this example, the spawned thread is "detached" from the current |
c34b1796 AL |
56 | //! thread. This means that it can outlive its parent (the thread that spawned |
57 | //! it), unless this parent is the main thread. | |
1a4d82fc | 58 | //! |
9346a6ac | 59 | //! The parent thread can also wait on the completion of the child |
476ff2be | 60 | //! thread; a call to [`spawn`] produces a [`JoinHandle`], which provides |
9346a6ac AL |
61 | //! a `join` method for waiting: |
62 | //! | |
63 | //! ```rust | |
64 | //! use std::thread; | |
65 | //! | |
66 | //! let child = thread::spawn(move || { | |
67 | //! // some work here | |
68 | //! }); | |
69 | //! // some work here | |
70 | //! let res = child.join(); | |
71 | //! ``` | |
72 | //! | |
7cac9316 | 73 | //! The [`join`] method returns a [`thread::Result`] containing [`Ok`] of the final |
476ff2be SL |
74 | //! value produced by the child thread, or [`Err`] of the value given to |
75 | //! a call to [`panic!`] if the child panicked. | |
9346a6ac | 76 | //! |
1a4d82fc JJ |
77 | //! ## Configuring threads |
78 | //! | |
476ff2be | 79 | //! A new thread can be configured before it is spawned via the [`Builder`] type, |
bd371182 | 80 | //! which currently allows you to set the name and stack size for the child thread: |
1a4d82fc JJ |
81 | //! |
82 | //! ```rust | |
9346a6ac | 83 | //! # #![allow(unused_must_use)] |
1a4d82fc JJ |
84 | //! use std::thread; |
85 | //! | |
86 | //! thread::Builder::new().name("child1".to_string()).spawn(move || { | |
c34b1796 | 87 | //! println!("Hello, world!"); |
1a4d82fc JJ |
88 | //! }); |
89 | //! ``` | |
90 | //! | |
a7813a04 XL |
91 | //! ## The `Thread` type |
92 | //! | |
476ff2be | 93 | //! Threads are represented via the [`Thread`] type, which you can get in one of |
a7813a04 XL |
94 | //! two ways: |
95 | //! | |
476ff2be | 96 | //! * By spawning a new thread, e.g. using the [`thread::spawn`][`spawn`] |
cc61c64b XL |
97 | //! function, and calling [`thread`][`JoinHandle::thread`] on the [`JoinHandle`]. |
98 | //! * By requesting the current thread, using the [`thread::current`] function. | |
a7813a04 | 99 | //! |
cc61c64b | 100 | //! The [`thread::current`] function is available even for threads not spawned |
a7813a04 XL |
101 | //! by the APIs of this module. |
102 | //! | |
c34b1796 AL |
103 | //! ## Thread-local storage |
104 | //! | |
9e0c209e SL |
105 | //! This module also provides an implementation of thread-local storage for Rust |
106 | //! programs. Thread-local storage is a method of storing data into a global | |
107 | //! variable that each thread in the program will have its own copy of. | |
c34b1796 AL |
108 | //! Threads do not share this data, so accesses do not need to be synchronized. |
109 | //! | |
9e0c209e SL |
110 | //! A thread-local key owns the value it contains and will destroy the value when the |
111 | //! thread exits. It is created with the [`thread_local!`] macro and can contain any | |
112 | //! value that is `'static` (no borrowed pointers). It provides an accessor function, | |
113 | //! [`with`], that yields a shared reference to the value to the specified | |
114 | //! closure. Thread-local keys allow only shared access to values, as there would be no | |
115 | //! way to guarantee uniqueness if mutable borrows were allowed. Most values | |
c34b1796 | 116 | //! will want to make use of some form of **interior mutability** through the |
9e0c209e SL |
117 | //! [`Cell`] or [`RefCell`] types. |
118 | //! | |
3b2f2976 XL |
119 | //! ## Naming threads |
120 | //! | |
121 | //! Threads are able to have associated names for identification purposes. By default, spawned | |
122 | //! threads are unnamed. To specify a name for a thread, build the thread with [`Builder`] and pass | |
123 | //! the desired thread name to [`Builder::name`]. To retrieve the thread name from within the | |
124 | //! thread, use [`Thread::name`]. A couple examples of where the name of a thread gets used: | |
125 | //! | |
126 | //! * If a panic occurs in a named thread, the thread name will be printed in the panic message. | |
127 | //! * The thread name is provided to the OS where applicable (e.g. `pthread_setname_np` in | |
128 | //! unix-like platforms). | |
129 | //! | |
130 | //! ## Stack size | |
131 | //! | |
132 | //! The default stack size for spawned threads is 2 MiB, though this particular stack size is | |
133 | //! subject to change in the future. There are two ways to manually specify the stack size for | |
134 | //! spawned threads: | |
135 | //! | |
136 | //! * Build the thread with [`Builder`] and pass the desired stack size to [`Builder::stack_size`]. | |
137 | //! * Set the `RUST_MIN_STACK` environment variable to an integer representing the desired stack | |
138 | //! size (in bytes). Note that setting [`Builder::stack_size`] will override this. | |
139 | //! | |
140 | //! Note that the stack size of the main thread is *not* determined by Rust. | |
141 | //! | |
476ff2be SL |
142 | //! [channels]: ../../std/sync/mpsc/index.html |
143 | //! [`Arc`]: ../../std/sync/struct.Arc.html | |
144 | //! [`spawn`]: ../../std/thread/fn.spawn.html | |
145 | //! [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html | |
cc61c64b | 146 | //! [`JoinHandle::thread`]: ../../std/thread/struct.JoinHandle.html#method.thread |
476ff2be SL |
147 | //! [`join`]: ../../std/thread/struct.JoinHandle.html#method.join |
148 | //! [`Result`]: ../../std/result/enum.Result.html | |
149 | //! [`Ok`]: ../../std/result/enum.Result.html#variant.Ok | |
150 | //! [`Err`]: ../../std/result/enum.Result.html#variant.Err | |
151 | //! [`panic!`]: ../../std/macro.panic.html | |
152 | //! [`Builder`]: ../../std/thread/struct.Builder.html | |
3b2f2976 XL |
153 | //! [`Builder::stack_size`]: ../../std/thread/struct.Builder.html#method.stack_size |
154 | //! [`Builder::name`]: ../../std/thread/struct.Builder.html#method.name | |
cc61c64b | 155 | //! [`thread::current`]: ../../std/thread/fn.current.html |
7cac9316 | 156 | //! [`thread::Result`]: ../../std/thread/type.Result.html |
476ff2be | 157 | //! [`Thread`]: ../../std/thread/struct.Thread.html |
cc61c64b XL |
158 | //! [`park`]: ../../std/thread/fn.park.html |
159 | //! [`unpark`]: ../../std/thread/struct.Thread.html#method.unpark | |
3b2f2976 | 160 | //! [`Thread::name`]: ../../std/thread/struct.Thread.html#method.name |
cc61c64b | 161 | //! [`thread::park_timeout`]: ../../std/thread/fn.park_timeout.html |
9e0c209e SL |
162 | //! [`Cell`]: ../cell/struct.Cell.html |
163 | //! [`RefCell`]: ../cell/struct.RefCell.html | |
c30ab7b3 | 164 | //! [`thread_local!`]: ../macro.thread_local.html |
9e0c209e | 165 | //! [`with`]: struct.LocalKey.html#method.with |
1a4d82fc | 166 | |
85aaf69f SL |
167 | #![stable(feature = "rust1", since = "1.0.0")] |
168 | ||
1a4d82fc | 169 | use any::Any; |
1a4d82fc | 170 | use cell::UnsafeCell; |
a7813a04 | 171 | use ffi::{CStr, CString}; |
85aaf69f SL |
172 | use fmt; |
173 | use io; | |
a7813a04 XL |
174 | use panic; |
175 | use panicking; | |
54a0048b | 176 | use str; |
85aaf69f | 177 | use sync::{Mutex, Condvar, Arc}; |
abe05a73 XL |
178 | use sync::atomic::AtomicUsize; |
179 | use sync::atomic::Ordering::SeqCst; | |
c34b1796 | 180 | use sys::thread as imp; |
c30ab7b3 | 181 | use sys_common::mutex; |
e9174d1e | 182 | use sys_common::thread_info; |
ea8adc8c | 183 | use sys_common::thread; |
92a42be0 | 184 | use sys_common::{AsInner, IntoInner}; |
85aaf69f | 185 | use time::Duration; |
1a4d82fc | 186 | |
c34b1796 AL |
187 | //////////////////////////////////////////////////////////////////////////////// |
188 | // Thread-local storage | |
189 | //////////////////////////////////////////////////////////////////////////////// | |
190 | ||
9346a6ac | 191 | #[macro_use] mod local; |
9346a6ac AL |
192 | |
193 | #[stable(feature = "rust1", since = "1.0.0")] | |
041b39d2 | 194 | pub use self::local::{LocalKey, LocalKeyState, AccessError}; |
9346a6ac | 195 | |
c30ab7b3 SL |
196 | // The types used by the thread_local! macro to access TLS keys. Note that there |
197 | // are two types, the "OS" type and the "fast" type. The OS thread local key | |
198 | // type is accessed via platform-specific API calls and is slow, while the fast | |
199 | // key type is accessed via code generated via LLVM, where TLS keys are set up | |
200 | // by the elf linker. Note that the OS TLS type is always available: on macOS | |
201 | // the standard library is compiled with support for older platform versions | |
202 | // where fast TLS was not available; end-user code is compiled with fast TLS | |
203 | // where available, but both are needed. | |
204 | ||
92a42be0 | 205 | #[unstable(feature = "libstd_thread_internals", issue = "0")] |
9cc50fc6 | 206 | #[cfg(target_thread_local)] |
041b39d2 | 207 | #[doc(hidden)] pub use self::local::fast::Key as __FastLocalKeyInner; |
9cc50fc6 SL |
208 | #[unstable(feature = "libstd_thread_internals", issue = "0")] |
209 | #[doc(hidden)] pub use self::local::os::Key as __OsLocalKeyInner; | |
c34b1796 AL |
210 | |
211 | //////////////////////////////////////////////////////////////////////////////// | |
212 | // Builder | |
213 | //////////////////////////////////////////////////////////////////////////////// | |
1a4d82fc | 214 | |
7cac9316 XL |
215 | /// Thread factory, which can be used in order to configure the properties of |
216 | /// a new thread. | |
217 | /// | |
218 | /// Methods can be chained on it in order to configure it. | |
219 | /// | |
220 | /// The two configurations available are: | |
221 | /// | |
3b2f2976 XL |
222 | /// - [`name`]: specifies an [associated name for the thread][naming-threads] |
223 | /// - [`stack_size`]: specifies the [desired stack size for the thread][stack-size] | |
7cac9316 XL |
224 | /// |
225 | /// The [`spawn`] method will take ownership of the builder and create an | |
226 | /// [`io::Result`] to the thread handle with the given configuration. | |
227 | /// | |
228 | /// The [`thread::spawn`] free function uses a `Builder` with default | |
229 | /// configuration and [`unwrap`]s its return value. | |
230 | /// | |
231 | /// You may want to use [`spawn`] instead of [`thread::spawn`], when you want | |
232 | /// to recover from a failure to launch a thread, indeed the free function will | |
233 | /// panick where the `Builder` method will return a [`io::Result`]. | |
32a655c1 SL |
234 | /// |
235 | /// # Examples | |
236 | /// | |
237 | /// ``` | |
238 | /// use std::thread; | |
239 | /// | |
240 | /// let builder = thread::Builder::new(); | |
241 | /// | |
242 | /// let handler = builder.spawn(|| { | |
243 | /// // thread code | |
244 | /// }).unwrap(); | |
245 | /// | |
246 | /// handler.join().unwrap(); | |
247 | /// ``` | |
7cac9316 XL |
248 | /// |
249 | /// [`thread::spawn`]: ../../std/thread/fn.spawn.html | |
250 | /// [`stack_size`]: ../../std/thread/struct.Builder.html#method.stack_size | |
251 | /// [`name`]: ../../std/thread/struct.Builder.html#method.name | |
252 | /// [`spawn`]: ../../std/thread/struct.Builder.html#method.spawn | |
253 | /// [`io::Result`]: ../../std/io/type.Result.html | |
254 | /// [`unwrap`]: ../../std/result/enum.Result.html#method.unwrap | |
3b2f2976 XL |
255 | /// [naming-threads]: ./index.html#naming-threads |
256 | /// [stack-size]: ./index.html#stack-size | |
85aaf69f | 257 | #[stable(feature = "rust1", since = "1.0.0")] |
32a655c1 | 258 | #[derive(Debug)] |
1a4d82fc JJ |
259 | pub struct Builder { |
260 | // A name for the thread-to-be, for identification in panic messages | |
261 | name: Option<String>, | |
8bb4bdeb | 262 | // The size of the stack for the spawned thread in bytes |
c34b1796 | 263 | stack_size: Option<usize>, |
1a4d82fc JJ |
264 | } |
265 | ||
266 | impl Builder { | |
9346a6ac | 267 | /// Generates the base configuration for spawning a thread, from which |
1a4d82fc | 268 | /// configuration methods can be chained. |
32a655c1 SL |
269 | /// |
270 | /// # Examples | |
271 | /// | |
272 | /// ``` | |
273 | /// use std::thread; | |
274 | /// | |
275 | /// let builder = thread::Builder::new() | |
276 | /// .name("foo".into()) | |
277 | /// .stack_size(10); | |
278 | /// | |
279 | /// let handler = builder.spawn(|| { | |
280 | /// // thread code | |
281 | /// }).unwrap(); | |
282 | /// | |
283 | /// handler.join().unwrap(); | |
284 | /// ``` | |
85aaf69f | 285 | #[stable(feature = "rust1", since = "1.0.0")] |
1a4d82fc JJ |
286 | pub fn new() -> Builder { |
287 | Builder { | |
288 | name: None, | |
289 | stack_size: None, | |
1a4d82fc JJ |
290 | } |
291 | } | |
292 | ||
9346a6ac | 293 | /// Names the thread-to-be. Currently the name is used for identification |
1a4d82fc | 294 | /// only in panic messages. |
3157f602 | 295 | /// |
ea8adc8c XL |
296 | /// The name must not contain null bytes (`\0`). |
297 | /// | |
3b2f2976 XL |
298 | /// For more information about named threads, see |
299 | /// [this module-level documentation][naming-threads]. | |
300 | /// | |
3157f602 XL |
301 | /// # Examples |
302 | /// | |
32a655c1 | 303 | /// ``` |
3157f602 XL |
304 | /// use std::thread; |
305 | /// | |
306 | /// let builder = thread::Builder::new() | |
307 | /// .name("foo".into()); | |
308 | /// | |
309 | /// let handler = builder.spawn(|| { | |
310 | /// assert_eq!(thread::current().name(), Some("foo")) | |
311 | /// }).unwrap(); | |
312 | /// | |
313 | /// handler.join().unwrap(); | |
314 | /// ``` | |
3b2f2976 XL |
315 | /// |
316 | /// [naming-threads]: ./index.html#naming-threads | |
85aaf69f | 317 | #[stable(feature = "rust1", since = "1.0.0")] |
1a4d82fc JJ |
318 | pub fn name(mut self, name: String) -> Builder { |
319 | self.name = Some(name); | |
320 | self | |
321 | } | |
322 | ||
8bb4bdeb XL |
323 | /// Sets the size of the stack (in bytes) for the new thread. |
324 | /// | |
325 | /// The actual stack size may be greater than this value if | |
326 | /// the platform specifies minimal stack size. | |
32a655c1 | 327 | /// |
3b2f2976 XL |
328 | /// For more information about the stack size for threads, see |
329 | /// [this module-level documentation][stack-size]. | |
330 | /// | |
32a655c1 SL |
331 | /// # Examples |
332 | /// | |
333 | /// ``` | |
334 | /// use std::thread; | |
335 | /// | |
8bb4bdeb | 336 | /// let builder = thread::Builder::new().stack_size(32 * 1024); |
32a655c1 | 337 | /// ``` |
3b2f2976 XL |
338 | /// |
339 | /// [stack-size]: ./index.html#stack-size | |
85aaf69f | 340 | #[stable(feature = "rust1", since = "1.0.0")] |
c34b1796 | 341 | pub fn stack_size(mut self, size: usize) -> Builder { |
1a4d82fc JJ |
342 | self.stack_size = Some(size); |
343 | self | |
344 | } | |
345 | ||
7cac9316 XL |
346 | /// Spawns a new thread by taking ownership of the `Builder`, and returns an |
347 | /// [`io::Result`] to its [`JoinHandle`]. | |
1a4d82fc | 348 | /// |
7cac9316 | 349 | /// The spawned thread may outlive the caller (unless the caller thread |
85aaf69f | 350 | /// is the main thread; the whole process is terminated when the main |
bd371182 | 351 | /// thread finishes). The join handle can be used to block on |
85aaf69f SL |
352 | /// termination of the child thread, including recovering its panics. |
353 | /// | |
7cac9316 XL |
354 | /// For a more complete documentation see [`thread::spawn`][`spawn`]. |
355 | /// | |
85aaf69f SL |
356 | /// # Errors |
357 | /// | |
32a655c1 SL |
358 | /// Unlike the [`spawn`] free function, this method yields an |
359 | /// [`io::Result`] to capture any failure to create the thread at | |
85aaf69f | 360 | /// the OS level. |
32a655c1 SL |
361 | /// |
362 | /// [`spawn`]: ../../std/thread/fn.spawn.html | |
363 | /// [`io::Result`]: ../../std/io/type.Result.html | |
7cac9316 | 364 | /// [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html |
32a655c1 | 365 | /// |
ea8adc8c XL |
366 | /// # Panics |
367 | /// | |
368 | /// Panics if a thread name was set and it contained null bytes. | |
369 | /// | |
32a655c1 SL |
370 | /// # Examples |
371 | /// | |
372 | /// ``` | |
373 | /// use std::thread; | |
374 | /// | |
375 | /// let builder = thread::Builder::new(); | |
376 | /// | |
377 | /// let handler = builder.spawn(|| { | |
378 | /// // thread code | |
379 | /// }).unwrap(); | |
380 | /// | |
381 | /// handler.join().unwrap(); | |
382 | /// ``` | |
85aaf69f | 383 | #[stable(feature = "rust1", since = "1.0.0")] |
9346a6ac AL |
384 | pub fn spawn<F, T>(self, f: F) -> io::Result<JoinHandle<T>> where |
385 | F: FnOnce() -> T, F: Send + 'static, T: Send + 'static | |
85aaf69f | 386 | { |
c34b1796 | 387 | let Builder { name, stack_size } = self; |
1a4d82fc | 388 | |
ea8adc8c | 389 | let stack_size = stack_size.unwrap_or_else(thread::min_stack); |
85aaf69f | 390 | |
1a4d82fc JJ |
391 | let my_thread = Thread::new(name); |
392 | let their_thread = my_thread.clone(); | |
393 | ||
b039eaaf SL |
394 | let my_packet : Arc<UnsafeCell<Option<Result<T>>>> |
395 | = Arc::new(UnsafeCell::new(None)); | |
d9579d0f | 396 | let their_packet = my_packet.clone(); |
85aaf69f | 397 | |
85aaf69f | 398 | let main = move || { |
54a0048b | 399 | if let Some(name) = their_thread.cname() { |
d9579d0f | 400 | imp::Thread::set_name(name); |
85aaf69f | 401 | } |
b039eaaf SL |
402 | unsafe { |
403 | thread_info::set(imp::guard::current(), their_thread); | |
7cac9316 XL |
404 | #[cfg(feature = "backtrace")] |
405 | let try_result = panic::catch_unwind(panic::AssertUnwindSafe(|| { | |
406 | ::sys_common::backtrace::__rust_begin_short_backtrace(f) | |
407 | })); | |
408 | #[cfg(not(feature = "backtrace"))] | |
a7813a04 XL |
409 | let try_result = panic::catch_unwind(panic::AssertUnwindSafe(f)); |
410 | *their_packet.get() = Some(try_result); | |
b039eaaf | 411 | } |
1a4d82fc JJ |
412 | }; |
413 | ||
b039eaaf SL |
414 | Ok(JoinHandle(JoinInner { |
415 | native: unsafe { | |
54a0048b | 416 | Some(imp::Thread::new(stack_size, Box::new(main))?) |
b039eaaf | 417 | }, |
85aaf69f | 418 | thread: my_thread, |
d9579d0f | 419 | packet: Packet(my_packet), |
b039eaaf | 420 | })) |
1a4d82fc JJ |
421 | } |
422 | } | |
423 | ||
c34b1796 AL |
424 | //////////////////////////////////////////////////////////////////////////////// |
425 | // Free functions | |
426 | //////////////////////////////////////////////////////////////////////////////// | |
427 | ||
32a655c1 | 428 | /// Spawns a new thread, returning a [`JoinHandle`] for it. |
85aaf69f | 429 | /// |
c34b1796 AL |
430 | /// The join handle will implicitly *detach* the child thread upon being |
431 | /// dropped. In this case, the child thread may outlive the parent (unless | |
432 | /// the parent thread is the main thread; the whole process is terminated when | |
32a655c1 | 433 | /// the main thread finishes). Additionally, the join handle provides a [`join`] |
c34b1796 | 434 | /// method that can be used to join the child thread. If the child thread |
32a655c1 SL |
435 | /// panics, [`join`] will return an [`Err`] containing the argument given to |
436 | /// [`panic`]. | |
85aaf69f | 437 | /// |
7cac9316 XL |
438 | /// This will create a thread using default parameters of [`Builder`], if you |
439 | /// want to specify the stack size or the name of the thread, use this API | |
440 | /// instead. | |
441 | /// | |
442 | /// As you can see in the signature of `spawn` there are two constraints on | |
443 | /// both the closure given to `spawn` and its return value, let's explain them: | |
444 | /// | |
445 | /// - The `'static` constraint means that the closure and its return value | |
446 | /// must have a lifetime of the whole program execution. The reason for this | |
447 | /// is that threads can `detach` and outlive the lifetime they have been | |
448 | /// created in. | |
449 | /// Indeed if the thread, and by extension its return value, can outlive their | |
450 | /// caller, we need to make sure that they will be valid afterwards, and since | |
451 | /// we *can't* know when it will return we need to have them valid as long as | |
452 | /// possible, that is until the end of the program, hence the `'static` | |
453 | /// lifetime. | |
454 | /// - The [`Send`] constraint is because the closure will need to be passed | |
455 | /// *by value* from the thread where it is spawned to the new thread. Its | |
456 | /// return value will need to be passed from the new thread to the thread | |
457 | /// where it is `join`ed. | |
3b2f2976 | 458 | /// As a reminder, the [`Send`] marker trait expresses that it is safe to be |
7cac9316 XL |
459 | /// passed from thread to thread. [`Sync`] expresses that it is safe to have a |
460 | /// reference be passed from thread to thread. | |
461 | /// | |
85aaf69f SL |
462 | /// # Panics |
463 | /// | |
32a655c1 | 464 | /// Panics if the OS fails to create a thread; use [`Builder::spawn`] |
85aaf69f | 465 | /// to recover from such errors. |
32a655c1 | 466 | /// |
32a655c1 SL |
467 | /// # Examples |
468 | /// | |
7cac9316 XL |
469 | /// Creating a thread. |
470 | /// | |
32a655c1 SL |
471 | /// ``` |
472 | /// use std::thread; | |
473 | /// | |
474 | /// let handler = thread::spawn(|| { | |
475 | /// // thread code | |
476 | /// }); | |
477 | /// | |
478 | /// handler.join().unwrap(); | |
479 | /// ``` | |
7cac9316 XL |
480 | /// |
481 | /// As mentioned in the module documentation, threads are usually made to | |
482 | /// communicate using [`channels`], here is how it usually looks. | |
483 | /// | |
484 | /// This example also shows how to use `move`, in order to give ownership | |
485 | /// of values to a thread. | |
486 | /// | |
487 | /// ``` | |
488 | /// use std::thread; | |
489 | /// use std::sync::mpsc::channel; | |
490 | /// | |
491 | /// let (tx, rx) = channel(); | |
492 | /// | |
493 | /// let sender = thread::spawn(move || { | |
abe05a73 XL |
494 | /// tx.send("Hello, thread".to_owned()) |
495 | /// .expect("Unable to send on channel"); | |
7cac9316 XL |
496 | /// }); |
497 | /// | |
498 | /// let receiver = thread::spawn(move || { | |
abe05a73 XL |
499 | /// let value = rx.recv().expect("Unable to receive from channel"); |
500 | /// println!("{}", value); | |
7cac9316 XL |
501 | /// }); |
502 | /// | |
abe05a73 XL |
503 | /// sender.join().expect("The sender thread has panicked"); |
504 | /// receiver.join().expect("The receiver thread has panicked"); | |
7cac9316 XL |
505 | /// ``` |
506 | /// | |
507 | /// A thread can also return a value through its [`JoinHandle`], you can use | |
508 | /// this to make asynchronous computations (futures might be more appropriate | |
509 | /// though). | |
510 | /// | |
511 | /// ``` | |
512 | /// use std::thread; | |
513 | /// | |
514 | /// let computation = thread::spawn(|| { | |
515 | /// // Some expensive computation. | |
516 | /// 42 | |
517 | /// }); | |
518 | /// | |
519 | /// let result = computation.join().unwrap(); | |
520 | /// println!("{}", result); | |
521 | /// ``` | |
522 | /// | |
523 | /// [`channels`]: ../../std/sync/mpsc/index.html | |
524 | /// [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html | |
525 | /// [`join`]: ../../std/thread/struct.JoinHandle.html#method.join | |
526 | /// [`Err`]: ../../std/result/enum.Result.html#variant.Err | |
527 | /// [`panic`]: ../../std/macro.panic.html | |
528 | /// [`Builder::spawn`]: ../../std/thread/struct.Builder.html#method.spawn | |
529 | /// [`Builder`]: ../../std/thread/struct.Builder.html | |
530 | /// [`Send`]: ../../std/marker/trait.Send.html | |
531 | /// [`Sync`]: ../../std/marker/trait.Sync.html | |
85aaf69f | 532 | #[stable(feature = "rust1", since = "1.0.0")] |
9346a6ac AL |
533 | pub fn spawn<F, T>(f: F) -> JoinHandle<T> where |
534 | F: FnOnce() -> T, F: Send + 'static, T: Send + 'static | |
535 | { | |
85aaf69f SL |
536 | Builder::new().spawn(f).unwrap() |
537 | } | |
538 | ||
85aaf69f | 539 | /// Gets a handle to the thread that invokes it. |
9e0c209e | 540 | /// |
32a655c1 | 541 | /// # Examples |
9e0c209e SL |
542 | /// |
543 | /// Getting a handle to the current thread with `thread::current()`: | |
544 | /// | |
545 | /// ``` | |
546 | /// use std::thread; | |
547 | /// | |
548 | /// let handler = thread::Builder::new() | |
549 | /// .name("named thread".into()) | |
550 | /// .spawn(|| { | |
551 | /// let handle = thread::current(); | |
552 | /// assert_eq!(handle.name(), Some("named thread")); | |
553 | /// }) | |
554 | /// .unwrap(); | |
555 | /// | |
556 | /// handler.join().unwrap(); | |
557 | /// ``` | |
85aaf69f SL |
558 | #[stable(feature = "rust1", since = "1.0.0")] |
559 | pub fn current() -> Thread { | |
d9579d0f AL |
560 | thread_info::current_thread().expect("use of std::thread::current() is not \ |
561 | possible after the thread's local \ | |
562 | data has been destroyed") | |
85aaf69f SL |
563 | } |
564 | ||
9346a6ac | 565 | /// Cooperatively gives up a timeslice to the OS scheduler. |
32a655c1 | 566 | /// |
7cac9316 XL |
567 | /// This is used when the programmer knows that the thread will have nothing |
568 | /// to do for some time, and thus avoid wasting computing time. | |
569 | /// | |
570 | /// For example when polling on a resource, it is common to check that it is | |
571 | /// available, and if not to yield in order to avoid busy waiting. | |
572 | /// | |
573 | /// Thus the pattern of `yield`ing after a failed poll is rather common when | |
574 | /// implementing low-level shared resources or synchronization primitives. | |
575 | /// | |
3b2f2976 XL |
576 | /// However programmers will usually prefer to use, [`channel`]s, [`Condvar`]s, |
577 | /// [`Mutex`]es or [`join`] for their synchronization routines, as they avoid | |
578 | /// thinking about thread scheduling. | |
7cac9316 XL |
579 | /// |
580 | /// Note that [`channel`]s for example are implemented using this primitive. | |
581 | /// Indeed when you call `send` or `recv`, which are blocking, they will yield | |
582 | /// if the channel is not available. | |
583 | /// | |
32a655c1 SL |
584 | /// # Examples |
585 | /// | |
586 | /// ``` | |
587 | /// use std::thread; | |
588 | /// | |
589 | /// thread::yield_now(); | |
590 | /// ``` | |
7cac9316 XL |
591 | /// |
592 | /// [`channel`]: ../../std/sync/mpsc/index.html | |
593 | /// [`spawn`]: ../../std/thread/fn.spawn.html | |
594 | /// [`join`]: ../../std/thread/struct.JoinHandle.html#method.join | |
595 | /// [`Mutex`]: ../../std/sync/struct.Mutex.html | |
596 | /// [`Condvar`]: ../../std/sync/struct.Condvar.html | |
85aaf69f SL |
597 | #[stable(feature = "rust1", since = "1.0.0")] |
598 | pub fn yield_now() { | |
d9579d0f | 599 | imp::Thread::yield_now() |
85aaf69f SL |
600 | } |
601 | ||
602 | /// Determines whether the current thread is unwinding because of panic. | |
3157f602 | 603 | /// |
7cac9316 XL |
604 | /// A common use of this feature is to poison shared resources when writing |
605 | /// unsafe code, by checking `panicking` when the `drop` is called. | |
606 | /// | |
607 | /// This is usually not needed when writing safe code, as [`Mutex`es][Mutex] | |
608 | /// already poison themselves when a thread panics while holding the lock. | |
609 | /// | |
610 | /// This can also be used in multithreaded applications, in order to send a | |
611 | /// message to other threads warning that a thread has panicked (e.g. for | |
612 | /// monitoring purposes). | |
613 | /// | |
3157f602 XL |
614 | /// # Examples |
615 | /// | |
32a655c1 | 616 | /// ```should_panic |
3157f602 XL |
617 | /// use std::thread; |
618 | /// | |
619 | /// struct SomeStruct; | |
620 | /// | |
621 | /// impl Drop for SomeStruct { | |
622 | /// fn drop(&mut self) { | |
623 | /// if thread::panicking() { | |
624 | /// println!("dropped while unwinding"); | |
625 | /// } else { | |
626 | /// println!("dropped while not unwinding"); | |
627 | /// } | |
628 | /// } | |
629 | /// } | |
630 | /// | |
631 | /// { | |
632 | /// print!("a: "); | |
633 | /// let a = SomeStruct; | |
634 | /// } | |
635 | /// | |
636 | /// { | |
637 | /// print!("b: "); | |
638 | /// let b = SomeStruct; | |
639 | /// panic!() | |
640 | /// } | |
641 | /// ``` | |
7cac9316 XL |
642 | /// |
643 | /// [Mutex]: ../../std/sync/struct.Mutex.html | |
85aaf69f SL |
644 | #[inline] |
645 | #[stable(feature = "rust1", since = "1.0.0")] | |
646 | pub fn panicking() -> bool { | |
a7813a04 | 647 | panicking::panicking() |
85aaf69f SL |
648 | } |
649 | ||
9346a6ac | 650 | /// Puts the current thread to sleep for the specified amount of time. |
c34b1796 AL |
651 | /// |
652 | /// The thread may sleep longer than the duration specified due to scheduling | |
32a655c1 SL |
653 | /// specifics or platform-dependent functionality. |
654 | /// | |
655 | /// # Platform behavior | |
656 | /// | |
657 | /// On Unix platforms this function will not return early due to a | |
658 | /// signal being received or a spurious wakeup. | |
659 | /// | |
660 | /// # Examples | |
661 | /// | |
662 | /// ```no_run | |
663 | /// use std::thread; | |
664 | /// | |
665 | /// // Let's sleep for 2 seconds: | |
666 | /// thread::sleep_ms(2000); | |
667 | /// ``` | |
c34b1796 | 668 | #[stable(feature = "rust1", since = "1.0.0")] |
92a42be0 | 669 | #[rustc_deprecated(since = "1.6.0", reason = "replaced by `std::thread::sleep`")] |
c34b1796 | 670 | pub fn sleep_ms(ms: u32) { |
d9579d0f AL |
671 | sleep(Duration::from_millis(ms as u64)) |
672 | } | |
673 | ||
674 | /// Puts the current thread to sleep for the specified amount of time. | |
675 | /// | |
676 | /// The thread may sleep longer than the duration specified due to scheduling | |
677 | /// specifics or platform-dependent functionality. | |
678 | /// | |
679 | /// # Platform behavior | |
680 | /// | |
681 | /// On Unix platforms this function will not return early due to a | |
682 | /// signal being received or a spurious wakeup. Platforms which do not support | |
683 | /// nanosecond precision for sleeping will have `dur` rounded up to the nearest | |
684 | /// granularity of time they can sleep for. | |
3157f602 XL |
685 | /// |
686 | /// # Examples | |
687 | /// | |
32a655c1 | 688 | /// ```no_run |
3157f602 XL |
689 | /// use std::{thread, time}; |
690 | /// | |
691 | /// let ten_millis = time::Duration::from_millis(10); | |
692 | /// let now = time::Instant::now(); | |
693 | /// | |
694 | /// thread::sleep(ten_millis); | |
695 | /// | |
696 | /// assert!(now.elapsed() >= ten_millis); | |
697 | /// ``` | |
e9174d1e | 698 | #[stable(feature = "thread_sleep", since = "1.4.0")] |
d9579d0f AL |
699 | pub fn sleep(dur: Duration) { |
700 | imp::Thread::sleep(dur) | |
c34b1796 AL |
701 | } |
702 | ||
abe05a73 XL |
703 | // constants for park/unpark |
704 | const EMPTY: usize = 0; | |
705 | const PARKED: usize = 1; | |
706 | const NOTIFIED: usize = 2; | |
707 | ||
c1a9b12d SL |
708 | /// Blocks unless or until the current thread's token is made available. |
709 | /// | |
7cac9316 XL |
710 | /// A call to `park` does not guarantee that the thread will remain parked |
711 | /// forever, and callers should be prepared for this possibility. | |
712 | /// | |
713 | /// # park and unpark | |
714 | /// | |
715 | /// Every thread is equipped with some basic low-level blocking support, via the | |
716 | /// [`thread::park`][`park`] function and [`thread::Thread::unpark`][`unpark`] | |
717 | /// method. [`park`] blocks the current thread, which can then be resumed from | |
718 | /// another thread by calling the [`unpark`] method on the blocked thread's | |
719 | /// handle. | |
720 | /// | |
721 | /// Conceptually, each [`Thread`] handle has an associated token, which is | |
722 | /// initially not present: | |
c1a9b12d | 723 | /// |
7cac9316 XL |
724 | /// * The [`thread::park`][`park`] function blocks the current thread unless or |
725 | /// until the token is available for its thread handle, at which point it | |
726 | /// atomically consumes the token. It may also return *spuriously*, without | |
727 | /// consuming the token. [`thread::park_timeout`] does the same, but allows | |
728 | /// specifying a maximum time to block the thread for. | |
729 | /// | |
730 | /// * The [`unpark`] method on a [`Thread`] atomically makes the token available | |
731 | /// if it wasn't already. | |
732 | /// | |
733 | /// In other words, each [`Thread`] acts a bit like a spinlock that can be | |
734 | /// locked and unlocked using `park` and `unpark`. | |
c1a9b12d SL |
735 | /// |
736 | /// The API is typically used by acquiring a handle to the current thread, | |
737 | /// placing that handle in a shared data structure so that other threads can | |
7cac9316 XL |
738 | /// find it, and then `park`ing. When some desired condition is met, another |
739 | /// thread calls [`unpark`] on the handle. | |
c1a9b12d | 740 | /// |
7cac9316 | 741 | /// The motivation for this design is twofold: |
c1a9b12d | 742 | /// |
7cac9316 XL |
743 | /// * It avoids the need to allocate mutexes and condvars when building new |
744 | /// synchronization primitives; the threads already provide basic | |
745 | /// blocking/signaling. | |
85aaf69f | 746 | /// |
7cac9316 XL |
747 | /// * It can be implemented very efficiently on many platforms. |
748 | /// | |
749 | /// # Examples | |
750 | /// | |
751 | /// ``` | |
752 | /// use std::thread; | |
753 | /// use std::time::Duration; | |
754 | /// | |
755 | /// let parked_thread = thread::Builder::new() | |
756 | /// .spawn(|| { | |
757 | /// println!("Parking thread"); | |
758 | /// thread::park(); | |
759 | /// println!("Thread unparked"); | |
760 | /// }) | |
761 | /// .unwrap(); | |
762 | /// | |
763 | /// // Let some time pass for the thread to be spawned. | |
764 | /// thread::sleep(Duration::from_millis(10)); | |
765 | /// | |
766 | /// println!("Unpark the thread"); | |
767 | /// parked_thread.thread().unpark(); | |
768 | /// | |
769 | /// parked_thread.join().unwrap(); | |
770 | /// ``` | |
771 | /// | |
772 | /// [`Thread`]: ../../std/thread/struct.Thread.html | |
773 | /// [`park`]: ../../std/thread/fn.park.html | |
774 | /// [`unpark`]: ../../std/thread/struct.Thread.html#method.unpark | |
775 | /// [`thread::park_timeout`]: ../../std/thread/fn.park_timeout.html | |
85aaf69f SL |
776 | // |
777 | // The implementation currently uses the trivial strategy of a Mutex+Condvar | |
778 | // with wakeup flag, which does not actually allow spurious wakeups. In the | |
779 | // future, this will be implemented in a more efficient way, perhaps along the lines of | |
780 | // http://cr.openjdk.java.net/~stefank/6989984.1/raw_files/new/src/os/linux/vm/os_linux.cpp | |
781 | // or futuxes, and in either case may allow spurious wakeups. | |
782 | #[stable(feature = "rust1", since = "1.0.0")] | |
783 | pub fn park() { | |
784 | let thread = current(); | |
abe05a73 XL |
785 | |
786 | // If we were previously notified then we consume this notification and | |
787 | // return quickly. | |
788 | if thread.inner.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() { | |
789 | return | |
790 | } | |
791 | ||
792 | // Otherwise we need to coordinate going to sleep | |
793 | let mut m = thread.inner.lock.lock().unwrap(); | |
794 | match thread.inner.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) { | |
795 | Ok(_) => {} | |
796 | Err(NOTIFIED) => return, // notified after we locked | |
797 | Err(_) => panic!("inconsistent park state"), | |
798 | } | |
799 | loop { | |
800 | m = thread.inner.cvar.wait(m).unwrap(); | |
801 | match thread.inner.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst) { | |
802 | Ok(_) => return, // got a notification | |
803 | Err(_) => {} // spurious wakeup, go back to sleep | |
804 | } | |
85aaf69f | 805 | } |
85aaf69f SL |
806 | } |
807 | ||
7cac9316 | 808 | /// Use [`park_timeout`]. |
5bcae85e | 809 | /// |
9346a6ac | 810 | /// Blocks unless or until the current thread's token is made available or |
85aaf69f SL |
811 | /// the specified duration has been reached (may wake spuriously). |
812 | /// | |
7cac9316 XL |
813 | /// The semantics of this function are equivalent to [`park`] except |
814 | /// that the thread will be blocked for roughly no longer than `dur`. This | |
815 | /// method should not be used for precise timing due to anomalies such as | |
85aaf69f | 816 | /// preemption or platform differences that may not cause the maximum |
3157f602 | 817 | /// amount of time waited to be precisely `ms` long. |
85aaf69f | 818 | /// |
7cac9316 | 819 | /// See the [park documentation][`park`] for more detail. |
5bcae85e | 820 | /// |
7cac9316 XL |
821 | /// [`park_timeout`]: fn.park_timeout.html |
822 | /// [`park`]: ../../std/thread/fn.park.html | |
c34b1796 | 823 | #[stable(feature = "rust1", since = "1.0.0")] |
92a42be0 | 824 | #[rustc_deprecated(since = "1.6.0", reason = "replaced by `std::thread::park_timeout`")] |
c34b1796 | 825 | pub fn park_timeout_ms(ms: u32) { |
d9579d0f AL |
826 | park_timeout(Duration::from_millis(ms as u64)) |
827 | } | |
828 | ||
829 | /// Blocks unless or until the current thread's token is made available or | |
830 | /// the specified duration has been reached (may wake spuriously). | |
831 | /// | |
7cac9316 XL |
832 | /// The semantics of this function are equivalent to [`park`][park] except |
833 | /// that the thread will be blocked for roughly no longer than `dur`. This | |
834 | /// method should not be used for precise timing due to anomalies such as | |
d9579d0f | 835 | /// preemption or platform differences that may not cause the maximum |
3157f602 | 836 | /// amount of time waited to be precisely `dur` long. |
d9579d0f | 837 | /// |
3b2f2976 | 838 | /// See the [park documentation][park] for more details. |
d9579d0f AL |
839 | /// |
840 | /// # Platform behavior | |
841 | /// | |
842 | /// Platforms which do not support nanosecond precision for sleeping will have | |
843 | /// `dur` rounded up to the nearest granularity of time they can sleep for. | |
5bcae85e | 844 | /// |
3b2f2976 | 845 | /// # Examples |
5bcae85e SL |
846 | /// |
847 | /// Waiting for the complete expiration of the timeout: | |
848 | /// | |
849 | /// ```rust,no_run | |
850 | /// use std::thread::park_timeout; | |
851 | /// use std::time::{Instant, Duration}; | |
852 | /// | |
853 | /// let timeout = Duration::from_secs(2); | |
854 | /// let beginning_park = Instant::now(); | |
5bcae85e | 855 | /// |
041b39d2 XL |
856 | /// let mut timeout_remaining = timeout; |
857 | /// loop { | |
858 | /// park_timeout(timeout_remaining); | |
859 | /// let elapsed = beginning_park.elapsed(); | |
860 | /// if elapsed >= timeout { | |
861 | /// break; | |
862 | /// } | |
863 | /// println!("restarting park_timeout after {:?}", elapsed); | |
864 | /// timeout_remaining = timeout - elapsed; | |
5bcae85e SL |
865 | /// } |
866 | /// ``` | |
7cac9316 XL |
867 | /// |
868 | /// [park]: fn.park.html | |
e9174d1e | 869 | #[stable(feature = "park_timeout", since = "1.4.0")] |
d9579d0f | 870 | pub fn park_timeout(dur: Duration) { |
85aaf69f | 871 | let thread = current(); |
abe05a73 XL |
872 | |
873 | // Like `park` above we have a fast path for an already-notified thread, and | |
874 | // afterwards we start coordinating for a sleep. | |
875 | // return quickly. | |
876 | if thread.inner.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() { | |
877 | return | |
878 | } | |
879 | let m = thread.inner.lock.lock().unwrap(); | |
880 | match thread.inner.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) { | |
881 | Ok(_) => {} | |
882 | Err(NOTIFIED) => return, // notified after we locked | |
883 | Err(_) => panic!("inconsistent park_timeout state"), | |
884 | } | |
885 | ||
886 | // Wait with a timeout, and if we spuriously wake up or otherwise wake up | |
887 | // from a notification we just want to unconditionally set the state back to | |
888 | // empty, either consuming a notification or un-flagging ourselves as | |
889 | // parked. | |
890 | let (_m, _result) = thread.inner.cvar.wait_timeout(m, dur).unwrap(); | |
891 | match thread.inner.state.swap(EMPTY, SeqCst) { | |
892 | NOTIFIED => {} // got a notification, hurray! | |
893 | PARKED => {} // no notification, alas | |
894 | n => panic!("inconsistent park_timeout state: {}", n), | |
85aaf69f | 895 | } |
85aaf69f SL |
896 | } |
897 | ||
c30ab7b3 SL |
898 | //////////////////////////////////////////////////////////////////////////////// |
899 | // ThreadId | |
900 | //////////////////////////////////////////////////////////////////////////////// | |
901 | ||
902 | /// A unique identifier for a running thread. | |
903 | /// | |
904 | /// A `ThreadId` is an opaque object that has a unique value for each thread | |
cc61c64b | 905 | /// that creates one. `ThreadId`s are not guaranteed to correspond to a thread's |
3b2f2976 XL |
906 | /// system-designated identifier. A `ThreadId` can be retrieved from the [`id`] |
907 | /// method on a [`Thread`]. | |
32a655c1 SL |
908 | /// |
909 | /// # Examples | |
910 | /// | |
911 | /// ``` | |
32a655c1 SL |
912 | /// use std::thread; |
913 | /// | |
cc61c64b XL |
914 | /// let other_thread = thread::spawn(|| { |
915 | /// thread::current().id() | |
916 | /// }); | |
32a655c1 | 917 | /// |
cc61c64b XL |
918 | /// let other_thread_id = other_thread.join().unwrap(); |
919 | /// assert!(thread::current().id() != other_thread_id); | |
32a655c1 | 920 | /// ``` |
3b2f2976 XL |
921 | /// |
922 | /// [`id`]: ../../std/thread/struct.Thread.html#method.id | |
923 | /// [`Thread`]: ../../std/thread/struct.Thread.html | |
7cac9316 | 924 | #[stable(feature = "thread_id", since = "1.19.0")] |
cc61c64b | 925 | #[derive(Eq, PartialEq, Clone, Copy, Hash, Debug)] |
c30ab7b3 SL |
926 | pub struct ThreadId(u64); |
927 | ||
928 | impl ThreadId { | |
929 | // Generate a new unique thread ID. | |
930 | fn new() -> ThreadId { | |
931 | static GUARD: mutex::Mutex = mutex::Mutex::new(); | |
932 | static mut COUNTER: u64 = 0; | |
933 | ||
934 | unsafe { | |
935 | GUARD.lock(); | |
936 | ||
937 | // If we somehow use up all our bits, panic so that we're not | |
938 | // covering up subtle bugs of IDs being reused. | |
939 | if COUNTER == ::u64::MAX { | |
940 | GUARD.unlock(); | |
941 | panic!("failed to generate unique thread ID: bitspace exhausted"); | |
942 | } | |
943 | ||
944 | let id = COUNTER; | |
945 | COUNTER += 1; | |
946 | ||
947 | GUARD.unlock(); | |
948 | ||
949 | ThreadId(id) | |
950 | } | |
951 | } | |
952 | } | |
953 | ||
c34b1796 AL |
954 | //////////////////////////////////////////////////////////////////////////////// |
955 | // Thread | |
956 | //////////////////////////////////////////////////////////////////////////////// | |
957 | ||
85aaf69f | 958 | /// The internal representation of a `Thread` handle |
1a4d82fc | 959 | struct Inner { |
54a0048b | 960 | name: Option<CString>, // Guaranteed to be UTF-8 |
c30ab7b3 | 961 | id: ThreadId, |
abe05a73 XL |
962 | |
963 | // state for thread park/unpark | |
964 | state: AtomicUsize, | |
965 | lock: Mutex<()>, | |
1a4d82fc JJ |
966 | cvar: Condvar, |
967 | } | |
968 | ||
1a4d82fc | 969 | #[derive(Clone)] |
85aaf69f | 970 | #[stable(feature = "rust1", since = "1.0.0")] |
1a4d82fc | 971 | /// A handle to a thread. |
32a655c1 | 972 | /// |
7cac9316 XL |
973 | /// Threads are represented via the `Thread` type, which you can get in one of |
974 | /// two ways: | |
32a655c1 | 975 | /// |
7cac9316 XL |
976 | /// * By spawning a new thread, e.g. using the [`thread::spawn`][`spawn`] |
977 | /// function, and calling [`thread`][`JoinHandle::thread`] on the | |
978 | /// [`JoinHandle`]. | |
979 | /// * By requesting the current thread, using the [`thread::current`] function. | |
32a655c1 | 980 | /// |
7cac9316 XL |
981 | /// The [`thread::current`] function is available even for threads not spawned |
982 | /// by the APIs of this module. | |
32a655c1 | 983 | /// |
3b2f2976 | 984 | /// There is usually no need to create a `Thread` struct yourself, one |
7cac9316 XL |
985 | /// should instead use a function like `spawn` to create new threads, see the |
986 | /// docs of [`Builder`] and [`spawn`] for more details. | |
987 | /// | |
988 | /// [`Builder`]: ../../std/thread/struct.Builder.html | |
3b2f2976 XL |
989 | /// [`JoinHandle::thread`]: ../../std/thread/struct.JoinHandle.html#method.thread |
990 | /// [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html | |
991 | /// [`thread::current`]: ../../std/thread/fn.current.html | |
7cac9316 XL |
992 | /// [`spawn`]: ../../std/thread/fn.spawn.html |
993 | ||
1a4d82fc JJ |
994 | pub struct Thread { |
995 | inner: Arc<Inner>, | |
996 | } | |
997 | ||
998 | impl Thread { | |
999 | // Used only internally to construct a thread object without spawning | |
ea8adc8c | 1000 | // Panics if the name contains nuls. |
cc61c64b | 1001 | pub(crate) fn new(name: Option<String>) -> Thread { |
3157f602 XL |
1002 | let cname = name.map(|n| { |
1003 | CString::new(n).expect("thread name may not contain interior null bytes") | |
1004 | }); | |
1a4d82fc JJ |
1005 | Thread { |
1006 | inner: Arc::new(Inner { | |
54a0048b | 1007 | name: cname, |
c30ab7b3 | 1008 | id: ThreadId::new(), |
abe05a73 XL |
1009 | state: AtomicUsize::new(EMPTY), |
1010 | lock: Mutex::new(()), | |
1a4d82fc JJ |
1011 | cvar: Condvar::new(), |
1012 | }) | |
1013 | } | |
1014 | } | |
1015 | ||
1a4d82fc JJ |
1016 | /// Atomically makes the handle's token available if it is not already. |
1017 | /// | |
7cac9316 XL |
1018 | /// Every thread is equipped with some basic low-level blocking support, via |
1019 | /// the [`park`][park] function and the `unpark()` method. These can be | |
1020 | /// used as a more CPU-efficient implementation of a spinlock. | |
1021 | /// | |
1022 | /// See the [park documentation][park] for more details. | |
32a655c1 SL |
1023 | /// |
1024 | /// # Examples | |
1025 | /// | |
1026 | /// ``` | |
1027 | /// use std::thread; | |
7cac9316 | 1028 | /// use std::time::Duration; |
32a655c1 | 1029 | /// |
7cac9316 | 1030 | /// let parked_thread = thread::Builder::new() |
32a655c1 | 1031 | /// .spawn(|| { |
7cac9316 XL |
1032 | /// println!("Parking thread"); |
1033 | /// thread::park(); | |
1034 | /// println!("Thread unparked"); | |
32a655c1 SL |
1035 | /// }) |
1036 | /// .unwrap(); | |
1037 | /// | |
7cac9316 XL |
1038 | /// // Let some time pass for the thread to be spawned. |
1039 | /// thread::sleep(Duration::from_millis(10)); | |
1040 | /// | |
1041 | /// println!("Unpark the thread"); | |
1042 | /// parked_thread.thread().unpark(); | |
1043 | /// | |
1044 | /// parked_thread.join().unwrap(); | |
32a655c1 | 1045 | /// ``` |
7cac9316 XL |
1046 | /// |
1047 | /// [park]: fn.park.html | |
85aaf69f | 1048 | #[stable(feature = "rust1", since = "1.0.0")] |
1a4d82fc | 1049 | pub fn unpark(&self) { |
abe05a73 XL |
1050 | loop { |
1051 | match self.inner.state.compare_exchange(EMPTY, NOTIFIED, SeqCst, SeqCst) { | |
1052 | Ok(_) => return, // no one was waiting | |
1053 | Err(NOTIFIED) => return, // already unparked | |
1054 | Err(PARKED) => {} // gotta go wake someone up | |
1055 | _ => panic!("inconsistent state in unpark"), | |
1056 | } | |
1057 | ||
1058 | // Coordinate wakeup through the mutex and a condvar notification | |
1059 | let _lock = self.inner.lock.lock().unwrap(); | |
1060 | match self.inner.state.compare_exchange(PARKED, NOTIFIED, SeqCst, SeqCst) { | |
1061 | Ok(_) => return self.inner.cvar.notify_one(), | |
1062 | Err(NOTIFIED) => return, // a different thread unparked | |
1063 | Err(EMPTY) => {} // parked thread went away, try again | |
1064 | _ => panic!("inconsistent state in unpark"), | |
1065 | } | |
1a4d82fc JJ |
1066 | } |
1067 | } | |
1068 | ||
c30ab7b3 | 1069 | /// Gets the thread's unique identifier. |
32a655c1 SL |
1070 | /// |
1071 | /// # Examples | |
1072 | /// | |
1073 | /// ``` | |
32a655c1 SL |
1074 | /// use std::thread; |
1075 | /// | |
cc61c64b XL |
1076 | /// let other_thread = thread::spawn(|| { |
1077 | /// thread::current().id() | |
1078 | /// }); | |
32a655c1 | 1079 | /// |
cc61c64b XL |
1080 | /// let other_thread_id = other_thread.join().unwrap(); |
1081 | /// assert!(thread::current().id() != other_thread_id); | |
32a655c1 | 1082 | /// ``` |
7cac9316 | 1083 | #[stable(feature = "thread_id", since = "1.19.0")] |
c30ab7b3 SL |
1084 | pub fn id(&self) -> ThreadId { |
1085 | self.inner.id | |
1086 | } | |
1087 | ||
9346a6ac | 1088 | /// Gets the thread's name. |
3157f602 | 1089 | /// |
3b2f2976 XL |
1090 | /// For more information about named threads, see |
1091 | /// [this module-level documentation][naming-threads]. | |
1092 | /// | |
3157f602 XL |
1093 | /// # Examples |
1094 | /// | |
1095 | /// Threads by default have no name specified: | |
1096 | /// | |
1097 | /// ``` | |
1098 | /// use std::thread; | |
1099 | /// | |
1100 | /// let builder = thread::Builder::new(); | |
1101 | /// | |
1102 | /// let handler = builder.spawn(|| { | |
1103 | /// assert!(thread::current().name().is_none()); | |
1104 | /// }).unwrap(); | |
1105 | /// | |
1106 | /// handler.join().unwrap(); | |
1107 | /// ``` | |
1108 | /// | |
1109 | /// Thread with a specified name: | |
1110 | /// | |
1111 | /// ``` | |
1112 | /// use std::thread; | |
1113 | /// | |
1114 | /// let builder = thread::Builder::new() | |
1115 | /// .name("foo".into()); | |
1116 | /// | |
1117 | /// let handler = builder.spawn(|| { | |
1118 | /// assert_eq!(thread::current().name(), Some("foo")) | |
1119 | /// }).unwrap(); | |
1120 | /// | |
1121 | /// handler.join().unwrap(); | |
1122 | /// ``` | |
3b2f2976 XL |
1123 | /// |
1124 | /// [naming-threads]: ./index.html#naming-threads | |
85aaf69f | 1125 | #[stable(feature = "rust1", since = "1.0.0")] |
1a4d82fc | 1126 | pub fn name(&self) -> Option<&str> { |
54a0048b SL |
1127 | self.cname().map(|s| unsafe { str::from_utf8_unchecked(s.to_bytes()) } ) |
1128 | } | |
1129 | ||
1130 | fn cname(&self) -> Option<&CStr> { | |
85aaf69f SL |
1131 | self.inner.name.as_ref().map(|s| &**s) |
1132 | } | |
1133 | } | |
1134 | ||
1135 | #[stable(feature = "rust1", since = "1.0.0")] | |
1136 | impl fmt::Debug for Thread { | |
1137 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
1138 | fmt::Debug::fmt(&self.name(), f) | |
1a4d82fc JJ |
1139 | } |
1140 | } | |
1141 | ||
c34b1796 | 1142 | //////////////////////////////////////////////////////////////////////////////// |
e9174d1e | 1143 | // JoinHandle |
c34b1796 AL |
1144 | //////////////////////////////////////////////////////////////////////////////// |
1145 | ||
7cac9316 XL |
1146 | /// A specialized [`Result`] type for threads. |
1147 | /// | |
1a4d82fc JJ |
1148 | /// Indicates the manner in which a thread exited. |
1149 | /// | |
1150 | /// A thread that completes without panicking is considered to exit successfully. | |
7cac9316 XL |
1151 | /// |
1152 | /// # Examples | |
1153 | /// | |
1154 | /// ```no_run | |
1155 | /// use std::thread; | |
1156 | /// use std::fs; | |
1157 | /// | |
1158 | /// fn copy_in_thread() -> thread::Result<()> { | |
1159 | /// thread::spawn(move || { fs::copy("foo.txt", "bar.txt").unwrap(); }).join() | |
1160 | /// } | |
1161 | /// | |
1162 | /// fn main() { | |
1163 | /// match copy_in_thread() { | |
1164 | /// Ok(_) => println!("this is fine"), | |
1165 | /// Err(_) => println!("thread panicked"), | |
1166 | /// } | |
1167 | /// } | |
1168 | /// ``` | |
1169 | /// | |
1170 | /// [`Result`]: ../../std/result/enum.Result.html | |
85aaf69f SL |
1171 | #[stable(feature = "rust1", since = "1.0.0")] |
1172 | pub type Result<T> = ::result::Result<T, Box<Any + Send + 'static>>; | |
1a4d82fc | 1173 | |
d9579d0f AL |
1174 | // This packet is used to communicate the return value between the child thread |
1175 | // and the parent thread. Memory is shared through the `Arc` within and there's | |
1176 | // no need for a mutex here because synchronization happens with `join()` (the | |
1177 | // parent thread never reads this packet until the child has exited). | |
1178 | // | |
1179 | // This packet itself is then stored into a `JoinInner` which in turns is placed | |
1180 | // in `JoinHandle` and `JoinGuard`. Due to the usage of `UnsafeCell` we need to | |
1181 | // manually worry about impls like Send and Sync. The type `T` should | |
1182 | // already always be Send (otherwise the thread could not have been created) and | |
1183 | // this type is inherently Sync because no methods take &self. Regardless, | |
1184 | // however, we add inheriting impls for Send/Sync to this type to ensure it's | |
1185 | // Send/Sync and that future modifications will still appropriately classify it. | |
1a4d82fc JJ |
1186 | struct Packet<T>(Arc<UnsafeCell<Option<Result<T>>>>); |
1187 | ||
d9579d0f AL |
1188 | unsafe impl<T: Send> Send for Packet<T> {} |
1189 | unsafe impl<T: Sync> Sync for Packet<T> {} | |
1a4d82fc | 1190 | |
e9174d1e | 1191 | /// Inner representation for JoinHandle |
85aaf69f | 1192 | struct JoinInner<T> { |
d9579d0f | 1193 | native: Option<imp::Thread>, |
85aaf69f SL |
1194 | thread: Thread, |
1195 | packet: Packet<T>, | |
85aaf69f SL |
1196 | } |
1197 | ||
1198 | impl<T> JoinInner<T> { | |
1199 | fn join(&mut self) -> Result<T> { | |
d9579d0f | 1200 | self.native.take().unwrap().join(); |
85aaf69f SL |
1201 | unsafe { |
1202 | (*self.packet.0.get()).take().unwrap() | |
1203 | } | |
1204 | } | |
1205 | } | |
1206 | ||
1207 | /// An owned permission to join on a thread (block on its termination). | |
1208 | /// | |
7cac9316 XL |
1209 | /// A `JoinHandle` *detaches* the associated thread when it is dropped, which |
1210 | /// means that there is no longer any handle to thread and no way to `join` | |
1211 | /// on it. | |
85aaf69f | 1212 | /// |
32a655c1 | 1213 | /// Due to platform restrictions, it is not possible to [`Clone`] this |
7cac9316 | 1214 | /// handle: the ability to join a thread is a uniquely-owned permission. |
3157f602 XL |
1215 | /// |
1216 | /// This `struct` is created by the [`thread::spawn`] function and the | |
1217 | /// [`thread::Builder::spawn`] method. | |
1218 | /// | |
1219 | /// # Examples | |
1220 | /// | |
1221 | /// Creation from [`thread::spawn`]: | |
1222 | /// | |
32a655c1 | 1223 | /// ``` |
3157f602 XL |
1224 | /// use std::thread; |
1225 | /// | |
1226 | /// let join_handle: thread::JoinHandle<_> = thread::spawn(|| { | |
1227 | /// // some work here | |
1228 | /// }); | |
1229 | /// ``` | |
1230 | /// | |
1231 | /// Creation from [`thread::Builder::spawn`]: | |
1232 | /// | |
32a655c1 | 1233 | /// ``` |
3157f602 XL |
1234 | /// use std::thread; |
1235 | /// | |
1236 | /// let builder = thread::Builder::new(); | |
1237 | /// | |
1238 | /// let join_handle: thread::JoinHandle<_> = builder.spawn(|| { | |
1239 | /// // some work here | |
1240 | /// }).unwrap(); | |
1241 | /// ``` | |
1242 | /// | |
7cac9316 XL |
1243 | /// Child being detached and outliving its parent: |
1244 | /// | |
1245 | /// ```no_run | |
1246 | /// use std::thread; | |
1247 | /// use std::time::Duration; | |
1248 | /// | |
1249 | /// let original_thread = thread::spawn(|| { | |
1250 | /// let _detached_thread = thread::spawn(|| { | |
1251 | /// // Here we sleep to make sure that the first thread returns before. | |
1252 | /// thread::sleep(Duration::from_millis(10)); | |
1253 | /// // This will be called, even though the JoinHandle is dropped. | |
1254 | /// println!("♫ Still alive ♫"); | |
1255 | /// }); | |
1256 | /// }); | |
1257 | /// | |
abe05a73 | 1258 | /// original_thread.join().expect("The thread being joined has panicked"); |
7cac9316 XL |
1259 | /// println!("Original thread is joined."); |
1260 | /// | |
1261 | /// // We make sure that the new thread has time to run, before the main | |
1262 | /// // thread returns. | |
1263 | /// | |
1264 | /// thread::sleep(Duration::from_millis(1000)); | |
1265 | /// ``` | |
1266 | /// | |
32a655c1 | 1267 | /// [`Clone`]: ../../std/clone/trait.Clone.html |
3157f602 XL |
1268 | /// [`thread::spawn`]: fn.spawn.html |
1269 | /// [`thread::Builder::spawn`]: struct.Builder.html#method.spawn | |
85aaf69f | 1270 | #[stable(feature = "rust1", since = "1.0.0")] |
9346a6ac | 1271 | pub struct JoinHandle<T>(JoinInner<T>); |
85aaf69f | 1272 | |
9346a6ac | 1273 | impl<T> JoinHandle<T> { |
32a655c1 SL |
1274 | /// Extracts a handle to the underlying thread. |
1275 | /// | |
1276 | /// # Examples | |
1277 | /// | |
1278 | /// ``` | |
32a655c1 SL |
1279 | /// use std::thread; |
1280 | /// | |
1281 | /// let builder = thread::Builder::new(); | |
1282 | /// | |
1283 | /// let join_handle: thread::JoinHandle<_> = builder.spawn(|| { | |
1284 | /// // some work here | |
1285 | /// }).unwrap(); | |
1286 | /// | |
1287 | /// let thread = join_handle.thread(); | |
1288 | /// println!("thread id: {:?}", thread.id()); | |
1289 | /// ``` | |
85aaf69f SL |
1290 | #[stable(feature = "rust1", since = "1.0.0")] |
1291 | pub fn thread(&self) -> &Thread { | |
1292 | &self.0.thread | |
1293 | } | |
1294 | ||
9346a6ac | 1295 | /// Waits for the associated thread to finish. |
85aaf69f | 1296 | /// |
32a655c1 SL |
1297 | /// If the child thread panics, [`Err`] is returned with the parameter given |
1298 | /// to [`panic`]. | |
1299 | /// | |
1300 | /// [`Err`]: ../../std/result/enum.Result.html#variant.Err | |
1301 | /// [`panic`]: ../../std/macro.panic.html | |
1302 | /// | |
3b2f2976 XL |
1303 | /// # Panics |
1304 | /// | |
1305 | /// This function may panic on some platforms if a thread attempts to join | |
1306 | /// itself or otherwise may create a deadlock with joining threads. | |
1307 | /// | |
32a655c1 SL |
1308 | /// # Examples |
1309 | /// | |
1310 | /// ``` | |
1311 | /// use std::thread; | |
1312 | /// | |
1313 | /// let builder = thread::Builder::new(); | |
1314 | /// | |
1315 | /// let join_handle: thread::JoinHandle<_> = builder.spawn(|| { | |
1316 | /// // some work here | |
1317 | /// }).unwrap(); | |
1318 | /// join_handle.join().expect("Couldn't join on the associated thread"); | |
1319 | /// ``` | |
85aaf69f | 1320 | #[stable(feature = "rust1", since = "1.0.0")] |
9346a6ac | 1321 | pub fn join(mut self) -> Result<T> { |
85aaf69f SL |
1322 | self.0.join() |
1323 | } | |
1324 | } | |
1325 | ||
92a42be0 SL |
1326 | impl<T> AsInner<imp::Thread> for JoinHandle<T> { |
1327 | fn as_inner(&self) -> &imp::Thread { self.0.native.as_ref().unwrap() } | |
1328 | } | |
1329 | ||
1330 | impl<T> IntoInner<imp::Thread> for JoinHandle<T> { | |
1331 | fn into_inner(self) -> imp::Thread { self.0.native.unwrap() } | |
1332 | } | |
1333 | ||
8bb4bdeb | 1334 | #[stable(feature = "std_debug", since = "1.16.0")] |
32a655c1 SL |
1335 | impl<T> fmt::Debug for JoinHandle<T> { |
1336 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
1337 | f.pad("JoinHandle { .. }") | |
1338 | } | |
1339 | } | |
1340 | ||
d9579d0f AL |
1341 | fn _assert_sync_and_send() { |
1342 | fn _assert_both<T: Send + Sync>() {} | |
1343 | _assert_both::<JoinHandle<()>>(); | |
d9579d0f AL |
1344 | _assert_both::<Thread>(); |
1345 | } | |
1346 | ||
c34b1796 AL |
1347 | //////////////////////////////////////////////////////////////////////////////// |
1348 | // Tests | |
1349 | //////////////////////////////////////////////////////////////////////////////// | |
1350 | ||
c30ab7b3 | 1351 | #[cfg(all(test, not(target_os = "emscripten")))] |
d9579d0f | 1352 | mod tests { |
1a4d82fc JJ |
1353 | use any::Any; |
1354 | use sync::mpsc::{channel, Sender}; | |
1a4d82fc | 1355 | use result; |
c34b1796 | 1356 | use super::{Builder}; |
85aaf69f | 1357 | use thread; |
85aaf69f | 1358 | use time::Duration; |
c34b1796 | 1359 | use u32; |
1a4d82fc JJ |
1360 | |
1361 | // !!! These tests are dangerous. If something is buggy, they will hang, !!! | |
1362 | // !!! instead of exiting cleanly. This might wedge the buildbots. !!! | |
1363 | ||
1364 | #[test] | |
1365 | fn test_unnamed_thread() { | |
85aaf69f SL |
1366 | thread::spawn(move|| { |
1367 | assert!(thread::current().name().is_none()); | |
1368 | }).join().ok().unwrap(); | |
1a4d82fc JJ |
1369 | } |
1370 | ||
1371 | #[test] | |
1372 | fn test_named_thread() { | |
e9174d1e | 1373 | Builder::new().name("ada lovelace".to_string()).spawn(move|| { |
85aaf69f | 1374 | assert!(thread::current().name().unwrap() == "ada lovelace".to_string()); |
e9174d1e | 1375 | }).unwrap().join().unwrap(); |
1a4d82fc JJ |
1376 | } |
1377 | ||
54a0048b SL |
1378 | #[test] |
1379 | #[should_panic] | |
1380 | fn test_invalid_named_thread() { | |
1381 | let _ = Builder::new().name("ada l\0velace".to_string()).spawn(|| {}); | |
1382 | } | |
1383 | ||
1a4d82fc JJ |
1384 | #[test] |
1385 | fn test_run_basic() { | |
1386 | let (tx, rx) = channel(); | |
85aaf69f | 1387 | thread::spawn(move|| { |
1a4d82fc JJ |
1388 | tx.send(()).unwrap(); |
1389 | }); | |
1390 | rx.recv().unwrap(); | |
1391 | } | |
1392 | ||
1a4d82fc JJ |
1393 | #[test] |
1394 | fn test_join_panic() { | |
85aaf69f | 1395 | match thread::spawn(move|| { |
1a4d82fc JJ |
1396 | panic!() |
1397 | }).join() { | |
1398 | result::Result::Err(_) => (), | |
1399 | result::Result::Ok(()) => panic!() | |
1400 | } | |
1401 | } | |
1402 | ||
1403 | #[test] | |
1404 | fn test_spawn_sched() { | |
1a4d82fc JJ |
1405 | let (tx, rx) = channel(); |
1406 | ||
c34b1796 | 1407 | fn f(i: i32, tx: Sender<()>) { |
1a4d82fc | 1408 | let tx = tx.clone(); |
85aaf69f | 1409 | thread::spawn(move|| { |
1a4d82fc JJ |
1410 | if i == 0 { |
1411 | tx.send(()).unwrap(); | |
1412 | } else { | |
1413 | f(i - 1, tx); | |
1414 | } | |
1415 | }); | |
1416 | ||
1417 | } | |
1418 | f(10, tx); | |
1419 | rx.recv().unwrap(); | |
1420 | } | |
1421 | ||
1422 | #[test] | |
1423 | fn test_spawn_sched_childs_on_default_sched() { | |
1424 | let (tx, rx) = channel(); | |
1425 | ||
85aaf69f SL |
1426 | thread::spawn(move|| { |
1427 | thread::spawn(move|| { | |
1a4d82fc JJ |
1428 | tx.send(()).unwrap(); |
1429 | }); | |
1430 | }); | |
1431 | ||
1432 | rx.recv().unwrap(); | |
1433 | } | |
1434 | ||
e9174d1e | 1435 | fn avoid_copying_the_body<F>(spawnfn: F) where F: FnOnce(Box<Fn() + Send>) { |
c34b1796 | 1436 | let (tx, rx) = channel(); |
1a4d82fc | 1437 | |
c34b1796 AL |
1438 | let x: Box<_> = box 1; |
1439 | let x_in_parent = (&*x) as *const i32 as usize; | |
1a4d82fc | 1440 | |
c34b1796 AL |
1441 | spawnfn(Box::new(move|| { |
1442 | let x_in_child = (&*x) as *const i32 as usize; | |
1a4d82fc JJ |
1443 | tx.send(x_in_child).unwrap(); |
1444 | })); | |
1445 | ||
1446 | let x_in_child = rx.recv().unwrap(); | |
1447 | assert_eq!(x_in_parent, x_in_child); | |
1448 | } | |
1449 | ||
1450 | #[test] | |
1451 | fn test_avoid_copying_the_body_spawn() { | |
1452 | avoid_copying_the_body(|v| { | |
c34b1796 | 1453 | thread::spawn(move || v()); |
1a4d82fc JJ |
1454 | }); |
1455 | } | |
1456 | ||
1457 | #[test] | |
1458 | fn test_avoid_copying_the_body_thread_spawn() { | |
1459 | avoid_copying_the_body(|f| { | |
85aaf69f | 1460 | thread::spawn(move|| { |
c34b1796 | 1461 | f(); |
1a4d82fc JJ |
1462 | }); |
1463 | }) | |
1464 | } | |
1465 | ||
1466 | #[test] | |
1467 | fn test_avoid_copying_the_body_join() { | |
1468 | avoid_copying_the_body(|f| { | |
85aaf69f | 1469 | let _ = thread::spawn(move|| { |
c34b1796 | 1470 | f() |
1a4d82fc JJ |
1471 | }).join(); |
1472 | }) | |
1473 | } | |
1474 | ||
1475 | #[test] | |
1476 | fn test_child_doesnt_ref_parent() { | |
bd371182 AL |
1477 | // If the child refcounts the parent thread, this will stack overflow when |
1478 | // climbing the thread tree to dereference each ancestor. (See #1789) | |
1a4d82fc JJ |
1479 | // (well, it would if the constant were 8000+ - I lowered it to be more |
1480 | // valgrind-friendly. try this at home, instead..!) | |
c34b1796 | 1481 | const GENERATIONS: u32 = 16; |
e9174d1e | 1482 | fn child_no(x: u32) -> Box<Fn() + Send> { |
c34b1796 | 1483 | return Box::new(move|| { |
1a4d82fc | 1484 | if x < GENERATIONS { |
c34b1796 | 1485 | thread::spawn(move|| child_no(x+1)()); |
1a4d82fc JJ |
1486 | } |
1487 | }); | |
1488 | } | |
c34b1796 | 1489 | thread::spawn(|| child_no(0)()); |
1a4d82fc JJ |
1490 | } |
1491 | ||
1492 | #[test] | |
1493 | fn test_simple_newsched_spawn() { | |
85aaf69f | 1494 | thread::spawn(move || {}); |
1a4d82fc JJ |
1495 | } |
1496 | ||
1497 | #[test] | |
1498 | fn test_try_panic_message_static_str() { | |
85aaf69f | 1499 | match thread::spawn(move|| { |
1a4d82fc JJ |
1500 | panic!("static string"); |
1501 | }).join() { | |
1502 | Err(e) => { | |
1503 | type T = &'static str; | |
1504 | assert!(e.is::<T>()); | |
c34b1796 | 1505 | assert_eq!(*e.downcast::<T>().unwrap(), "static string"); |
1a4d82fc JJ |
1506 | } |
1507 | Ok(()) => panic!() | |
1508 | } | |
1509 | } | |
1510 | ||
1511 | #[test] | |
1512 | fn test_try_panic_message_owned_str() { | |
85aaf69f | 1513 | match thread::spawn(move|| { |
1a4d82fc JJ |
1514 | panic!("owned string".to_string()); |
1515 | }).join() { | |
1516 | Err(e) => { | |
1517 | type T = String; | |
1518 | assert!(e.is::<T>()); | |
c34b1796 | 1519 | assert_eq!(*e.downcast::<T>().unwrap(), "owned string".to_string()); |
1a4d82fc JJ |
1520 | } |
1521 | Ok(()) => panic!() | |
1522 | } | |
1523 | } | |
1524 | ||
1525 | #[test] | |
1526 | fn test_try_panic_message_any() { | |
85aaf69f | 1527 | match thread::spawn(move|| { |
1a4d82fc JJ |
1528 | panic!(box 413u16 as Box<Any + Send>); |
1529 | }).join() { | |
1530 | Err(e) => { | |
1531 | type T = Box<Any + Send>; | |
1532 | assert!(e.is::<T>()); | |
c34b1796 | 1533 | let any = e.downcast::<T>().unwrap(); |
1a4d82fc | 1534 | assert!(any.is::<u16>()); |
c34b1796 | 1535 | assert_eq!(*any.downcast::<u16>().unwrap(), 413); |
1a4d82fc JJ |
1536 | } |
1537 | Ok(()) => panic!() | |
1538 | } | |
1539 | } | |
1540 | ||
1541 | #[test] | |
1542 | fn test_try_panic_message_unit_struct() { | |
1543 | struct Juju; | |
1544 | ||
85aaf69f | 1545 | match thread::spawn(move|| { |
1a4d82fc JJ |
1546 | panic!(Juju) |
1547 | }).join() { | |
1548 | Err(ref e) if e.is::<Juju>() => {} | |
1549 | Err(_) | Ok(()) => panic!() | |
1550 | } | |
1551 | } | |
1552 | ||
85aaf69f SL |
1553 | #[test] |
1554 | fn test_park_timeout_unpark_before() { | |
1555 | for _ in 0..10 { | |
1556 | thread::current().unpark(); | |
9cc50fc6 | 1557 | thread::park_timeout(Duration::from_millis(u32::MAX as u64)); |
85aaf69f SL |
1558 | } |
1559 | } | |
1560 | ||
1561 | #[test] | |
1562 | fn test_park_timeout_unpark_not_called() { | |
1563 | for _ in 0..10 { | |
9cc50fc6 | 1564 | thread::park_timeout(Duration::from_millis(10)); |
85aaf69f SL |
1565 | } |
1566 | } | |
1567 | ||
1568 | #[test] | |
1569 | fn test_park_timeout_unpark_called_other_thread() { | |
85aaf69f SL |
1570 | for _ in 0..10 { |
1571 | let th = thread::current(); | |
1572 | ||
1573 | let _guard = thread::spawn(move || { | |
9cc50fc6 | 1574 | super::sleep(Duration::from_millis(50)); |
85aaf69f SL |
1575 | th.unpark(); |
1576 | }); | |
1577 | ||
9cc50fc6 | 1578 | thread::park_timeout(Duration::from_millis(u32::MAX as u64)); |
85aaf69f SL |
1579 | } |
1580 | } | |
1581 | ||
c34b1796 AL |
1582 | #[test] |
1583 | fn sleep_ms_smoke() { | |
9cc50fc6 | 1584 | thread::sleep(Duration::from_millis(2)); |
c34b1796 AL |
1585 | } |
1586 | ||
c30ab7b3 SL |
1587 | #[test] |
1588 | fn test_thread_id_equal() { | |
1589 | assert!(thread::current().id() == thread::current().id()); | |
1590 | } | |
1591 | ||
1592 | #[test] | |
1593 | fn test_thread_id_not_equal() { | |
1594 | let spawned_id = thread::spawn(|| thread::current().id()).join().unwrap(); | |
1595 | assert!(thread::current().id() != spawned_id); | |
1596 | } | |
1597 | ||
bd371182 | 1598 | // NOTE: the corresponding test for stderr is in run-pass/thread-stderr, due |
1a4d82fc JJ |
1599 | // to the test harness apparently interfering with stderr configuration. |
1600 | } |