From 397569503e080c71628f8dcb053132e322e4aa04 Mon Sep 17 00:00:00 2001 From: David Roundy Date: Sun, 18 Oct 2026 13:42:40 -0700 Subject: [PATCH] Split spin_wait into std and no_std versions Instead of one function that mixes cfg! in its condition, a cfg attribute on the yield, and a min(3) that only the no_std path needs, define spin_wait once for each configuration. Behavior is unchanged. Co-Authored-By: Claude Opus 5.5 --- src/lib.rs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 6e19cdb..123f78a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -101,14 +101,14 @@ const fn bin_size(array: u32) -> usize { (1 << 3) << array } +#[cfg(feature = "std")] fn spin_wait(failures: &mut usize) { // Saturate, since a long enough wait would overflow a 32-bit counter. *failures = failures.saturating_add(1); - if *failures <= 3 || cfg!(not(feature = "std")) { + if *failures <= 3 { // If there haven't been many failures yet, then we optimistically - // spinloop. Without `std` there is no scheduler to yield to, so we - // always spin. - for _ in 0..(1 << (*failures).min(3)) { + // spinloop. + for _ in 0..(1 << *failures) { core::hint::spin_loop(); } } else { @@ -116,11 +116,20 @@ fn spin_wait(failures: &mut usize) { // probably just waste CPU, and whoever we are waiting for has been // preempted then spinning could actively delay completion of the task. // So instead, we cooperatively yield to the OS scheduler. - #[cfg(feature = "std")] std::thread::yield_now(); } } +/// Without `std` there is no scheduler to yield to, so we always spin, backing +/// off up to 8 spins per call. +#[cfg(not(feature = "std"))] +fn spin_wait(failures: &mut usize) { + *failures = (*failures + 1).min(3); + for _ in 0..(1 << *failures) { + core::hint::spin_loop(); + } +} + #[test] fn test_indices() { for i in 0..32 {