diff --git a/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs index 2c71fb8afeede..ca3550e9278d1 100644 --- a/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs @@ -2,7 +2,7 @@ use crate::spec::{FramePointer, LinkerFlavor, SanitizerSet, Target, TargetOption pub fn target() -> Target { let mut base = super::apple_base::opts("macos"); - base.cpu = "apple-a12".to_string(); + base.cpu = "apple-a14".to_string(); base.max_atomic_width = Some(128); // FIXME: The leak sanitizer currently fails the tests, see #88132. diff --git a/library/std/src/sys/windows/thread_local_dtor.rs b/library/std/src/sys/windows/thread_local_dtor.rs index 7be13bc4b2bc7..25d1c6e8e87c2 100644 --- a/library/std/src/sys/windows/thread_local_dtor.rs +++ b/library/std/src/sys/windows/thread_local_dtor.rs @@ -1,4 +1,28 @@ +//! Implements thread-local destructors that are not associated with any +//! particular data. + #![unstable(feature = "thread_local_internals", issue = "none")] #![cfg(target_thread_local)] -pub use crate::sys_common::thread_local_dtor::register_dtor_fallback as register_dtor; +// Using a per-thread list avoids the problems in synchronizing global state. +#[thread_local] +static mut DESTRUCTORS: Vec<(*mut u8, unsafe extern "C" fn(*mut u8))> = Vec::new(); + +pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { + DESTRUCTORS.push((t, dtor)); +} + +/// Runs destructors. This should not be called until thread exit. +pub unsafe fn run_keyless_dtors() { + // Drop all the destructors. + // + // Note: While this is potentially an infinite loop, it *should* be + // the case that this loop always terminates because we provide the + // guarantee that a TLS key cannot be set after it is flagged for + // destruction. + while let Some((ptr, dtor)) = DESTRUCTORS.pop() { + (dtor)(ptr); + } + // We're done so free the memory. + DESTRUCTORS = Vec::new(); +} diff --git a/library/std/src/sys/windows/thread_local_key.rs b/library/std/src/sys/windows/thread_local_key.rs index 0bc511146654b..ec670238e6f0e 100644 --- a/library/std/src/sys/windows/thread_local_key.rs +++ b/library/std/src/sys/windows/thread_local_key.rs @@ -196,6 +196,8 @@ pub static p_thread_callback: unsafe extern "system" fn(c::LPVOID, c::DWORD, c:: unsafe extern "system" fn on_tls_callback(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID) { if dwReason == c::DLL_THREAD_DETACH || dwReason == c::DLL_PROCESS_DETACH { run_dtors(); + #[cfg(target_thread_local)] + super::thread_local_dtor::run_keyless_dtors(); } // See comments above for what this is doing. Note that we don't need this diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index e7944c715ed6f..2a155ce311731 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -1407,6 +1407,15 @@ impl JoinHandle { pub fn join(mut self) -> Result { self.0.join() } + + /// Checks if the the associated thread is still running its main function. + /// + /// This might return `false` for a brief moment after the thread's main + /// function has returned, but before the thread itself has stopped running. + #[unstable(feature = "thread_is_running", issue = "90470")] + pub fn is_running(&self) -> bool { + Arc::strong_count(&self.0.packet.0) > 1 + } } impl AsInner for JoinHandle { diff --git a/library/std/src/thread/tests.rs b/library/std/src/thread/tests.rs index 16ad366fc126a..ca0d88135a5d8 100644 --- a/library/std/src/thread/tests.rs +++ b/library/std/src/thread/tests.rs @@ -2,9 +2,13 @@ use super::Builder; use crate::any::Any; use crate::mem; use crate::result; -use crate::sync::mpsc::{channel, Sender}; +use crate::sync::{ + mpsc::{channel, Sender}, + Arc, Barrier, +}; use crate::thread::{self, ThreadId}; use crate::time::Duration; +use crate::time::Instant; // !!! These tests are dangerous. If something is buggy, they will hang, !!! // !!! instead of exiting cleanly. This might wedge the buildbots. !!! @@ -46,6 +50,36 @@ fn test_run_basic() { rx.recv().unwrap(); } +#[test] +fn test_is_running() { + let b = Arc::new(Barrier::new(2)); + let t = thread::spawn({ + let b = b.clone(); + move || { + b.wait(); + 1234 + } + }); + + // Thread is definitely running here, since it's still waiting for the barrier. + assert_eq!(t.is_running(), true); + + // Unblock the barrier. + b.wait(); + + // Now check that t.is_running() becomes false within a reasonable time. + let start = Instant::now(); + while t.is_running() { + assert!(start.elapsed() < Duration::from_secs(2)); + thread::sleep(Duration::from_millis(15)); + } + + // Joining the thread should not block for a significant time now. + let join_time = Instant::now(); + assert_eq!(t.join().unwrap(), 1234); + assert!(join_time.elapsed() < Duration::from_secs(2)); +} + #[test] fn test_join_panic() { match thread::spawn(move || panic!()).join() { diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index d5656f0f37e03..6ba1b1b6036ea 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -482,6 +482,7 @@ impl<'a> Builder<'a> { doc::RustByExample, doc::RustcBook, doc::CargoBook, + doc::Clippy, doc::EmbeddedBook, doc::EditionGuide, ), diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 6f2470b706a64..2804e7119fbc1 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -755,6 +755,7 @@ tool_doc!( "src/tools/rustfmt", ["rustfmt-nightly", "rustfmt-config_proc_macro"], ); +tool_doc!(Clippy, "clippy", "src/tools/clippy", ["clippy_utils"]); #[derive(Ord, PartialOrd, Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct ErrorIndex { diff --git a/src/doc/unstable-book/src/library-features/asm.md b/src/doc/unstable-book/src/library-features/asm.md index bd7234522e1fe..6bf21e8f58b25 100644 --- a/src/doc/unstable-book/src/library-features/asm.md +++ b/src/doc/unstable-book/src/library-features/asm.md @@ -257,7 +257,7 @@ unsafe { } println!( - "L1 Cache: {}", + "L0 Cache: {}", ((ebx >> 22) + 1) * (((ebx >> 12) & 0x3ff) + 1) * ((ebx & 0xfff) + 1) * (ecx + 1) ); ```