From e8b5be5dffef9ef6a15a085e4b06c4a0471f360d Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Sun, 30 Aug 2020 10:35:50 +0800 Subject: [PATCH] Stabilize hint::spin_loop Partially fix #55002, deprecate in another release Co-authored-by: Ashley Mannix Update stable version for stabilize_spin_loop Co-authored-by: Joshua Nelson Use better example for spinlock As suggested by KodrAus Remove renamed_spin_loop already available in master Fix spin loop example --- library/alloc/src/lib.rs | 1 - library/core/src/hint.rs | 62 ++++++++++++++++++++++++++++----- library/core/src/sync/atomic.rs | 16 ++------- library/std/src/lib.rs | 1 - 4 files changed, 56 insertions(+), 24 deletions(-) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 0fe15958076c5..ccabc336acc16 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -119,7 +119,6 @@ #![feature(raw_ref_op)] #![feature(rustc_attrs)] #![feature(receiver_trait)] -#![feature(renamed_spin_loop)] #![feature(min_specialization)] #![feature(slice_ptr_get)] #![feature(slice_ptr_len)] diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 454fb34e77e49..979a5f8cf5075 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -1,6 +1,7 @@ #![stable(feature = "core_hint", since = "1.27.0")] //! Hints to compiler that affects how code should be emitted or optimized. +//! Hints may be compile time or runtime. use crate::intrinsics; @@ -24,7 +25,6 @@ use crate::intrinsics; /// Otherwise, consider using the [`unreachable!`] macro, which does not allow /// optimizations but will panic when executed. /// -/// /// # Example /// /// ``` @@ -51,18 +51,62 @@ pub const unsafe fn unreachable_unchecked() -> ! { unsafe { intrinsics::unreachable() } } -/// Emits a machine instruction hinting to the processor that it is running in busy-wait -/// spin-loop ("spin lock"). +/// Emits a machine instruction to signal the processor that it is running in +/// a busy-wait spin-loop ("spin lock"). +/// +/// Upon receiving the spin-loop signal the processor can optimize its behavior by, +/// for example, saving power or switching hyper-threads. +/// +/// This function is different from [`thread::yield_now`] which directly +/// yields to the system's scheduler, whereas `spin_loop` does not interact +/// with the operating system. +/// +/// A common use case for `spin_loop` is implementing bounded optimistic +/// spinning in a CAS loop in synchronization primitives. To avoid problems +/// like priority inversion, it is strongly recommended that the spin loop is +/// terminated after a finite amount of iterations and an appropriate blocking +/// syscall is made. +/// +/// **Note**: On platforms that do not support receiving spin-loop hints this +/// function does not do anything at all. +/// +/// # Examples /// -/// For a discussion of different locking strategies and their trade-offs, see -/// [`core::sync::atomic::spin_loop_hint`]. +/// ``` +/// use std::sync::atomic::{AtomicBool, Ordering}; +/// use std::sync::Arc; +/// use std::{hint, thread}; +/// +/// // A shared atomic value that threads will use to coordinate +/// let live = Arc::new(AtomicBool::new(false)); +/// +/// // In a background thread we'll eventually set the value +/// let bg_work = { +/// let live = live.clone(); +/// thread::spawn(move || { +/// // Do some work, then make the value live +/// do_some_work(); +/// live.store(true, Ordering::Release); +/// }) +/// }; /// -/// **Note**: On platforms that do not support receiving spin-loop hints this function does not -/// do anything at all. +/// // Back on our current thread, we wait for the value to be set +/// while live.load(Ordering::Acquire) { +/// // The spin loop is a hint to the CPU that we're waiting, but probably +/// // not for very long +/// hint::spin_loop(); +/// } +/// +/// // The value is now set +/// # fn do_some_work() {} +/// do_some_work(); +/// bg_work.join()?; +/// # Ok::<(), Box>(()) +/// ``` /// -/// [`core::sync::atomic::spin_loop_hint`]: crate::sync::atomic::spin_loop_hint +/// [`thread::yield_now`]: ../../std/thread/fn.yield_now.html #[inline] -#[unstable(feature = "renamed_spin_loop", issue = "55002")] +#[stable(feature = "renamed_spin_loop", since = "1.49.0")] pub fn spin_loop() { #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "sse2"))] { diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 5c9cfe27101f0..5dbea6e71aa4f 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -115,23 +115,13 @@ use crate::hint::spin_loop; /// Signals the processor that it is inside a busy-wait spin-loop ("spin lock"). /// -/// Upon receiving spin-loop signal the processor can optimize its behavior by, for example, saving -/// power or switching hyper-threads. -/// -/// This function is different from [`std::thread::yield_now`] which directly yields to the -/// system's scheduler, whereas `spin_loop_hint` does not interact with the operating system. -/// -/// A common use case for `spin_loop_hint` is implementing bounded optimistic spinning in a CAS -/// loop in synchronization primitives. To avoid problems like priority inversion, it is strongly -/// recommended that the spin loop is terminated after a finite amount of iterations and an -/// appropriate blocking syscall is made. +/// This function is expected to be deprecated in favor of +/// [`hint::spin_loop`]. /// /// **Note**: On platforms that do not support receiving spin-loop hints this function does not /// do anything at all. /// -/// [`std::thread::yield_now`]: ../../../std/thread/fn.yield_now.html -/// [`std::thread::sleep`]: ../../../std/thread/fn.sleep.html -/// [`std::sync::Mutex`]: ../../../std/sync/struct.Mutex.html +/// [`hint::spin_loop`]: crate::hint::spin_loop #[inline] #[stable(feature = "spin_loop_hint", since = "1.24.0")] pub fn spin_loop_hint() { diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 96a7755c68821..1636fe5e2575a 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -296,7 +296,6 @@ #![feature(raw)] #![feature(raw_ref_macros)] #![feature(ready_macro)] -#![feature(renamed_spin_loop)] #![feature(rustc_attrs)] #![feature(rustc_private)] #![feature(shrink_to)]