]>
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 | |
28 | //! owned resources. Thread panic is unrecoverable from within | |
29 | //! the panicking thread (i.e. there is no 'try/catch' in Rust), but | |
c34b1796 AL |
30 | //! the panic may optionally be detected from a different thread. If |
31 | //! the main thread panics, the application will exit with a non-zero | |
1a4d82fc JJ |
32 | //! exit code. |
33 | //! | |
34 | //! When the main thread of a Rust program terminates, the entire program shuts | |
35 | //! down, even if other threads are still running. However, this module provides | |
36 | //! convenient facilities for automatically waiting for the termination of a | |
c34b1796 | 37 | //! child thread (i.e., join). |
1a4d82fc | 38 | //! |
1a4d82fc JJ |
39 | //! ## Spawning a thread |
40 | //! | |
476ff2be | 41 | //! A new thread can be spawned using the [`thread::spawn`][`spawn`] function: |
1a4d82fc JJ |
42 | //! |
43 | //! ```rust | |
85aaf69f | 44 | //! use std::thread; |
1a4d82fc | 45 | //! |
85aaf69f | 46 | //! thread::spawn(move || { |
c34b1796 | 47 | //! // some work here |
1a4d82fc JJ |
48 | //! }); |
49 | //! ``` | |
50 | //! | |
85aaf69f | 51 | //! In this example, the spawned thread is "detached" from the current |
c34b1796 AL |
52 | //! thread. This means that it can outlive its parent (the thread that spawned |
53 | //! it), unless this parent is the main thread. | |
1a4d82fc | 54 | //! |
9346a6ac | 55 | //! The parent thread can also wait on the completion of the child |
476ff2be | 56 | //! thread; a call to [`spawn`] produces a [`JoinHandle`], which provides |
9346a6ac AL |
57 | //! a `join` method for waiting: |
58 | //! | |
59 | //! ```rust | |
60 | //! use std::thread; | |
61 | //! | |
62 | //! let child = thread::spawn(move || { | |
63 | //! // some work here | |
64 | //! }); | |
65 | //! // some work here | |
66 | //! let res = child.join(); | |
67 | //! ``` | |
68 | //! | |
476ff2be SL |
69 | //! The [`join`] method returns a [`Result`] containing [`Ok`] of the final |
70 | //! value produced by the child thread, or [`Err`] of the value given to | |
71 | //! a call to [`panic!`] if the child panicked. | |
9346a6ac | 72 | //! |
1a4d82fc JJ |
73 | //! ## Configuring threads |
74 | //! | |
476ff2be | 75 | //! A new thread can be configured before it is spawned via the [`Builder`] type, |
bd371182 | 76 | //! which currently allows you to set the name and stack size for the child thread: |
1a4d82fc JJ |
77 | //! |
78 | //! ```rust | |
9346a6ac | 79 | //! # #![allow(unused_must_use)] |
1a4d82fc JJ |
80 | //! use std::thread; |
81 | //! | |
82 | //! thread::Builder::new().name("child1".to_string()).spawn(move || { | |
c34b1796 | 83 | //! println!("Hello, world!"); |
1a4d82fc JJ |
84 | //! }); |
85 | //! ``` | |
86 | //! | |
a7813a04 XL |
87 | //! ## The `Thread` type |
88 | //! | |
476ff2be | 89 | //! Threads are represented via the [`Thread`] type, which you can get in one of |
a7813a04 XL |
90 | //! two ways: |
91 | //! | |
476ff2be SL |
92 | //! * By spawning a new thread, e.g. using the [`thread::spawn`][`spawn`] |
93 | //! function, and calling [`thread()`] on the [`JoinHandle`]. | |
94 | //! * By requesting the current thread, using the [`thread::current()`] function. | |
a7813a04 | 95 | //! |
476ff2be | 96 | //! The [`thread::current()`] function is available even for threads not spawned |
a7813a04 XL |
97 | //! by the APIs of this module. |
98 | //! | |
1a4d82fc JJ |
99 | //! ## Blocking support: park and unpark |
100 | //! | |
101 | //! Every thread is equipped with some basic low-level blocking support, via the | |
476ff2be SL |
102 | //! [`thread::park()`][`park()`] function and [`thread::Thread::unpark()`][`unpark()`] |
103 | //! method. [`park()`] blocks the current thread, which can then be resumed from | |
104 | //! another thread by calling the [`unpark()`] method on the blocked thread's handle. | |
1a4d82fc | 105 | //! |
476ff2be | 106 | //! Conceptually, each [`Thread`] handle has an associated token, which is |
1a4d82fc JJ |
107 | //! initially not present: |
108 | //! | |
476ff2be | 109 | //! * The [`thread::park()`][`park()`] function blocks the current thread unless or until |
c34b1796 | 110 | //! the token is available for its thread handle, at which point it atomically |
1a4d82fc | 111 | //! consumes the token. It may also return *spuriously*, without consuming the |
476ff2be | 112 | //! token. [`thread::park_timeout()`] does the same, but allows specifying a |
85aaf69f | 113 | //! maximum time to block the thread for. |
1a4d82fc | 114 | //! |
476ff2be | 115 | //! * The [`unpark()`] method on a [`Thread`] atomically makes the token available |
1a4d82fc JJ |
116 | //! if it wasn't already. |
117 | //! | |
476ff2be | 118 | //! In other words, each [`Thread`] acts a bit like a semaphore with initial count |
1a4d82fc JJ |
119 | //! 0, except that the semaphore is *saturating* (the count cannot go above 1), |
120 | //! and can return spuriously. | |
121 | //! | |
122 | //! The API is typically used by acquiring a handle to the current thread, | |
123 | //! placing that handle in a shared data structure so that other threads can | |
124 | //! find it, and then `park`ing. When some desired condition is met, another | |
476ff2be | 125 | //! thread calls [`unpark()`] on the handle. |
1a4d82fc JJ |
126 | //! |
127 | //! The motivation for this design is twofold: | |
128 | //! | |
129 | //! * It avoids the need to allocate mutexes and condvars when building new | |
130 | //! synchronization primitives; the threads already provide basic blocking/signaling. | |
131 | //! | |
c34b1796 AL |
132 | //! * It can be implemented very efficiently on many platforms. |
133 | //! | |
134 | //! ## Thread-local storage | |
135 | //! | |
9e0c209e SL |
136 | //! This module also provides an implementation of thread-local storage for Rust |
137 | //! programs. Thread-local storage is a method of storing data into a global | |
138 | //! variable that each thread in the program will have its own copy of. | |
c34b1796 AL |
139 | //! Threads do not share this data, so accesses do not need to be synchronized. |
140 | //! | |
9e0c209e SL |
141 | //! A thread-local key owns the value it contains and will destroy the value when the |
142 | //! thread exits. It is created with the [`thread_local!`] macro and can contain any | |
143 | //! value that is `'static` (no borrowed pointers). It provides an accessor function, | |
144 | //! [`with`], that yields a shared reference to the value to the specified | |
145 | //! closure. Thread-local keys allow only shared access to values, as there would be no | |
146 | //! way to guarantee uniqueness if mutable borrows were allowed. Most values | |
c34b1796 | 147 | //! will want to make use of some form of **interior mutability** through the |
9e0c209e SL |
148 | //! [`Cell`] or [`RefCell`] types. |
149 | //! | |
476ff2be SL |
150 | //! [channels]: ../../std/sync/mpsc/index.html |
151 | //! [`Arc`]: ../../std/sync/struct.Arc.html | |
152 | //! [`spawn`]: ../../std/thread/fn.spawn.html | |
153 | //! [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html | |
154 | //! [`thread()`]: ../../std/thread/struct.JoinHandle.html#method.thread | |
155 | //! [`join`]: ../../std/thread/struct.JoinHandle.html#method.join | |
156 | //! [`Result`]: ../../std/result/enum.Result.html | |
157 | //! [`Ok`]: ../../std/result/enum.Result.html#variant.Ok | |
158 | //! [`Err`]: ../../std/result/enum.Result.html#variant.Err | |
159 | //! [`panic!`]: ../../std/macro.panic.html | |
160 | //! [`Builder`]: ../../std/thread/struct.Builder.html | |
161 | //! [`thread::current()`]: ../../std/thread/fn.spawn.html | |
162 | //! [`Thread`]: ../../std/thread/struct.Thread.html | |
163 | //! [`park()`]: ../../std/thread/fn.park.html | |
164 | //! [`unpark()`]: ../../std/thread/struct.Thread.html#method.unpark | |
165 | //! [`thread::park_timeout()`]: ../../std/thread/fn.park_timeout.html | |
9e0c209e SL |
166 | //! [`Cell`]: ../cell/struct.Cell.html |
167 | //! [`RefCell`]: ../cell/struct.RefCell.html | |
c30ab7b3 | 168 | //! [`thread_local!`]: ../macro.thread_local.html |
9e0c209e | 169 | //! [`with`]: struct.LocalKey.html#method.with |
1a4d82fc | 170 | |
85aaf69f SL |
171 | #![stable(feature = "rust1", since = "1.0.0")] |
172 | ||
1a4d82fc | 173 | use any::Any; |
1a4d82fc | 174 | use cell::UnsafeCell; |
a7813a04 | 175 | use ffi::{CStr, CString}; |
85aaf69f SL |
176 | use fmt; |
177 | use io; | |
a7813a04 XL |
178 | use panic; |
179 | use panicking; | |
54a0048b | 180 | use str; |
85aaf69f | 181 | use sync::{Mutex, Condvar, Arc}; |
c34b1796 | 182 | use sys::thread as imp; |
c30ab7b3 | 183 | use sys_common::mutex; |
e9174d1e | 184 | use sys_common::thread_info; |
e9174d1e | 185 | use sys_common::util; |
92a42be0 | 186 | use sys_common::{AsInner, IntoInner}; |
85aaf69f | 187 | use time::Duration; |
1a4d82fc | 188 | |
c34b1796 AL |
189 | //////////////////////////////////////////////////////////////////////////////// |
190 | // Thread-local storage | |
191 | //////////////////////////////////////////////////////////////////////////////// | |
192 | ||
9346a6ac | 193 | #[macro_use] mod local; |
9346a6ac AL |
194 | |
195 | #[stable(feature = "rust1", since = "1.0.0")] | |
196 | pub use self::local::{LocalKey, LocalKeyState}; | |
197 | ||
c30ab7b3 SL |
198 | // The types used by the thread_local! macro to access TLS keys. Note that there |
199 | // are two types, the "OS" type and the "fast" type. The OS thread local key | |
200 | // type is accessed via platform-specific API calls and is slow, while the fast | |
201 | // key type is accessed via code generated via LLVM, where TLS keys are set up | |
202 | // by the elf linker. Note that the OS TLS type is always available: on macOS | |
203 | // the standard library is compiled with support for older platform versions | |
204 | // where fast TLS was not available; end-user code is compiled with fast TLS | |
205 | // where available, but both are needed. | |
206 | ||
92a42be0 | 207 | #[unstable(feature = "libstd_thread_internals", issue = "0")] |
9cc50fc6 | 208 | #[cfg(target_thread_local)] |
c30ab7b3 | 209 | #[doc(hidden)] pub use sys::fast_thread_local::Key as __FastLocalKeyInner; |
9cc50fc6 SL |
210 | #[unstable(feature = "libstd_thread_internals", issue = "0")] |
211 | #[doc(hidden)] pub use self::local::os::Key as __OsLocalKeyInner; | |
c34b1796 AL |
212 | |
213 | //////////////////////////////////////////////////////////////////////////////// | |
214 | // Builder | |
215 | //////////////////////////////////////////////////////////////////////////////// | |
1a4d82fc JJ |
216 | |
217 | /// Thread configuration. Provides detailed control over the properties | |
218 | /// and behavior of new threads. | |
32a655c1 SL |
219 | /// |
220 | /// # Examples | |
221 | /// | |
222 | /// ``` | |
223 | /// use std::thread; | |
224 | /// | |
225 | /// let builder = thread::Builder::new(); | |
226 | /// | |
227 | /// let handler = builder.spawn(|| { | |
228 | /// // thread code | |
229 | /// }).unwrap(); | |
230 | /// | |
231 | /// handler.join().unwrap(); | |
232 | /// ``` | |
85aaf69f | 233 | #[stable(feature = "rust1", since = "1.0.0")] |
32a655c1 | 234 | #[derive(Debug)] |
1a4d82fc JJ |
235 | pub struct Builder { |
236 | // A name for the thread-to-be, for identification in panic messages | |
237 | name: Option<String>, | |
8bb4bdeb | 238 | // The size of the stack for the spawned thread in bytes |
c34b1796 | 239 | stack_size: Option<usize>, |
1a4d82fc JJ |
240 | } |
241 | ||
242 | impl Builder { | |
9346a6ac | 243 | /// Generates the base configuration for spawning a thread, from which |
1a4d82fc | 244 | /// configuration methods can be chained. |
32a655c1 SL |
245 | /// |
246 | /// # Examples | |
247 | /// | |
248 | /// ``` | |
249 | /// use std::thread; | |
250 | /// | |
251 | /// let builder = thread::Builder::new() | |
252 | /// .name("foo".into()) | |
253 | /// .stack_size(10); | |
254 | /// | |
255 | /// let handler = builder.spawn(|| { | |
256 | /// // thread code | |
257 | /// }).unwrap(); | |
258 | /// | |
259 | /// handler.join().unwrap(); | |
260 | /// ``` | |
85aaf69f | 261 | #[stable(feature = "rust1", since = "1.0.0")] |
1a4d82fc JJ |
262 | pub fn new() -> Builder { |
263 | Builder { | |
264 | name: None, | |
265 | stack_size: None, | |
1a4d82fc JJ |
266 | } |
267 | } | |
268 | ||
9346a6ac | 269 | /// Names the thread-to-be. Currently the name is used for identification |
1a4d82fc | 270 | /// only in panic messages. |
3157f602 XL |
271 | /// |
272 | /// # Examples | |
273 | /// | |
32a655c1 | 274 | /// ``` |
3157f602 XL |
275 | /// use std::thread; |
276 | /// | |
277 | /// let builder = thread::Builder::new() | |
278 | /// .name("foo".into()); | |
279 | /// | |
280 | /// let handler = builder.spawn(|| { | |
281 | /// assert_eq!(thread::current().name(), Some("foo")) | |
282 | /// }).unwrap(); | |
283 | /// | |
284 | /// handler.join().unwrap(); | |
285 | /// ``` | |
85aaf69f | 286 | #[stable(feature = "rust1", since = "1.0.0")] |
1a4d82fc JJ |
287 | pub fn name(mut self, name: String) -> Builder { |
288 | self.name = Some(name); | |
289 | self | |
290 | } | |
291 | ||
8bb4bdeb XL |
292 | /// Sets the size of the stack (in bytes) for the new thread. |
293 | /// | |
294 | /// The actual stack size may be greater than this value if | |
295 | /// the platform specifies minimal stack size. | |
32a655c1 SL |
296 | /// |
297 | /// # Examples | |
298 | /// | |
299 | /// ``` | |
300 | /// use std::thread; | |
301 | /// | |
8bb4bdeb | 302 | /// let builder = thread::Builder::new().stack_size(32 * 1024); |
32a655c1 | 303 | /// ``` |
85aaf69f | 304 | #[stable(feature = "rust1", since = "1.0.0")] |
c34b1796 | 305 | pub fn stack_size(mut self, size: usize) -> Builder { |
1a4d82fc JJ |
306 | self.stack_size = Some(size); |
307 | self | |
308 | } | |
309 | ||
9346a6ac | 310 | /// Spawns a new thread, and returns a join handle for it. |
1a4d82fc | 311 | /// |
85aaf69f SL |
312 | /// The child thread may outlive the parent (unless the parent thread |
313 | /// is the main thread; the whole process is terminated when the main | |
bd371182 | 314 | /// thread finishes). The join handle can be used to block on |
85aaf69f SL |
315 | /// termination of the child thread, including recovering its panics. |
316 | /// | |
317 | /// # Errors | |
318 | /// | |
32a655c1 SL |
319 | /// Unlike the [`spawn`] free function, this method yields an |
320 | /// [`io::Result`] to capture any failure to create the thread at | |
85aaf69f | 321 | /// the OS level. |
32a655c1 SL |
322 | /// |
323 | /// [`spawn`]: ../../std/thread/fn.spawn.html | |
324 | /// [`io::Result`]: ../../std/io/type.Result.html | |
325 | /// | |
326 | /// # Examples | |
327 | /// | |
328 | /// ``` | |
329 | /// use std::thread; | |
330 | /// | |
331 | /// let builder = thread::Builder::new(); | |
332 | /// | |
333 | /// let handler = builder.spawn(|| { | |
334 | /// // thread code | |
335 | /// }).unwrap(); | |
336 | /// | |
337 | /// handler.join().unwrap(); | |
338 | /// ``` | |
85aaf69f | 339 | #[stable(feature = "rust1", since = "1.0.0")] |
9346a6ac AL |
340 | pub fn spawn<F, T>(self, f: F) -> io::Result<JoinHandle<T>> where |
341 | F: FnOnce() -> T, F: Send + 'static, T: Send + 'static | |
85aaf69f | 342 | { |
c34b1796 | 343 | let Builder { name, stack_size } = self; |
1a4d82fc | 344 | |
e9174d1e | 345 | let stack_size = stack_size.unwrap_or(util::min_stack()); |
85aaf69f | 346 | |
1a4d82fc JJ |
347 | let my_thread = Thread::new(name); |
348 | let their_thread = my_thread.clone(); | |
349 | ||
b039eaaf SL |
350 | let my_packet : Arc<UnsafeCell<Option<Result<T>>>> |
351 | = Arc::new(UnsafeCell::new(None)); | |
d9579d0f | 352 | let their_packet = my_packet.clone(); |
85aaf69f | 353 | |
85aaf69f | 354 | let main = move || { |
54a0048b | 355 | if let Some(name) = their_thread.cname() { |
d9579d0f | 356 | imp::Thread::set_name(name); |
85aaf69f | 357 | } |
b039eaaf SL |
358 | unsafe { |
359 | thread_info::set(imp::guard::current(), their_thread); | |
a7813a04 XL |
360 | let try_result = panic::catch_unwind(panic::AssertUnwindSafe(f)); |
361 | *their_packet.get() = Some(try_result); | |
b039eaaf | 362 | } |
1a4d82fc JJ |
363 | }; |
364 | ||
b039eaaf SL |
365 | Ok(JoinHandle(JoinInner { |
366 | native: unsafe { | |
54a0048b | 367 | Some(imp::Thread::new(stack_size, Box::new(main))?) |
b039eaaf | 368 | }, |
85aaf69f | 369 | thread: my_thread, |
d9579d0f | 370 | packet: Packet(my_packet), |
b039eaaf | 371 | })) |
1a4d82fc JJ |
372 | } |
373 | } | |
374 | ||
c34b1796 AL |
375 | //////////////////////////////////////////////////////////////////////////////// |
376 | // Free functions | |
377 | //////////////////////////////////////////////////////////////////////////////// | |
378 | ||
32a655c1 | 379 | /// Spawns a new thread, returning a [`JoinHandle`] for it. |
85aaf69f | 380 | /// |
c34b1796 AL |
381 | /// The join handle will implicitly *detach* the child thread upon being |
382 | /// dropped. In this case, the child thread may outlive the parent (unless | |
383 | /// the parent thread is the main thread; the whole process is terminated when | |
32a655c1 | 384 | /// the main thread finishes). Additionally, the join handle provides a [`join`] |
c34b1796 | 385 | /// method that can be used to join the child thread. If the child thread |
32a655c1 SL |
386 | /// panics, [`join`] will return an [`Err`] containing the argument given to |
387 | /// [`panic`]. | |
85aaf69f SL |
388 | /// |
389 | /// # Panics | |
390 | /// | |
32a655c1 | 391 | /// Panics if the OS fails to create a thread; use [`Builder::spawn`] |
85aaf69f | 392 | /// to recover from such errors. |
32a655c1 SL |
393 | /// |
394 | /// [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html | |
395 | /// [`join`]: ../../std/thread/struct.JoinHandle.html#method.join | |
396 | /// [`Err`]: ../../std/result/enum.Result.html#variant.Err | |
397 | /// [`panic`]: ../../std/macro.panic.html | |
398 | /// [`Builder::spawn`]: ../../std/thread/struct.Builder.html#method.spawn | |
399 | /// | |
400 | /// # Examples | |
401 | /// | |
402 | /// ``` | |
403 | /// use std::thread; | |
404 | /// | |
405 | /// let handler = thread::spawn(|| { | |
406 | /// // thread code | |
407 | /// }); | |
408 | /// | |
409 | /// handler.join().unwrap(); | |
410 | /// ``` | |
85aaf69f | 411 | #[stable(feature = "rust1", since = "1.0.0")] |
9346a6ac AL |
412 | pub fn spawn<F, T>(f: F) -> JoinHandle<T> where |
413 | F: FnOnce() -> T, F: Send + 'static, T: Send + 'static | |
414 | { | |
85aaf69f SL |
415 | Builder::new().spawn(f).unwrap() |
416 | } | |
417 | ||
85aaf69f | 418 | /// Gets a handle to the thread that invokes it. |
9e0c209e | 419 | /// |
32a655c1 | 420 | /// # Examples |
9e0c209e SL |
421 | /// |
422 | /// Getting a handle to the current thread with `thread::current()`: | |
423 | /// | |
424 | /// ``` | |
425 | /// use std::thread; | |
426 | /// | |
427 | /// let handler = thread::Builder::new() | |
428 | /// .name("named thread".into()) | |
429 | /// .spawn(|| { | |
430 | /// let handle = thread::current(); | |
431 | /// assert_eq!(handle.name(), Some("named thread")); | |
432 | /// }) | |
433 | /// .unwrap(); | |
434 | /// | |
435 | /// handler.join().unwrap(); | |
436 | /// ``` | |
85aaf69f SL |
437 | #[stable(feature = "rust1", since = "1.0.0")] |
438 | pub fn current() -> Thread { | |
d9579d0f AL |
439 | thread_info::current_thread().expect("use of std::thread::current() is not \ |
440 | possible after the thread's local \ | |
441 | data has been destroyed") | |
85aaf69f SL |
442 | } |
443 | ||
9346a6ac | 444 | /// Cooperatively gives up a timeslice to the OS scheduler. |
32a655c1 SL |
445 | /// |
446 | /// # Examples | |
447 | /// | |
448 | /// ``` | |
449 | /// use std::thread; | |
450 | /// | |
451 | /// thread::yield_now(); | |
452 | /// ``` | |
85aaf69f SL |
453 | #[stable(feature = "rust1", since = "1.0.0")] |
454 | pub fn yield_now() { | |
d9579d0f | 455 | imp::Thread::yield_now() |
85aaf69f SL |
456 | } |
457 | ||
458 | /// Determines whether the current thread is unwinding because of panic. | |
3157f602 XL |
459 | /// |
460 | /// # Examples | |
461 | /// | |
32a655c1 | 462 | /// ```should_panic |
3157f602 XL |
463 | /// use std::thread; |
464 | /// | |
465 | /// struct SomeStruct; | |
466 | /// | |
467 | /// impl Drop for SomeStruct { | |
468 | /// fn drop(&mut self) { | |
469 | /// if thread::panicking() { | |
470 | /// println!("dropped while unwinding"); | |
471 | /// } else { | |
472 | /// println!("dropped while not unwinding"); | |
473 | /// } | |
474 | /// } | |
475 | /// } | |
476 | /// | |
477 | /// { | |
478 | /// print!("a: "); | |
479 | /// let a = SomeStruct; | |
480 | /// } | |
481 | /// | |
482 | /// { | |
483 | /// print!("b: "); | |
484 | /// let b = SomeStruct; | |
485 | /// panic!() | |
486 | /// } | |
487 | /// ``` | |
85aaf69f SL |
488 | #[inline] |
489 | #[stable(feature = "rust1", since = "1.0.0")] | |
490 | pub fn panicking() -> bool { | |
a7813a04 | 491 | panicking::panicking() |
85aaf69f SL |
492 | } |
493 | ||
9346a6ac | 494 | /// Puts the current thread to sleep for the specified amount of time. |
c34b1796 AL |
495 | /// |
496 | /// The thread may sleep longer than the duration specified due to scheduling | |
32a655c1 SL |
497 | /// specifics or platform-dependent functionality. |
498 | /// | |
499 | /// # Platform behavior | |
500 | /// | |
501 | /// On Unix platforms this function will not return early due to a | |
502 | /// signal being received or a spurious wakeup. | |
503 | /// | |
504 | /// # Examples | |
505 | /// | |
506 | /// ```no_run | |
507 | /// use std::thread; | |
508 | /// | |
509 | /// // Let's sleep for 2 seconds: | |
510 | /// thread::sleep_ms(2000); | |
511 | /// ``` | |
c34b1796 | 512 | #[stable(feature = "rust1", since = "1.0.0")] |
92a42be0 | 513 | #[rustc_deprecated(since = "1.6.0", reason = "replaced by `std::thread::sleep`")] |
c34b1796 | 514 | pub fn sleep_ms(ms: u32) { |
d9579d0f AL |
515 | sleep(Duration::from_millis(ms as u64)) |
516 | } | |
517 | ||
518 | /// Puts the current thread to sleep for the specified amount of time. | |
519 | /// | |
520 | /// The thread may sleep longer than the duration specified due to scheduling | |
521 | /// specifics or platform-dependent functionality. | |
522 | /// | |
523 | /// # Platform behavior | |
524 | /// | |
525 | /// On Unix platforms this function will not return early due to a | |
526 | /// signal being received or a spurious wakeup. Platforms which do not support | |
527 | /// nanosecond precision for sleeping will have `dur` rounded up to the nearest | |
528 | /// granularity of time they can sleep for. | |
3157f602 XL |
529 | /// |
530 | /// # Examples | |
531 | /// | |
32a655c1 | 532 | /// ```no_run |
3157f602 XL |
533 | /// use std::{thread, time}; |
534 | /// | |
535 | /// let ten_millis = time::Duration::from_millis(10); | |
536 | /// let now = time::Instant::now(); | |
537 | /// | |
538 | /// thread::sleep(ten_millis); | |
539 | /// | |
540 | /// assert!(now.elapsed() >= ten_millis); | |
541 | /// ``` | |
e9174d1e | 542 | #[stable(feature = "thread_sleep", since = "1.4.0")] |
d9579d0f AL |
543 | pub fn sleep(dur: Duration) { |
544 | imp::Thread::sleep(dur) | |
c34b1796 AL |
545 | } |
546 | ||
c1a9b12d SL |
547 | /// Blocks unless or until the current thread's token is made available. |
548 | /// | |
549 | /// Every thread is equipped with some basic low-level blocking support, via | |
550 | /// the `park()` function and the [`unpark()`][unpark] method. These can be | |
551 | /// used as a more CPU-efficient implementation of a spinlock. | |
552 | /// | |
553 | /// [unpark]: struct.Thread.html#method.unpark | |
554 | /// | |
555 | /// The API is typically used by acquiring a handle to the current thread, | |
556 | /// placing that handle in a shared data structure so that other threads can | |
557 | /// find it, and then parking (in a loop with a check for the token actually | |
558 | /// being acquired). | |
559 | /// | |
560 | /// A call to `park` does not guarantee that the thread will remain parked | |
561 | /// forever, and callers should be prepared for this possibility. | |
562 | /// | |
563 | /// See the [module documentation][thread] for more detail. | |
85aaf69f | 564 | /// |
c1a9b12d | 565 | /// [thread]: index.html |
85aaf69f SL |
566 | // |
567 | // The implementation currently uses the trivial strategy of a Mutex+Condvar | |
568 | // with wakeup flag, which does not actually allow spurious wakeups. In the | |
569 | // future, this will be implemented in a more efficient way, perhaps along the lines of | |
570 | // http://cr.openjdk.java.net/~stefank/6989984.1/raw_files/new/src/os/linux/vm/os_linux.cpp | |
571 | // or futuxes, and in either case may allow spurious wakeups. | |
572 | #[stable(feature = "rust1", since = "1.0.0")] | |
573 | pub fn park() { | |
574 | let thread = current(); | |
575 | let mut guard = thread.inner.lock.lock().unwrap(); | |
576 | while !*guard { | |
577 | guard = thread.inner.cvar.wait(guard).unwrap(); | |
578 | } | |
579 | *guard = false; | |
580 | } | |
581 | ||
5bcae85e SL |
582 | /// Use [park_timeout]. |
583 | /// | |
9346a6ac | 584 | /// Blocks unless or until the current thread's token is made available or |
85aaf69f SL |
585 | /// the specified duration has been reached (may wake spuriously). |
586 | /// | |
587 | /// The semantics of this function are equivalent to `park()` except that the | |
3157f602 | 588 | /// thread will be blocked for roughly no longer than `ms`. This method |
85aaf69f SL |
589 | /// should not be used for precise timing due to anomalies such as |
590 | /// preemption or platform differences that may not cause the maximum | |
3157f602 | 591 | /// amount of time waited to be precisely `ms` long. |
85aaf69f | 592 | /// |
5bcae85e SL |
593 | /// See the [module documentation][thread] for more detail. |
594 | /// | |
595 | /// [thread]: index.html | |
596 | /// [park_timeout]: fn.park_timeout.html | |
c34b1796 | 597 | #[stable(feature = "rust1", since = "1.0.0")] |
92a42be0 | 598 | #[rustc_deprecated(since = "1.6.0", reason = "replaced by `std::thread::park_timeout`")] |
c34b1796 | 599 | pub fn park_timeout_ms(ms: u32) { |
d9579d0f AL |
600 | park_timeout(Duration::from_millis(ms as u64)) |
601 | } | |
602 | ||
603 | /// Blocks unless or until the current thread's token is made available or | |
604 | /// the specified duration has been reached (may wake spuriously). | |
605 | /// | |
606 | /// The semantics of this function are equivalent to `park()` except that the | |
3157f602 | 607 | /// thread will be blocked for roughly no longer than `dur`. This method |
d9579d0f AL |
608 | /// should not be used for precise timing due to anomalies such as |
609 | /// preemption or platform differences that may not cause the maximum | |
3157f602 | 610 | /// amount of time waited to be precisely `dur` long. |
d9579d0f AL |
611 | /// |
612 | /// See the module doc for more detail. | |
613 | /// | |
614 | /// # Platform behavior | |
615 | /// | |
616 | /// Platforms which do not support nanosecond precision for sleeping will have | |
617 | /// `dur` rounded up to the nearest granularity of time they can sleep for. | |
5bcae85e SL |
618 | /// |
619 | /// # Example | |
620 | /// | |
621 | /// Waiting for the complete expiration of the timeout: | |
622 | /// | |
623 | /// ```rust,no_run | |
624 | /// use std::thread::park_timeout; | |
625 | /// use std::time::{Instant, Duration}; | |
626 | /// | |
627 | /// let timeout = Duration::from_secs(2); | |
628 | /// let beginning_park = Instant::now(); | |
629 | /// park_timeout(timeout); | |
630 | /// | |
631 | /// while beginning_park.elapsed() < timeout { | |
632 | /// println!("restarting park_timeout after {:?}", beginning_park.elapsed()); | |
633 | /// let timeout = timeout - beginning_park.elapsed(); | |
634 | /// park_timeout(timeout); | |
635 | /// } | |
636 | /// ``` | |
e9174d1e | 637 | #[stable(feature = "park_timeout", since = "1.4.0")] |
d9579d0f | 638 | pub fn park_timeout(dur: Duration) { |
85aaf69f SL |
639 | let thread = current(); |
640 | let mut guard = thread.inner.lock.lock().unwrap(); | |
641 | if !*guard { | |
d9579d0f | 642 | let (g, _) = thread.inner.cvar.wait_timeout(guard, dur).unwrap(); |
85aaf69f SL |
643 | guard = g; |
644 | } | |
645 | *guard = false; | |
646 | } | |
647 | ||
c30ab7b3 SL |
648 | //////////////////////////////////////////////////////////////////////////////// |
649 | // ThreadId | |
650 | //////////////////////////////////////////////////////////////////////////////// | |
651 | ||
652 | /// A unique identifier for a running thread. | |
653 | /// | |
654 | /// A `ThreadId` is an opaque object that has a unique value for each thread | |
655 | /// that creates one. `ThreadId`s do not correspond to a thread's system- | |
656 | /// designated identifier. | |
32a655c1 SL |
657 | /// |
658 | /// # Examples | |
659 | /// | |
660 | /// ``` | |
661 | /// #![feature(thread_id)] | |
662 | /// | |
663 | /// use std::thread; | |
664 | /// | |
665 | /// let handler = thread::Builder::new() | |
666 | /// .spawn(|| { | |
667 | /// let thread = thread::current(); | |
668 | /// let thread_id = thread.id(); | |
669 | /// }) | |
670 | /// .unwrap(); | |
671 | /// | |
672 | /// handler.join().unwrap(); | |
673 | /// ``` | |
c30ab7b3 SL |
674 | #[unstable(feature = "thread_id", issue = "21507")] |
675 | #[derive(Eq, PartialEq, Copy, Clone)] | |
676 | pub struct ThreadId(u64); | |
677 | ||
678 | impl ThreadId { | |
679 | // Generate a new unique thread ID. | |
680 | fn new() -> ThreadId { | |
681 | static GUARD: mutex::Mutex = mutex::Mutex::new(); | |
682 | static mut COUNTER: u64 = 0; | |
683 | ||
684 | unsafe { | |
685 | GUARD.lock(); | |
686 | ||
687 | // If we somehow use up all our bits, panic so that we're not | |
688 | // covering up subtle bugs of IDs being reused. | |
689 | if COUNTER == ::u64::MAX { | |
690 | GUARD.unlock(); | |
691 | panic!("failed to generate unique thread ID: bitspace exhausted"); | |
692 | } | |
693 | ||
694 | let id = COUNTER; | |
695 | COUNTER += 1; | |
696 | ||
697 | GUARD.unlock(); | |
698 | ||
699 | ThreadId(id) | |
700 | } | |
701 | } | |
702 | } | |
703 | ||
8bb4bdeb | 704 | #[unstable(feature = "thread_id", issue = "21507")] |
32a655c1 SL |
705 | impl fmt::Debug for ThreadId { |
706 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
707 | f.pad("ThreadId { .. }") | |
708 | } | |
709 | } | |
710 | ||
c34b1796 AL |
711 | //////////////////////////////////////////////////////////////////////////////// |
712 | // Thread | |
713 | //////////////////////////////////////////////////////////////////////////////// | |
714 | ||
85aaf69f | 715 | /// The internal representation of a `Thread` handle |
1a4d82fc | 716 | struct Inner { |
54a0048b | 717 | name: Option<CString>, // Guaranteed to be UTF-8 |
c30ab7b3 | 718 | id: ThreadId, |
1a4d82fc JJ |
719 | lock: Mutex<bool>, // true when there is a buffered unpark |
720 | cvar: Condvar, | |
721 | } | |
722 | ||
1a4d82fc | 723 | #[derive(Clone)] |
85aaf69f | 724 | #[stable(feature = "rust1", since = "1.0.0")] |
1a4d82fc | 725 | /// A handle to a thread. |
32a655c1 SL |
726 | /// |
727 | /// # Examples | |
728 | /// | |
729 | /// ``` | |
730 | /// use std::thread; | |
731 | /// | |
732 | /// let handler = thread::Builder::new() | |
733 | /// .name("foo".into()) | |
734 | /// .spawn(|| { | |
735 | /// let thread = thread::current(); | |
736 | /// println!("thread name: {}", thread.name().unwrap()); | |
737 | /// }) | |
738 | /// .unwrap(); | |
739 | /// | |
740 | /// handler.join().unwrap(); | |
741 | /// ``` | |
1a4d82fc JJ |
742 | pub struct Thread { |
743 | inner: Arc<Inner>, | |
744 | } | |
745 | ||
746 | impl Thread { | |
747 | // Used only internally to construct a thread object without spawning | |
748 | fn new(name: Option<String>) -> Thread { | |
3157f602 XL |
749 | let cname = name.map(|n| { |
750 | CString::new(n).expect("thread name may not contain interior null bytes") | |
751 | }); | |
1a4d82fc JJ |
752 | Thread { |
753 | inner: Arc::new(Inner { | |
54a0048b | 754 | name: cname, |
c30ab7b3 | 755 | id: ThreadId::new(), |
1a4d82fc JJ |
756 | lock: Mutex::new(false), |
757 | cvar: Condvar::new(), | |
758 | }) | |
759 | } | |
760 | } | |
761 | ||
1a4d82fc JJ |
762 | /// Atomically makes the handle's token available if it is not already. |
763 | /// | |
764 | /// See the module doc for more detail. | |
32a655c1 SL |
765 | /// |
766 | /// # Examples | |
767 | /// | |
768 | /// ``` | |
769 | /// use std::thread; | |
770 | /// | |
771 | /// let handler = thread::Builder::new() | |
772 | /// .spawn(|| { | |
773 | /// let thread = thread::current(); | |
774 | /// thread.unpark(); | |
775 | /// }) | |
776 | /// .unwrap(); | |
777 | /// | |
778 | /// handler.join().unwrap(); | |
779 | /// ``` | |
85aaf69f | 780 | #[stable(feature = "rust1", since = "1.0.0")] |
1a4d82fc JJ |
781 | pub fn unpark(&self) { |
782 | let mut guard = self.inner.lock.lock().unwrap(); | |
783 | if !*guard { | |
784 | *guard = true; | |
785 | self.inner.cvar.notify_one(); | |
786 | } | |
787 | } | |
788 | ||
c30ab7b3 | 789 | /// Gets the thread's unique identifier. |
32a655c1 SL |
790 | /// |
791 | /// # Examples | |
792 | /// | |
793 | /// ``` | |
794 | /// #![feature(thread_id)] | |
795 | /// | |
796 | /// use std::thread; | |
797 | /// | |
798 | /// let handler = thread::Builder::new() | |
799 | /// .spawn(|| { | |
800 | /// let thread = thread::current(); | |
801 | /// println!("thread id: {:?}", thread.id()); | |
802 | /// }) | |
803 | /// .unwrap(); | |
804 | /// | |
805 | /// handler.join().unwrap(); | |
806 | /// ``` | |
c30ab7b3 SL |
807 | #[unstable(feature = "thread_id", issue = "21507")] |
808 | pub fn id(&self) -> ThreadId { | |
809 | self.inner.id | |
810 | } | |
811 | ||
9346a6ac | 812 | /// Gets the thread's name. |
3157f602 XL |
813 | /// |
814 | /// # Examples | |
815 | /// | |
816 | /// Threads by default have no name specified: | |
817 | /// | |
818 | /// ``` | |
819 | /// use std::thread; | |
820 | /// | |
821 | /// let builder = thread::Builder::new(); | |
822 | /// | |
823 | /// let handler = builder.spawn(|| { | |
824 | /// assert!(thread::current().name().is_none()); | |
825 | /// }).unwrap(); | |
826 | /// | |
827 | /// handler.join().unwrap(); | |
828 | /// ``` | |
829 | /// | |
830 | /// Thread with a specified name: | |
831 | /// | |
832 | /// ``` | |
833 | /// use std::thread; | |
834 | /// | |
835 | /// let builder = thread::Builder::new() | |
836 | /// .name("foo".into()); | |
837 | /// | |
838 | /// let handler = builder.spawn(|| { | |
839 | /// assert_eq!(thread::current().name(), Some("foo")) | |
840 | /// }).unwrap(); | |
841 | /// | |
842 | /// handler.join().unwrap(); | |
843 | /// ``` | |
85aaf69f | 844 | #[stable(feature = "rust1", since = "1.0.0")] |
1a4d82fc | 845 | pub fn name(&self) -> Option<&str> { |
54a0048b SL |
846 | self.cname().map(|s| unsafe { str::from_utf8_unchecked(s.to_bytes()) } ) |
847 | } | |
848 | ||
849 | fn cname(&self) -> Option<&CStr> { | |
85aaf69f SL |
850 | self.inner.name.as_ref().map(|s| &**s) |
851 | } | |
852 | } | |
853 | ||
854 | #[stable(feature = "rust1", since = "1.0.0")] | |
855 | impl fmt::Debug for Thread { | |
856 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
857 | fmt::Debug::fmt(&self.name(), f) | |
1a4d82fc JJ |
858 | } |
859 | } | |
860 | ||
861 | // a hack to get around privacy restrictions | |
862 | impl thread_info::NewThread for Thread { | |
863 | fn new(name: Option<String>) -> Thread { Thread::new(name) } | |
864 | } | |
865 | ||
c34b1796 | 866 | //////////////////////////////////////////////////////////////////////////////// |
e9174d1e | 867 | // JoinHandle |
c34b1796 AL |
868 | //////////////////////////////////////////////////////////////////////////////// |
869 | ||
1a4d82fc JJ |
870 | /// Indicates the manner in which a thread exited. |
871 | /// | |
872 | /// A thread that completes without panicking is considered to exit successfully. | |
85aaf69f SL |
873 | #[stable(feature = "rust1", since = "1.0.0")] |
874 | pub type Result<T> = ::result::Result<T, Box<Any + Send + 'static>>; | |
1a4d82fc | 875 | |
d9579d0f AL |
876 | // This packet is used to communicate the return value between the child thread |
877 | // and the parent thread. Memory is shared through the `Arc` within and there's | |
878 | // no need for a mutex here because synchronization happens with `join()` (the | |
879 | // parent thread never reads this packet until the child has exited). | |
880 | // | |
881 | // This packet itself is then stored into a `JoinInner` which in turns is placed | |
882 | // in `JoinHandle` and `JoinGuard`. Due to the usage of `UnsafeCell` we need to | |
883 | // manually worry about impls like Send and Sync. The type `T` should | |
884 | // already always be Send (otherwise the thread could not have been created) and | |
885 | // this type is inherently Sync because no methods take &self. Regardless, | |
886 | // however, we add inheriting impls for Send/Sync to this type to ensure it's | |
887 | // Send/Sync and that future modifications will still appropriately classify it. | |
1a4d82fc JJ |
888 | struct Packet<T>(Arc<UnsafeCell<Option<Result<T>>>>); |
889 | ||
d9579d0f AL |
890 | unsafe impl<T: Send> Send for Packet<T> {} |
891 | unsafe impl<T: Sync> Sync for Packet<T> {} | |
1a4d82fc | 892 | |
e9174d1e | 893 | /// Inner representation for JoinHandle |
85aaf69f | 894 | struct JoinInner<T> { |
d9579d0f | 895 | native: Option<imp::Thread>, |
85aaf69f SL |
896 | thread: Thread, |
897 | packet: Packet<T>, | |
85aaf69f SL |
898 | } |
899 | ||
900 | impl<T> JoinInner<T> { | |
901 | fn join(&mut self) -> Result<T> { | |
d9579d0f | 902 | self.native.take().unwrap().join(); |
85aaf69f SL |
903 | unsafe { |
904 | (*self.packet.0.get()).take().unwrap() | |
905 | } | |
906 | } | |
907 | } | |
908 | ||
909 | /// An owned permission to join on a thread (block on its termination). | |
910 | /// | |
e9174d1e | 911 | /// A `JoinHandle` *detaches* the child thread when it is dropped. |
85aaf69f | 912 | /// |
32a655c1 | 913 | /// Due to platform restrictions, it is not possible to [`Clone`] this |
85aaf69f SL |
914 | /// handle: the ability to join a child thread is a uniquely-owned |
915 | /// permission. | |
3157f602 XL |
916 | /// |
917 | /// This `struct` is created by the [`thread::spawn`] function and the | |
918 | /// [`thread::Builder::spawn`] method. | |
919 | /// | |
920 | /// # Examples | |
921 | /// | |
922 | /// Creation from [`thread::spawn`]: | |
923 | /// | |
32a655c1 | 924 | /// ``` |
3157f602 XL |
925 | /// use std::thread; |
926 | /// | |
927 | /// let join_handle: thread::JoinHandle<_> = thread::spawn(|| { | |
928 | /// // some work here | |
929 | /// }); | |
930 | /// ``` | |
931 | /// | |
932 | /// Creation from [`thread::Builder::spawn`]: | |
933 | /// | |
32a655c1 | 934 | /// ``` |
3157f602 XL |
935 | /// use std::thread; |
936 | /// | |
937 | /// let builder = thread::Builder::new(); | |
938 | /// | |
939 | /// let join_handle: thread::JoinHandle<_> = builder.spawn(|| { | |
940 | /// // some work here | |
941 | /// }).unwrap(); | |
942 | /// ``` | |
943 | /// | |
32a655c1 | 944 | /// [`Clone`]: ../../std/clone/trait.Clone.html |
3157f602 XL |
945 | /// [`thread::spawn`]: fn.spawn.html |
946 | /// [`thread::Builder::spawn`]: struct.Builder.html#method.spawn | |
85aaf69f | 947 | #[stable(feature = "rust1", since = "1.0.0")] |
9346a6ac | 948 | pub struct JoinHandle<T>(JoinInner<T>); |
85aaf69f | 949 | |
9346a6ac | 950 | impl<T> JoinHandle<T> { |
32a655c1 SL |
951 | /// Extracts a handle to the underlying thread. |
952 | /// | |
953 | /// # Examples | |
954 | /// | |
955 | /// ``` | |
956 | /// #![feature(thread_id)] | |
957 | /// | |
958 | /// use std::thread; | |
959 | /// | |
960 | /// let builder = thread::Builder::new(); | |
961 | /// | |
962 | /// let join_handle: thread::JoinHandle<_> = builder.spawn(|| { | |
963 | /// // some work here | |
964 | /// }).unwrap(); | |
965 | /// | |
966 | /// let thread = join_handle.thread(); | |
967 | /// println!("thread id: {:?}", thread.id()); | |
968 | /// ``` | |
85aaf69f SL |
969 | #[stable(feature = "rust1", since = "1.0.0")] |
970 | pub fn thread(&self) -> &Thread { | |
971 | &self.0.thread | |
972 | } | |
973 | ||
9346a6ac | 974 | /// Waits for the associated thread to finish. |
85aaf69f | 975 | /// |
32a655c1 SL |
976 | /// If the child thread panics, [`Err`] is returned with the parameter given |
977 | /// to [`panic`]. | |
978 | /// | |
979 | /// [`Err`]: ../../std/result/enum.Result.html#variant.Err | |
980 | /// [`panic`]: ../../std/macro.panic.html | |
981 | /// | |
982 | /// # Examples | |
983 | /// | |
984 | /// ``` | |
985 | /// use std::thread; | |
986 | /// | |
987 | /// let builder = thread::Builder::new(); | |
988 | /// | |
989 | /// let join_handle: thread::JoinHandle<_> = builder.spawn(|| { | |
990 | /// // some work here | |
991 | /// }).unwrap(); | |
992 | /// join_handle.join().expect("Couldn't join on the associated thread"); | |
993 | /// ``` | |
85aaf69f | 994 | #[stable(feature = "rust1", since = "1.0.0")] |
9346a6ac | 995 | pub fn join(mut self) -> Result<T> { |
85aaf69f SL |
996 | self.0.join() |
997 | } | |
998 | } | |
999 | ||
92a42be0 SL |
1000 | impl<T> AsInner<imp::Thread> for JoinHandle<T> { |
1001 | fn as_inner(&self) -> &imp::Thread { self.0.native.as_ref().unwrap() } | |
1002 | } | |
1003 | ||
1004 | impl<T> IntoInner<imp::Thread> for JoinHandle<T> { | |
1005 | fn into_inner(self) -> imp::Thread { self.0.native.unwrap() } | |
1006 | } | |
1007 | ||
8bb4bdeb | 1008 | #[stable(feature = "std_debug", since = "1.16.0")] |
32a655c1 SL |
1009 | impl<T> fmt::Debug for JoinHandle<T> { |
1010 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
1011 | f.pad("JoinHandle { .. }") | |
1012 | } | |
1013 | } | |
1014 | ||
d9579d0f AL |
1015 | fn _assert_sync_and_send() { |
1016 | fn _assert_both<T: Send + Sync>() {} | |
1017 | _assert_both::<JoinHandle<()>>(); | |
d9579d0f AL |
1018 | _assert_both::<Thread>(); |
1019 | } | |
1020 | ||
c34b1796 AL |
1021 | //////////////////////////////////////////////////////////////////////////////// |
1022 | // Tests | |
1023 | //////////////////////////////////////////////////////////////////////////////// | |
1024 | ||
c30ab7b3 | 1025 | #[cfg(all(test, not(target_os = "emscripten")))] |
d9579d0f | 1026 | mod tests { |
1a4d82fc JJ |
1027 | use any::Any; |
1028 | use sync::mpsc::{channel, Sender}; | |
1a4d82fc | 1029 | use result; |
c34b1796 | 1030 | use super::{Builder}; |
85aaf69f | 1031 | use thread; |
85aaf69f | 1032 | use time::Duration; |
c34b1796 | 1033 | use u32; |
1a4d82fc JJ |
1034 | |
1035 | // !!! These tests are dangerous. If something is buggy, they will hang, !!! | |
1036 | // !!! instead of exiting cleanly. This might wedge the buildbots. !!! | |
1037 | ||
1038 | #[test] | |
1039 | fn test_unnamed_thread() { | |
85aaf69f SL |
1040 | thread::spawn(move|| { |
1041 | assert!(thread::current().name().is_none()); | |
1042 | }).join().ok().unwrap(); | |
1a4d82fc JJ |
1043 | } |
1044 | ||
1045 | #[test] | |
1046 | fn test_named_thread() { | |
e9174d1e | 1047 | Builder::new().name("ada lovelace".to_string()).spawn(move|| { |
85aaf69f | 1048 | assert!(thread::current().name().unwrap() == "ada lovelace".to_string()); |
e9174d1e | 1049 | }).unwrap().join().unwrap(); |
1a4d82fc JJ |
1050 | } |
1051 | ||
54a0048b SL |
1052 | #[test] |
1053 | #[should_panic] | |
1054 | fn test_invalid_named_thread() { | |
1055 | let _ = Builder::new().name("ada l\0velace".to_string()).spawn(|| {}); | |
1056 | } | |
1057 | ||
1a4d82fc JJ |
1058 | #[test] |
1059 | fn test_run_basic() { | |
1060 | let (tx, rx) = channel(); | |
85aaf69f | 1061 | thread::spawn(move|| { |
1a4d82fc JJ |
1062 | tx.send(()).unwrap(); |
1063 | }); | |
1064 | rx.recv().unwrap(); | |
1065 | } | |
1066 | ||
1a4d82fc JJ |
1067 | #[test] |
1068 | fn test_join_panic() { | |
85aaf69f | 1069 | match thread::spawn(move|| { |
1a4d82fc JJ |
1070 | panic!() |
1071 | }).join() { | |
1072 | result::Result::Err(_) => (), | |
1073 | result::Result::Ok(()) => panic!() | |
1074 | } | |
1075 | } | |
1076 | ||
1077 | #[test] | |
1078 | fn test_spawn_sched() { | |
1a4d82fc JJ |
1079 | let (tx, rx) = channel(); |
1080 | ||
c34b1796 | 1081 | fn f(i: i32, tx: Sender<()>) { |
1a4d82fc | 1082 | let tx = tx.clone(); |
85aaf69f | 1083 | thread::spawn(move|| { |
1a4d82fc JJ |
1084 | if i == 0 { |
1085 | tx.send(()).unwrap(); | |
1086 | } else { | |
1087 | f(i - 1, tx); | |
1088 | } | |
1089 | }); | |
1090 | ||
1091 | } | |
1092 | f(10, tx); | |
1093 | rx.recv().unwrap(); | |
1094 | } | |
1095 | ||
1096 | #[test] | |
1097 | fn test_spawn_sched_childs_on_default_sched() { | |
1098 | let (tx, rx) = channel(); | |
1099 | ||
85aaf69f SL |
1100 | thread::spawn(move|| { |
1101 | thread::spawn(move|| { | |
1a4d82fc JJ |
1102 | tx.send(()).unwrap(); |
1103 | }); | |
1104 | }); | |
1105 | ||
1106 | rx.recv().unwrap(); | |
1107 | } | |
1108 | ||
e9174d1e | 1109 | fn avoid_copying_the_body<F>(spawnfn: F) where F: FnOnce(Box<Fn() + Send>) { |
c34b1796 | 1110 | let (tx, rx) = channel(); |
1a4d82fc | 1111 | |
c34b1796 AL |
1112 | let x: Box<_> = box 1; |
1113 | let x_in_parent = (&*x) as *const i32 as usize; | |
1a4d82fc | 1114 | |
c34b1796 AL |
1115 | spawnfn(Box::new(move|| { |
1116 | let x_in_child = (&*x) as *const i32 as usize; | |
1a4d82fc JJ |
1117 | tx.send(x_in_child).unwrap(); |
1118 | })); | |
1119 | ||
1120 | let x_in_child = rx.recv().unwrap(); | |
1121 | assert_eq!(x_in_parent, x_in_child); | |
1122 | } | |
1123 | ||
1124 | #[test] | |
1125 | fn test_avoid_copying_the_body_spawn() { | |
1126 | avoid_copying_the_body(|v| { | |
c34b1796 | 1127 | thread::spawn(move || v()); |
1a4d82fc JJ |
1128 | }); |
1129 | } | |
1130 | ||
1131 | #[test] | |
1132 | fn test_avoid_copying_the_body_thread_spawn() { | |
1133 | avoid_copying_the_body(|f| { | |
85aaf69f | 1134 | thread::spawn(move|| { |
c34b1796 | 1135 | f(); |
1a4d82fc JJ |
1136 | }); |
1137 | }) | |
1138 | } | |
1139 | ||
1140 | #[test] | |
1141 | fn test_avoid_copying_the_body_join() { | |
1142 | avoid_copying_the_body(|f| { | |
85aaf69f | 1143 | let _ = thread::spawn(move|| { |
c34b1796 | 1144 | f() |
1a4d82fc JJ |
1145 | }).join(); |
1146 | }) | |
1147 | } | |
1148 | ||
1149 | #[test] | |
1150 | fn test_child_doesnt_ref_parent() { | |
bd371182 AL |
1151 | // If the child refcounts the parent thread, this will stack overflow when |
1152 | // climbing the thread tree to dereference each ancestor. (See #1789) | |
1a4d82fc JJ |
1153 | // (well, it would if the constant were 8000+ - I lowered it to be more |
1154 | // valgrind-friendly. try this at home, instead..!) | |
c34b1796 | 1155 | const GENERATIONS: u32 = 16; |
e9174d1e | 1156 | fn child_no(x: u32) -> Box<Fn() + Send> { |
c34b1796 | 1157 | return Box::new(move|| { |
1a4d82fc | 1158 | if x < GENERATIONS { |
c34b1796 | 1159 | thread::spawn(move|| child_no(x+1)()); |
1a4d82fc JJ |
1160 | } |
1161 | }); | |
1162 | } | |
c34b1796 | 1163 | thread::spawn(|| child_no(0)()); |
1a4d82fc JJ |
1164 | } |
1165 | ||
1166 | #[test] | |
1167 | fn test_simple_newsched_spawn() { | |
85aaf69f | 1168 | thread::spawn(move || {}); |
1a4d82fc JJ |
1169 | } |
1170 | ||
1171 | #[test] | |
1172 | fn test_try_panic_message_static_str() { | |
85aaf69f | 1173 | match thread::spawn(move|| { |
1a4d82fc JJ |
1174 | panic!("static string"); |
1175 | }).join() { | |
1176 | Err(e) => { | |
1177 | type T = &'static str; | |
1178 | assert!(e.is::<T>()); | |
c34b1796 | 1179 | assert_eq!(*e.downcast::<T>().unwrap(), "static string"); |
1a4d82fc JJ |
1180 | } |
1181 | Ok(()) => panic!() | |
1182 | } | |
1183 | } | |
1184 | ||
1185 | #[test] | |
1186 | fn test_try_panic_message_owned_str() { | |
85aaf69f | 1187 | match thread::spawn(move|| { |
1a4d82fc JJ |
1188 | panic!("owned string".to_string()); |
1189 | }).join() { | |
1190 | Err(e) => { | |
1191 | type T = String; | |
1192 | assert!(e.is::<T>()); | |
c34b1796 | 1193 | assert_eq!(*e.downcast::<T>().unwrap(), "owned string".to_string()); |
1a4d82fc JJ |
1194 | } |
1195 | Ok(()) => panic!() | |
1196 | } | |
1197 | } | |
1198 | ||
1199 | #[test] | |
1200 | fn test_try_panic_message_any() { | |
85aaf69f | 1201 | match thread::spawn(move|| { |
1a4d82fc JJ |
1202 | panic!(box 413u16 as Box<Any + Send>); |
1203 | }).join() { | |
1204 | Err(e) => { | |
1205 | type T = Box<Any + Send>; | |
1206 | assert!(e.is::<T>()); | |
c34b1796 | 1207 | let any = e.downcast::<T>().unwrap(); |
1a4d82fc | 1208 | assert!(any.is::<u16>()); |
c34b1796 | 1209 | assert_eq!(*any.downcast::<u16>().unwrap(), 413); |
1a4d82fc JJ |
1210 | } |
1211 | Ok(()) => panic!() | |
1212 | } | |
1213 | } | |
1214 | ||
1215 | #[test] | |
1216 | fn test_try_panic_message_unit_struct() { | |
1217 | struct Juju; | |
1218 | ||
85aaf69f | 1219 | match thread::spawn(move|| { |
1a4d82fc JJ |
1220 | panic!(Juju) |
1221 | }).join() { | |
1222 | Err(ref e) if e.is::<Juju>() => {} | |
1223 | Err(_) | Ok(()) => panic!() | |
1224 | } | |
1225 | } | |
1226 | ||
85aaf69f SL |
1227 | #[test] |
1228 | fn test_park_timeout_unpark_before() { | |
1229 | for _ in 0..10 { | |
1230 | thread::current().unpark(); | |
9cc50fc6 | 1231 | thread::park_timeout(Duration::from_millis(u32::MAX as u64)); |
85aaf69f SL |
1232 | } |
1233 | } | |
1234 | ||
1235 | #[test] | |
1236 | fn test_park_timeout_unpark_not_called() { | |
1237 | for _ in 0..10 { | |
9cc50fc6 | 1238 | thread::park_timeout(Duration::from_millis(10)); |
85aaf69f SL |
1239 | } |
1240 | } | |
1241 | ||
1242 | #[test] | |
1243 | fn test_park_timeout_unpark_called_other_thread() { | |
85aaf69f SL |
1244 | for _ in 0..10 { |
1245 | let th = thread::current(); | |
1246 | ||
1247 | let _guard = thread::spawn(move || { | |
9cc50fc6 | 1248 | super::sleep(Duration::from_millis(50)); |
85aaf69f SL |
1249 | th.unpark(); |
1250 | }); | |
1251 | ||
9cc50fc6 | 1252 | thread::park_timeout(Duration::from_millis(u32::MAX as u64)); |
85aaf69f SL |
1253 | } |
1254 | } | |
1255 | ||
c34b1796 AL |
1256 | #[test] |
1257 | fn sleep_ms_smoke() { | |
9cc50fc6 | 1258 | thread::sleep(Duration::from_millis(2)); |
c34b1796 AL |
1259 | } |
1260 | ||
c30ab7b3 SL |
1261 | #[test] |
1262 | fn test_thread_id_equal() { | |
1263 | assert!(thread::current().id() == thread::current().id()); | |
1264 | } | |
1265 | ||
1266 | #[test] | |
1267 | fn test_thread_id_not_equal() { | |
1268 | let spawned_id = thread::spawn(|| thread::current().id()).join().unwrap(); | |
1269 | assert!(thread::current().id() != spawned_id); | |
1270 | } | |
1271 | ||
bd371182 | 1272 | // NOTE: the corresponding test for stderr is in run-pass/thread-stderr, due |
1a4d82fc JJ |
1273 | // to the test harness apparently interfering with stderr configuration. |
1274 | } |