Skip to content

Commit 1db1ae4

Browse files
committed
std: split up the thread module
1 parent ab67c37 commit 1db1ae4

File tree

12 files changed

+1918
-1876
lines changed

12 files changed

+1918
-1876
lines changed

library/std/src/thread/builder.rs

Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
use super::join_handle::JoinHandle;
2+
use super::lifecycle::spawn_unchecked;
3+
use crate::io;
4+
5+
/// Thread factory, which can be used in order to configure the properties of
6+
/// a new thread.
7+
///
8+
/// Methods can be chained on it in order to configure it.
9+
///
10+
/// The two configurations available are:
11+
///
12+
/// - [`name`]: specifies an [associated name for the thread][naming-threads]
13+
/// - [`stack_size`]: specifies the [desired stack size for the thread][stack-size]
14+
///
15+
/// The [`spawn`] method will take ownership of the builder and create an
16+
/// [`io::Result`] to the thread handle with the given configuration.
17+
///
18+
/// The [`thread::spawn`] free function uses a `Builder` with default
19+
/// configuration and [`unwrap`]s its return value.
20+
///
21+
/// You may want to use [`spawn`] instead of [`thread::spawn`], when you want
22+
/// to recover from a failure to launch a thread, indeed the free function will
23+
/// panic where the `Builder` method will return a [`io::Result`].
24+
///
25+
/// # Examples
26+
///
27+
/// ```
28+
/// use std::thread;
29+
///
30+
/// let builder = thread::Builder::new();
31+
///
32+
/// let handler = builder.spawn(|| {
33+
/// // thread code
34+
/// }).unwrap();
35+
///
36+
/// handler.join().unwrap();
37+
/// ```
38+
///
39+
/// [`stack_size`]: Builder::stack_size
40+
/// [`name`]: Builder::name
41+
/// [`spawn`]: Builder::spawn
42+
/// [`thread::spawn`]: spawn
43+
/// [`io::Result`]: crate::io::Result
44+
/// [`unwrap`]: crate::result::Result::unwrap
45+
/// [naming-threads]: ./index.html#naming-threads
46+
/// [stack-size]: ./index.html#stack-size
47+
#[must_use = "must eventually spawn the thread"]
48+
#[stable(feature = "rust1", since = "1.0.0")]
49+
#[derive(Debug)]
50+
pub struct Builder {
51+
/// A name for the thread-to-be, for identification in panic messages
52+
pub(super) name: Option<String>,
53+
/// The size of the stack for the spawned thread in bytes
54+
pub(super) stack_size: Option<usize>,
55+
/// Skip running and inheriting the thread spawn hooks
56+
pub(super) no_hooks: bool,
57+
}
58+
59+
impl Builder {
60+
/// Generates the base configuration for spawning a thread, from which
61+
/// configuration methods can be chained.
62+
///
63+
/// # Examples
64+
///
65+
/// ```
66+
/// use std::thread;
67+
///
68+
/// let builder = thread::Builder::new()
69+
/// .name("foo".into())
70+
/// .stack_size(32 * 1024);
71+
///
72+
/// let handler = builder.spawn(|| {
73+
/// // thread code
74+
/// }).unwrap();
75+
///
76+
/// handler.join().unwrap();
77+
/// ```
78+
#[stable(feature = "rust1", since = "1.0.0")]
79+
pub fn new() -> Builder {
80+
Builder { name: None, stack_size: None, no_hooks: false }
81+
}
82+
83+
/// Names the thread-to-be. Currently the name is used for identification
84+
/// only in panic messages.
85+
///
86+
/// The name must not contain null bytes (`\0`).
87+
///
88+
/// For more information about named threads, see
89+
/// [this module-level documentation][naming-threads].
90+
///
91+
/// # Examples
92+
///
93+
/// ```
94+
/// use std::thread;
95+
///
96+
/// let builder = thread::Builder::new()
97+
/// .name("foo".into());
98+
///
99+
/// let handler = builder.spawn(|| {
100+
/// assert_eq!(thread::current().name(), Some("foo"))
101+
/// }).unwrap();
102+
///
103+
/// handler.join().unwrap();
104+
/// ```
105+
///
106+
/// [naming-threads]: ./index.html#naming-threads
107+
#[stable(feature = "rust1", since = "1.0.0")]
108+
pub fn name(mut self, name: String) -> Builder {
109+
self.name = Some(name);
110+
self
111+
}
112+
113+
/// Sets the size of the stack (in bytes) for the new thread.
114+
///
115+
/// The actual stack size may be greater than this value if
116+
/// the platform specifies a minimal stack size.
117+
///
118+
/// For more information about the stack size for threads, see
119+
/// [this module-level documentation][stack-size].
120+
///
121+
/// # Examples
122+
///
123+
/// ```
124+
/// use std::thread;
125+
///
126+
/// let builder = thread::Builder::new().stack_size(32 * 1024);
127+
/// ```
128+
///
129+
/// [stack-size]: ./index.html#stack-size
130+
#[stable(feature = "rust1", since = "1.0.0")]
131+
pub fn stack_size(mut self, size: usize) -> Builder {
132+
self.stack_size = Some(size);
133+
self
134+
}
135+
136+
/// Disables running and inheriting [spawn hooks](add_spawn_hook).
137+
///
138+
/// Use this if the parent thread is in no way relevant for the child thread.
139+
/// For example, when lazily spawning threads for a thread pool.
140+
#[unstable(feature = "thread_spawn_hook", issue = "132951")]
141+
pub fn no_hooks(mut self) -> Builder {
142+
self.no_hooks = true;
143+
self
144+
}
145+
146+
/// Spawns a new thread by taking ownership of the `Builder`, and returns an
147+
/// [`io::Result`] to its [`JoinHandle`].
148+
///
149+
/// The spawned thread may outlive the caller (unless the caller thread
150+
/// is the main thread; the whole process is terminated when the main
151+
/// thread finishes). The join handle can be used to block on
152+
/// termination of the spawned thread, including recovering its panics.
153+
///
154+
/// For a more complete documentation see [`thread::spawn`][`spawn`].
155+
///
156+
/// # Errors
157+
///
158+
/// Unlike the [`spawn`] free function, this method yields an
159+
/// [`io::Result`] to capture any failure to create the thread at
160+
/// the OS level.
161+
///
162+
/// [`io::Result`]: crate::io::Result
163+
///
164+
/// # Panics
165+
///
166+
/// Panics if a thread name was set and it contained null bytes.
167+
///
168+
/// # Examples
169+
///
170+
/// ```
171+
/// use std::thread;
172+
///
173+
/// let builder = thread::Builder::new();
174+
///
175+
/// let handler = builder.spawn(|| {
176+
/// // thread code
177+
/// }).unwrap();
178+
///
179+
/// handler.join().unwrap();
180+
/// ```
181+
#[stable(feature = "rust1", since = "1.0.0")]
182+
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
183+
pub fn spawn<F, T>(self, f: F) -> io::Result<JoinHandle<T>>
184+
where
185+
F: FnOnce() -> T,
186+
F: Send + 'static,
187+
T: Send + 'static,
188+
{
189+
unsafe { self.spawn_unchecked(f) }
190+
}
191+
192+
/// Spawns a new thread without any lifetime restrictions by taking ownership
193+
/// of the `Builder`, and returns an [`io::Result`] to its [`JoinHandle`].
194+
///
195+
/// The spawned thread may outlive the caller (unless the caller thread
196+
/// is the main thread; the whole process is terminated when the main
197+
/// thread finishes). The join handle can be used to block on
198+
/// termination of the spawned thread, including recovering its panics.
199+
///
200+
/// This method is identical to [`thread::Builder::spawn`][`Builder::spawn`],
201+
/// except for the relaxed lifetime bounds, which render it unsafe.
202+
/// For a more complete documentation see [`thread::spawn`][`spawn`].
203+
///
204+
/// # Errors
205+
///
206+
/// Unlike the [`spawn`] free function, this method yields an
207+
/// [`io::Result`] to capture any failure to create the thread at
208+
/// the OS level.
209+
///
210+
/// # Panics
211+
///
212+
/// Panics if a thread name was set and it contained null bytes.
213+
///
214+
/// # Safety
215+
///
216+
/// The caller has to ensure that the spawned thread does not outlive any
217+
/// references in the supplied thread closure and its return type.
218+
/// This can be guaranteed in two ways:
219+
///
220+
/// - ensure that [`join`][`JoinHandle::join`] is called before any referenced
221+
/// data is dropped
222+
/// - use only types with `'static` lifetime bounds, i.e., those with no or only
223+
/// `'static` references (both [`thread::Builder::spawn`][`Builder::spawn`]
224+
/// and [`thread::spawn`][`spawn`] enforce this property statically)
225+
///
226+
/// # Examples
227+
///
228+
/// ```
229+
/// use std::thread;
230+
///
231+
/// let builder = thread::Builder::new();
232+
///
233+
/// let x = 1;
234+
/// let thread_x = &x;
235+
///
236+
/// let handler = unsafe {
237+
/// builder.spawn_unchecked(move || {
238+
/// println!("x = {}", *thread_x);
239+
/// }).unwrap()
240+
/// };
241+
///
242+
/// // caller has to ensure `join()` is called, otherwise
243+
/// // it is possible to access freed memory if `x` gets
244+
/// // dropped before the thread closure is executed!
245+
/// handler.join().unwrap();
246+
/// ```
247+
///
248+
/// [`io::Result`]: crate::io::Result
249+
#[stable(feature = "thread_spawn_unchecked", since = "1.82.0")]
250+
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
251+
pub unsafe fn spawn_unchecked<F, T>(self, f: F) -> io::Result<JoinHandle<T>>
252+
where
253+
F: FnOnce() -> T,
254+
F: Send,
255+
T: Send,
256+
{
257+
let Builder { name, stack_size, no_hooks } = self;
258+
Ok(JoinHandle(unsafe { spawn_unchecked(name, stack_size, no_hooks, None, f) }?))
259+
}
260+
}

