aboutsummaryrefslogtreecommitdiff
path: root/vendor/crossbeam-utils/src/thread.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/crossbeam-utils/src/thread.rs')
-rw-r--r--vendor/crossbeam-utils/src/thread.rs604
1 files changed, 0 insertions, 604 deletions
diff --git a/vendor/crossbeam-utils/src/thread.rs b/vendor/crossbeam-utils/src/thread.rs
deleted file mode 100644
index 2d4805e..0000000
--- a/vendor/crossbeam-utils/src/thread.rs
+++ /dev/null
@@ -1,604 +0,0 @@
-//! Threads that can borrow variables from the stack.
-//!
-//! Create a scope when spawned threads need to access variables on the stack:
-//!
-//! ```
-//! use crossbeam_utils::thread;
-//!
-//! let people = vec![
-//! "Alice".to_string(),
-//! "Bob".to_string(),
-//! "Carol".to_string(),
-//! ];
-//!
-//! thread::scope(|s| {
-//! for person in &people {
-//! s.spawn(move |_| {
-//! println!("Hello, {}!", person);
-//! });
-//! }
-//! }).unwrap();
-//! ```
-//!
-//! # Why scoped threads?
-//!
-//! Suppose we wanted to re-write the previous example using plain threads:
-//!
-//! ```compile_fail,E0597
-//! use std::thread;
-//!
-//! let people = vec![
-//! "Alice".to_string(),
-//! "Bob".to_string(),
-//! "Carol".to_string(),
-//! ];
-//!
-//! let mut threads = Vec::new();
-//!
-//! for person in &people {
-//! threads.push(thread::spawn(move || {
-//! println!("Hello, {}!", person);
-//! }));
-//! }
-//!
-//! for thread in threads {
-//! thread.join().unwrap();
-//! }
-//! ```
-//!
-//! This doesn't work because the borrow checker complains about `people` not living long enough:
-//!
-//! ```text
-//! error[E0597]: `people` does not live long enough
-//! --> src/main.rs:12:20
-//! |
-//! 12 | for person in &people {
-//! | ^^^^^^ borrowed value does not live long enough
-//! ...
-//! 21 | }
-//! | - borrowed value only lives until here
-//! |
-//! = note: borrowed value must be valid for the static lifetime...
-//! ```
-//!
-//! The problem here is that spawned threads are not allowed to borrow variables on stack because
-//! the compiler cannot prove they will be joined before `people` is destroyed.
-//!
-//! Scoped threads are a mechanism to guarantee to the compiler that spawned threads will be joined
-//! before the scope ends.
-//!
-//! # How scoped threads work
-//!
-//! If a variable is borrowed by a thread, the thread must complete before the variable is
-//! destroyed. Threads spawned using [`std::thread::spawn`] can only borrow variables with the
-//! `'static` lifetime because the borrow checker cannot be sure when the thread will complete.
-//!
-//! A scope creates a clear boundary between variables outside the scope and threads inside the
-//! scope. Whenever a scope spawns a thread, it promises to join the thread before the scope ends.
-//! This way we guarantee to the borrow checker that scoped threads only live within the scope and
-//! can safely access variables outside it.
-//!
-//! # Nesting scoped threads
-//!
-//! Sometimes scoped threads need to spawn more threads within the same scope. This is a little
-//! tricky because argument `s` lives *inside* the invocation of `thread::scope()` and as such
-//! cannot be borrowed by scoped threads:
-//!
-//! ```compile_fail,E0521
-//! use crossbeam_utils::thread;
-//!
-//! thread::scope(|s| {
-//! s.spawn(|_| {
-//! // Not going to compile because we're trying to borrow `s`,
-//! // which lives *inside* the scope! :(
-//! s.spawn(|_| println!("nested thread"));
-//! });
-//! });
-//! ```
-//!
-//! Fortunately, there is a solution. Every scoped thread is passed a reference to its scope as an
-//! argument, which can be used for spawning nested threads:
-//!
-//! ```
-//! use crossbeam_utils::thread;
-//!
-//! thread::scope(|s| {
-//! // Note the `|s|` here.
-//! s.spawn(|s| {
-//! // Yay, this works because we're using a fresh argument `s`! :)
-//! s.spawn(|_| println!("nested thread"));
-//! });
-//! }).unwrap();
-//! ```
-
-use std::fmt;
-use std::io;
-use std::marker::PhantomData;
-use std::mem;
-use std::panic;
-use std::sync::{Arc, Mutex};
-use std::thread;
-
-use crate::sync::WaitGroup;
-use cfg_if::cfg_if;
-
-type SharedVec<T> = Arc<Mutex<Vec<T>>>;
-type SharedOption<T> = Arc<Mutex<Option<T>>>;
-
-/// Creates a new scope for spawning threads.
-///
-/// All child threads that haven't been manually joined will be automatically joined just before
-/// this function invocation ends. If all joined threads have successfully completed, `Ok` is
-/// returned with the return value of `f`. If any of the joined threads has panicked, an `Err` is
-/// returned containing errors from panicked threads. Note that if panics are implemented by
-/// aborting the process, no error is returned; see the notes of [std::panic::catch_unwind].
-///
-/// **Note:** Since Rust 1.63, this function is soft-deprecated in favor of the more efficient [`std::thread::scope`].
-///
-/// # Examples
-///
-/// ```
-/// use crossbeam_utils::thread;
-///
-/// let var = vec![1, 2, 3];
-///
-/// thread::scope(|s| {
-/// s.spawn(|_| {
-/// println!("A child thread borrowing `var`: {:?}", var);
-/// });
-/// }).unwrap();
-/// ```
-pub fn scope<'env, F, R>(f: F) -> thread::Result<R>
-where
- F: FnOnce(&Scope<'env>) -> R,
-{
- struct AbortOnPanic;
- impl Drop for AbortOnPanic {
- fn drop(&mut self) {
- if thread::panicking() {
- std::process::abort();
- }
- }
- }
-
- let wg = WaitGroup::new();
- let scope = Scope::<'env> {
- handles: SharedVec::default(),
- wait_group: wg.clone(),
- _marker: PhantomData,
- };
-
- // Execute the scoped function, but catch any panics.
- let result = panic::catch_unwind(panic::AssertUnwindSafe(|| f(&scope)));
-
- // If an unwinding panic occurs before all threads are joined
- // promote it to an aborting panic to prevent any threads from escaping the scope.
- let guard = AbortOnPanic;
-
- // Wait until all nested scopes are dropped.
- drop(scope.wait_group);
- wg.wait();
-
- // Join all remaining spawned threads.
- let panics: Vec<_> = scope
- .handles
- .lock()
- .unwrap()
- // Filter handles that haven't been joined, join them, and collect errors.
- .drain(..)
- .filter_map(|handle| handle.lock().unwrap().take())
- .filter_map(|handle| handle.join().err())
- .collect();
-
- mem::forget(guard);
-
- // If `f` has panicked, resume unwinding.
- // If any of the child threads have panicked, return the panic errors.
- // Otherwise, everything is OK and return the result of `f`.
- match result {
- Err(err) => panic::resume_unwind(err),
- Ok(res) => {
- if panics.is_empty() {
- Ok(res)
- } else {
- Err(Box::new(panics))
- }
- }
- }
-}
-
-/// A scope for spawning threads.
-pub struct Scope<'env> {
- /// The list of the thread join handles.
- handles: SharedVec<SharedOption<thread::JoinHandle<()>>>,
-
- /// Used to wait until all subscopes all dropped.
- wait_group: WaitGroup,
-
- /// Borrows data with invariant lifetime `'env`.
- _marker: PhantomData<&'env mut &'env ()>,
-}
-
-unsafe impl Sync for Scope<'_> {}
-
-impl<'env> Scope<'env> {
- /// Spawns a scoped thread.
- ///
- /// This method is similar to the [`spawn`] function in Rust's standard library. The difference
- /// is that this thread is scoped, meaning it's guaranteed to terminate before the scope exits,
- /// allowing it to reference variables outside the scope.
- ///
- /// The scoped thread is passed a reference to this scope as an argument, which can be used for
- /// spawning nested threads.
- ///
- /// The returned [handle](ScopedJoinHandle) can be used to manually
- /// [join](ScopedJoinHandle::join) the thread before the scope exits.
- ///
- /// This will create a thread using default parameters of [`ScopedThreadBuilder`], if you want to specify the
- /// stack size or the name of the thread, use this API instead.
- ///
- /// [`spawn`]: std::thread::spawn
- ///
- /// # Panics
- ///
- /// Panics if the OS fails to create a thread; use [`ScopedThreadBuilder::spawn`]
- /// to recover from such errors.
- ///
- /// # Examples
- ///
- /// ```
- /// use crossbeam_utils::thread;
- ///
- /// thread::scope(|s| {
- /// let handle = s.spawn(|_| {
- /// println!("A child thread is running");
- /// 42
- /// });
- ///
- /// // Join the thread and retrieve its result.
- /// let res = handle.join().unwrap();
- /// assert_eq!(res, 42);
- /// }).unwrap();
- /// ```
- pub fn spawn<'scope, F, T>(&'scope self, f: F) -> ScopedJoinHandle<'scope, T>
- where
- F: FnOnce(&Scope<'env>) -> T,
- F: Send + 'env,
- T: Send + 'env,
- {
- self.builder()
- .spawn(f)
- .expect("failed to spawn scoped thread")
- }
-
- /// Creates a builder that can configure a thread before spawning.
- ///
- /// # Examples
- ///
- /// ```
- /// use crossbeam_utils::thread;
- ///
- /// thread::scope(|s| {
- /// s.builder()
- /// .spawn(|_| println!("A child thread is running"))
- /// .unwrap();
- /// }).unwrap();
- /// ```
- pub fn builder<'scope>(&'scope self) -> ScopedThreadBuilder<'scope, 'env> {
- ScopedThreadBuilder {
- scope: self,
- builder: thread::Builder::new(),
- }
- }
-}
-
-impl fmt::Debug for Scope<'_> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.pad("Scope { .. }")
- }
-}
-
-/// Configures the properties of a new thread.
-///
-/// The two configurable properties are:
-///
-/// - [`name`]: Specifies an [associated name for the thread][naming-threads].
-/// - [`stack_size`]: Specifies the [desired stack size for the thread][stack-size].
-///
-/// The [`spawn`] method will take ownership of the builder and return an [`io::Result`] of the
-/// thread handle with the given configuration.
-///
-/// The [`Scope::spawn`] method uses a builder with default configuration and unwraps its return
-/// value. You may want to use this builder when you want to recover from a failure to launch a
-/// thread.
-///
-/// # Examples
-///
-/// ```
-/// use crossbeam_utils::thread;
-///
-/// thread::scope(|s| {
-/// s.builder()
-/// .spawn(|_| println!("Running a child thread"))
-/// .unwrap();
-/// }).unwrap();
-/// ```
-///
-/// [`name`]: ScopedThreadBuilder::name
-/// [`stack_size`]: ScopedThreadBuilder::stack_size
-/// [`spawn`]: ScopedThreadBuilder::spawn
-/// [`io::Result`]: std::io::Result
-/// [naming-threads]: std::thread#naming-threads
-/// [stack-size]: std::thread#stack-size
-#[derive(Debug)]
-pub struct ScopedThreadBuilder<'scope, 'env> {
- scope: &'scope Scope<'env>,
- builder: thread::Builder,
-}
-
-impl<'scope, 'env> ScopedThreadBuilder<'scope, 'env> {
- /// Sets the name for the new thread.
- ///
- /// The name must not contain null bytes (`\0`).
- ///
- /// For more information about named threads, see [here][naming-threads].
- ///
- /// # Examples
- ///
- /// ```
- /// use crossbeam_utils::thread;
- /// use std::thread::current;
- ///
- /// thread::scope(|s| {
- /// s.builder()
- /// .name("my thread".to_string())
- /// .spawn(|_| assert_eq!(current().name(), Some("my thread")))
- /// .unwrap();
- /// }).unwrap();
- /// ```
- ///
- /// [naming-threads]: std::thread#naming-threads
- pub fn name(mut self, name: String) -> ScopedThreadBuilder<'scope, 'env> {
- self.builder = self.builder.name(name);
- self
- }
-
- /// Sets the size of the stack for the new thread.
- ///
- /// The stack size is measured in bytes.
- ///
- /// For more information about the stack size for threads, see [here][stack-size].
- ///
- /// # Examples
- ///
- /// ```
- /// use crossbeam_utils::thread;
- ///
- /// thread::scope(|s| {
- /// s.builder()
- /// .stack_size(32 * 1024)
- /// .spawn(|_| println!("Running a child thread"))
- /// .unwrap();
- /// }).unwrap();
- /// ```
- ///
- /// [stack-size]: std::thread#stack-size
- pub fn stack_size(mut self, size: usize) -> ScopedThreadBuilder<'scope, 'env> {
- self.builder = self.builder.stack_size(size);
- self
- }
-
- /// Spawns a scoped thread with this configuration.
- ///
- /// The scoped thread is passed a reference to this scope as an argument, which can be used for
- /// spawning nested threads.
- ///
- /// The returned handle can be used to manually join the thread before the scope exits.
- ///
- /// # Errors
- ///
- /// Unlike the [`Scope::spawn`] method, this method yields an
- /// [`io::Result`] to capture any failure to create the thread at
- /// the OS level.
- ///
- /// [`io::Result`]: std::io::Result
- ///
- /// # Panics
- ///
- /// Panics if a thread name was set and it contained null bytes.
- ///
- /// # Examples
- ///
- /// ```
- /// use crossbeam_utils::thread;
- ///
- /// thread::scope(|s| {
- /// let handle = s.builder()
- /// .spawn(|_| {
- /// println!("A child thread is running");
- /// 42
- /// })
- /// .unwrap();
- ///
- /// // Join the thread and retrieve its result.
- /// let res = handle.join().unwrap();
- /// assert_eq!(res, 42);
- /// }).unwrap();
- /// ```
- pub fn spawn<F, T>(self, f: F) -> io::Result<ScopedJoinHandle<'scope, T>>
- where
- F: FnOnce(&Scope<'env>) -> T,
- F: Send + 'env,
- T: Send + 'env,
- {
- // The result of `f` will be stored here.
- let result = SharedOption::default();
-
- // Spawn the thread and grab its join handle and thread handle.
- let (handle, thread) = {
- let result = Arc::clone(&result);
-
- // A clone of the scope that will be moved into the new thread.
- let scope = Scope::<'env> {
- handles: Arc::clone(&self.scope.handles),
- wait_group: self.scope.wait_group.clone(),
- _marker: PhantomData,
- };
-
- // Spawn the thread.
- let handle = {
- let closure = move || {
- // Make sure the scope is inside the closure with the proper `'env` lifetime.
- let scope: Scope<'env> = scope;
-
- // Run the closure.
- let res = f(&scope);
-
- // Store the result if the closure didn't panic.
- *result.lock().unwrap() = Some(res);
- };
-
- // Allocate `closure` on the heap and erase the `'env` bound.
- let closure: Box<dyn FnOnce() + Send + 'env> = Box::new(closure);
- let closure: Box<dyn FnOnce() + Send + 'static> =
- unsafe { mem::transmute(closure) };
-
- // Finally, spawn the closure.
- self.builder.spawn(closure)?
- };
-
- let thread = handle.thread().clone();
- let handle = Arc::new(Mutex::new(Some(handle)));
- (handle, thread)
- };
-
- // Add the handle to the shared list of join handles.
- self.scope.handles.lock().unwrap().push(Arc::clone(&handle));
-
- Ok(ScopedJoinHandle {
- handle,
- result,
- thread,
- _marker: PhantomData,
- })
- }
-}
-
-unsafe impl<T> Send for ScopedJoinHandle<'_, T> {}
-unsafe impl<T> Sync for ScopedJoinHandle<'_, T> {}
-
-/// A handle that can be used to join its scoped thread.
-///
-/// This struct is created by the [`Scope::spawn`] method and the
-/// [`ScopedThreadBuilder::spawn`] method.
-pub struct ScopedJoinHandle<'scope, T> {
- /// A join handle to the spawned thread.
- handle: SharedOption<thread::JoinHandle<()>>,
-
- /// Holds the result of the inner closure.
- result: SharedOption<T>,
-
- /// A handle to the the spawned thread.
- thread: thread::Thread,
-
- /// Borrows the parent scope with lifetime `'scope`.
- _marker: PhantomData<&'scope ()>,
-}
-
-impl<T> ScopedJoinHandle<'_, T> {
- /// Waits for the thread to finish and returns its result.
- ///
- /// If the child thread panics, an error is returned. Note that if panics are implemented by
- /// aborting the process, no error is returned; see the notes of [std::panic::catch_unwind].
- ///
- /// # Panics
- ///
- /// This function may panic on some platforms if a thread attempts to join itself or otherwise
- /// may create a deadlock with joining threads.
- ///
- /// # Examples
- ///
- /// ```
- /// use crossbeam_utils::thread;
- ///
- /// thread::scope(|s| {
- /// let handle1 = s.spawn(|_| println!("I'm a happy thread :)"));
- /// let handle2 = s.spawn(|_| panic!("I'm a sad thread :("));
- ///
- /// // Join the first thread and verify that it succeeded.
- /// let res = handle1.join();
- /// assert!(res.is_ok());
- ///
- /// // Join the second thread and verify that it panicked.
- /// let res = handle2.join();
- /// assert!(res.is_err());
- /// }).unwrap();
- /// ```
- pub fn join(self) -> thread::Result<T> {
- // Take out the handle. The handle will surely be available because the root scope waits
- // for nested scopes before joining remaining threads.
- let handle = self.handle.lock().unwrap().take().unwrap();
-
- // Join the thread and then take the result out of its inner closure.
- handle
- .join()
- .map(|()| self.result.lock().unwrap().take().unwrap())
- }
-
- /// Returns a handle to the underlying thread.
- ///
- /// # Examples
- ///
- /// ```
- /// use crossbeam_utils::thread;
- ///
- /// thread::scope(|s| {
- /// let handle = s.spawn(|_| println!("A child thread is running"));
- /// println!("The child thread ID: {:?}", handle.thread().id());
- /// }).unwrap();
- /// ```
- pub fn thread(&self) -> &thread::Thread {
- &self.thread
- }
-}
-
-cfg_if! {
- if #[cfg(unix)] {
- use std::os::unix::thread::{JoinHandleExt, RawPthread};
-
- impl<T> JoinHandleExt for ScopedJoinHandle<'_, T> {
- fn as_pthread_t(&self) -> RawPthread {
- // Borrow the handle. The handle will surely be available because the root scope waits
- // for nested scopes before joining remaining threads.
- let handle = self.handle.lock().unwrap();
- handle.as_ref().unwrap().as_pthread_t()
- }
- fn into_pthread_t(self) -> RawPthread {
- self.as_pthread_t()
- }
- }
- } else if #[cfg(windows)] {
- use std::os::windows::io::{AsRawHandle, IntoRawHandle, RawHandle};
-
- impl<T> AsRawHandle for ScopedJoinHandle<'_, T> {
- fn as_raw_handle(&self) -> RawHandle {
- // Borrow the handle. The handle will surely be available because the root scope waits
- // for nested scopes before joining remaining threads.
- let handle = self.handle.lock().unwrap();
- handle.as_ref().unwrap().as_raw_handle()
- }
- }
-
- impl<T> IntoRawHandle for ScopedJoinHandle<'_, T> {
- fn into_raw_handle(self) -> RawHandle {
- self.as_raw_handle()
- }
- }
- }
-}
-
-impl<T> fmt::Debug for ScopedJoinHandle<'_, T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.pad("ScopedJoinHandle { .. }")
- }
-}