library/std/src/thread/current.rs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
use super::{Thread, ThreadId, imp};
1+
use super::id::ThreadId;
2+
use super::main_thread;
3+
use super::thread::Thread;
24
use crate::mem::ManuallyDrop;
35
use crate::ptr;
6+
use crate::sys::thread as imp;
47
use crate::sys::thread_local::local_pointer;
58

69
const NONE: *mut () = ptr::null_mut();
@@ -184,7 +187,7 @@ pub(crate) fn current_os_id() -> u64 {
184187

185188
/// Gets a reference to the handle of the thread that invokes it, if the handle
186189
/// has been initialized.
187-
pub(super) fn try_with_current<F, R>(f: F) -> R
190+
fn try_with_current<F, R>(f: F) -> R
188191
where
189192
F: FnOnce(Option<&Thread>) -> R,
190193
{
@@ -202,6 +205,36 @@ where
202205
}
203206
}
204207

208+
/// Run a function with the current thread's name.
209+
///
210+
/// Modulo thread local accesses, this function is safe to call from signal
211+
/// handlers and in similar circumstances where allocations are not possible.
212+
pub(crate) fn with_current_name<F, R>(f: F) -> R
213+
where
214+
F: FnOnce(Option<&str>) -> R,
215+
{
216+
try_with_current(|thread| {
217+
let name = if let Some(thread) = thread {
218+
// If there is a current thread handle, try to use the name stored
219+
// there.
220+
thread.name()
221+
} else if let Some(main) = main_thread::get()
222+
&& let Some(id) = id::get()
223+
&& id == main
224+
{
225+
// The main thread doesn't always have a thread handle, we must
226+
// identify it through its ID instead. The checks are ordered so
227+
// that the current ID is only loaded if it is actually needed,
228+
// since loading it from TLS might need multiple expensive accesses.
229+
Some("main")
230+
} else {
231+
None
232+
};
233+
234+
f(name)
235+
})
236+
}
237+
205238
/// Gets a handle to the thread that invokes it. If the handle stored in thread-
206239
/// local storage was already destroyed, this creates a new unnamed temporary
207240
/// handle to allow thread parking in nearly all situations.

0 commit comments

Comments
 (0)