diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4c6e28615..b664218f1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,9 +40,9 @@ jobs: matrix: # aarch64/x86_64 macOS and aarch64 Linux are tested on Cirrus CI include: - - rust: '1.38' + - rust: '1.61' os: ubuntu-latest - - rust: '1.38' + - rust: '1.61' os: windows-latest - rust: stable os: ubuntu-latest @@ -83,7 +83,7 @@ jobs: fail-fast: false matrix: rust: - - '1.38' + - '1.61' - nightly runs-on: ubuntu-latest steps: diff --git a/Cargo.toml b/Cargo.toml index 905c8ded6..fd27d492b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ name = "crossbeam" # - Create "crossbeam-X.Y.Z" git tag version = "0.8.2" edition = "2018" -rust-version = "1.38" +rust-version = "1.61" license = "MIT OR Apache-2.0" repository = "https://github.com/crossbeam-rs/crossbeam" homepage = "https://github.com/crossbeam-rs/crossbeam" diff --git a/README.md b/README.md index e44df6b88..264f373ea 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ https://github.com/crossbeam-rs/crossbeam#license) https://crates.io/crates/crossbeam) [![Documentation](https://docs.rs/crossbeam/badge.svg)]( https://docs.rs/crossbeam) -[![Rust 1.38+](https://img.shields.io/badge/rust-1.38+-lightgray.svg)]( +[![Rust 1.61+](https://img.shields.io/badge/rust-1.61+-lightgray.svg)]( https://www.rust-lang.org) [![chat](https://img.shields.io/discord/569610676205781012.svg?logo=discord)](https://discord.com/invite/JXYwgWZ) @@ -94,7 +94,7 @@ crossbeam = "0.8" Crossbeam supports stable Rust releases going back at least six months, and every time the minimum supported Rust version is increased, a new minor -version is released. Currently, the minimum supported Rust version is 1.38. +version is released. Currently, the minimum supported Rust version is 1.61. ## Contributing diff --git a/ci/miri.sh b/ci/miri.sh index 7babbde9a..c42943e22 100755 --- a/ci/miri.sh +++ b/ci/miri.sh @@ -11,14 +11,16 @@ export RUSTFLAGS="${RUSTFLAGS:-} -Z randomize-layout" export RUSTDOCFLAGS="${RUSTDOCFLAGS:-} -Z randomize-layout" MIRIFLAGS="-Zmiri-strict-provenance -Zmiri-symbolic-alignment-check -Zmiri-disable-isolation" \ + MIRI_LEAK_CHECK='1' \ cargo miri test \ + -p crossbeam-channel \ -p crossbeam-queue \ -p crossbeam-utils 2>&1 | ts -i '%.s ' -# -Zmiri-ignore-leaks is needed because we use detached threads in tests/docs: https://github.com/rust-lang/miri/issues/1371 +# -Zmiri-ignore-leaks is needed because we use detached threads in tests in tests/golang.rs: https://github.com/rust-lang/miri/issues/1371 MIRIFLAGS="-Zmiri-strict-provenance -Zmiri-symbolic-alignment-check -Zmiri-disable-isolation -Zmiri-ignore-leaks" \ cargo miri test \ - -p crossbeam-channel 2>&1 | ts -i '%.s ' + -p crossbeam-channel --test golang 2>&1 | ts -i '%.s ' # Use Tree Borrows instead of Stacked Borrows because epoch is not compatible with Stacked Borrows: https://github.com/crossbeam-rs/crossbeam/issues/545#issuecomment-1192785003 MIRIFLAGS="-Zmiri-strict-provenance -Zmiri-symbolic-alignment-check -Zmiri-disable-isolation -Zmiri-tree-borrows" \ diff --git a/ci/no_atomic.sh b/ci/no_atomic.sh index b3c617c76..44bd008ba 100755 --- a/ci/no_atomic.sh +++ b/ci/no_atomic.sh @@ -10,28 +10,26 @@ cd "$(dirname "$0")"/.. file="no_atomic.rs" -no_atomic_cas=() -no_atomic_64=() no_atomic=() -for target in $(rustc --print target-list); do - target_spec=$(rustc --print target-spec-json -Z unstable-options --target "${target}") +for target_spec in $(rustc -Z unstable-options --print all-target-specs-json | jq -c '. | to_entries | .[]'); do + target=$(jq <<<"${target_spec}" -r '.key') + target_spec=$(jq <<<"${target_spec}" -c '.value') res=$(jq <<<"${target_spec}" -r 'select(."atomic-cas" == false)') [[ -z "${res}" ]] || no_atomic_cas+=("${target}") max_atomic_width=$(jq <<<"${target_spec}" -r '."max-atomic-width"') min_atomic_width=$(jq <<<"${target_spec}" -r '."min-atomic-width"') case "${max_atomic_width}" in + # `"max-atomic-width" == 0` means that atomic is not supported at all. + # We do not have a cfg for targets with {8,16}-bit atomic only, so + # for now we treat them the same as targets that do not support atomic. + 0) no_atomic+=("${target}") ;; # It is not clear exactly what `"max-atomic-width" == null` means, but they # actually seem to have the same max-atomic-width as the target-pointer-width. # The targets currently included in this group are "mipsel-sony-psp", # "thumbv4t-none-eabi", "thumbv6m-none-eabi", all of which are # `"target-pointer-width" == "32"`, so assuming them `"max-atomic-width" == 32` # for now. - 32 | null) no_atomic_64+=("${target}") ;; - # `"max-atomic-width" == 0` means that atomic is not supported at all. - # We do not have a cfg for targets with {8,16}-bit atomic only, so - # for now we treat them the same as targets that do not support atomic. - 0 | 8 | 16) no_atomic+=("${target}") ;; - 64 | 128) ;; + null | 8 | 16 | 32 | 64 | 128) ;; *) exit 1 ;; esac case "${min_atomic_width}" in @@ -44,24 +42,6 @@ cat >"${file}" <>"${file}" -done -cat >>"${file}" <>"${file}" -done -cat >>"${file}" < io::Result> { let (s, r) = bounded(100); - let mut signals = Signals::new(&[SIGINT])?; + let mut signals = Signals::new([SIGINT])?; thread::spawn(move || { for _ in signals.forever() { diff --git a/crossbeam-channel/src/channel.rs b/crossbeam-channel/src/channel.rs index 61aefc2ce..b08461298 100644 --- a/crossbeam-channel/src/channel.rs +++ b/crossbeam-channel/src/channel.rs @@ -248,6 +248,7 @@ pub fn at(when: Instant) -> Receiver { /// /// let (s, r) = unbounded(); /// +/// # let t = /// thread::spawn(move || { /// thread::sleep(Duration::from_secs(1)); /// s.send(1).unwrap(); @@ -265,6 +266,7 @@ pub fn at(when: Instant) -> Receiver { /// recv(r) -> msg => assert_eq!(msg, Ok(1)), /// recv(timeout) -> _ => println!("timed out"), /// } +/// # t.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371 /// ``` pub fn never() -> Receiver { Receiver { @@ -1103,6 +1105,7 @@ impl Receiver { /// /// let (s, r) = unbounded::(); /// + /// # let t = /// thread::spawn(move || { /// s.send(1).unwrap(); /// thread::sleep(Duration::from_secs(1)); @@ -1118,6 +1121,7 @@ impl Receiver { /// let v: Vec<_> = r.try_iter().collect(); /// /// assert_eq!(v, [1, 2]); + /// # t.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371 /// ``` pub fn try_iter(&self) -> TryIter<'_, T> { TryIter { receiver: self } @@ -1269,6 +1273,7 @@ impl fmt::Debug for Iter<'_, T> { /// /// let (s, r) = unbounded::(); /// +/// # let t = /// thread::spawn(move || { /// s.send(1).unwrap(); /// thread::sleep(Duration::from_secs(1)); @@ -1284,6 +1289,7 @@ impl fmt::Debug for Iter<'_, T> { /// let v: Vec<_> = r.try_iter().collect(); /// /// assert_eq!(v, [1, 2]); +/// # t.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371 /// ``` pub struct TryIter<'a, T> { receiver: &'a Receiver, diff --git a/crossbeam-channel/src/err.rs b/crossbeam-channel/src/err.rs index 18cb8307a..293e13b3a 100644 --- a/crossbeam-channel/src/err.rs +++ b/crossbeam-channel/src/err.rs @@ -200,18 +200,12 @@ impl TrySendError { /// Returns `true` if the send operation failed because the channel is full. pub fn is_full(&self) -> bool { - match self { - TrySendError::Full(_) => true, - _ => false, - } + matches!(self, TrySendError::Full(_)) } /// Returns `true` if the send operation failed because the channel is disconnected. pub fn is_disconnected(&self) -> bool { - match self { - TrySendError::Disconnected(_) => true, - _ => false, - } + matches!(self, TrySendError::Disconnected(_)) } } @@ -264,18 +258,12 @@ impl SendTimeoutError { /// Returns `true` if the send operation timed out. pub fn is_timeout(&self) -> bool { - match self { - SendTimeoutError::Timeout(_) => true, - _ => false, - } + matches!(self, SendTimeoutError::Timeout(_)) } /// Returns `true` if the send operation failed because the channel is disconnected. pub fn is_disconnected(&self) -> bool { - match self { - SendTimeoutError::Disconnected(_) => true, - _ => false, - } + matches!(self, SendTimeoutError::Disconnected(_)) } } @@ -309,18 +297,12 @@ impl From for TryRecvError { impl TryRecvError { /// Returns `true` if the receive operation failed because the channel is empty. pub fn is_empty(&self) -> bool { - match self { - TryRecvError::Empty => true, - _ => false, - } + matches!(self, TryRecvError::Empty) } /// Returns `true` if the receive operation failed because the channel is disconnected. pub fn is_disconnected(&self) -> bool { - match self { - TryRecvError::Disconnected => true, - _ => false, - } + matches!(self, TryRecvError::Disconnected) } } @@ -346,18 +328,12 @@ impl From for RecvTimeoutError { impl RecvTimeoutError { /// Returns `true` if the receive operation timed out. pub fn is_timeout(&self) -> bool { - match self { - RecvTimeoutError::Timeout => true, - _ => false, - } + matches!(self, RecvTimeoutError::Timeout) } /// Returns `true` if the receive operation failed because the channel is disconnected. pub fn is_disconnected(&self) -> bool { - match self { - RecvTimeoutError::Disconnected => true, - _ => false, - } + matches!(self, RecvTimeoutError::Disconnected) } } diff --git a/crossbeam-channel/src/lib.rs b/crossbeam-channel/src/lib.rs index cc1ef112f..74cc66c2d 100644 --- a/crossbeam-channel/src/lib.rs +++ b/crossbeam-channel/src/lib.rs @@ -273,7 +273,9 @@ //! let (s1, r1) = unbounded(); //! let (s2, r2) = unbounded(); //! +//! # let t1 = //! thread::spawn(move || s1.send(10).unwrap()); +//! # let t2 = //! thread::spawn(move || s2.send(20).unwrap()); //! //! // At most one of these two receive operations will be executed. @@ -282,6 +284,8 @@ //! recv(r2) -> msg => assert_eq!(msg, Ok(20)), //! default(Duration::from_secs(1)) => println!("timed out"), //! } +//! # t1.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371 +//! # t2.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371 //! ``` //! //! If you need to select over a dynamically created list of channel operations, use [`Select`] diff --git a/crossbeam-channel/src/select.rs b/crossbeam-channel/src/select.rs index 3eb0b97c8..7546b5b70 100644 --- a/crossbeam-channel/src/select.rs +++ b/crossbeam-channel/src/select.rs @@ -79,10 +79,10 @@ impl From for Selected { } } -impl Into for Selected { +impl From for usize { #[inline] - fn into(self) -> usize { - match self { + fn from(val: Selected) -> Self { + match val { Selected::Waiting => 0, Selected::Aborted => 1, Selected::Disconnected => 2, @@ -791,10 +791,12 @@ impl<'a> Select<'a> { /// let (s1, r1) = unbounded(); /// let (s2, r2) = unbounded(); /// + /// # let t1 = /// thread::spawn(move || { /// thread::sleep(Duration::from_secs(1)); /// s1.send(10).unwrap(); /// }); + /// # let t2 = /// thread::spawn(move || s2.send(20).unwrap()); /// /// let mut sel = Select::new(); @@ -808,6 +810,8 @@ impl<'a> Select<'a> { /// i if i == oper2 => assert_eq!(oper.recv(&r2), Ok(20)), /// _ => unreachable!(), /// } + /// # t1.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371 + /// # t2.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371 /// ``` pub fn select(&mut self) -> SelectedOperation<'a> { select(&mut self.handles) @@ -835,10 +839,12 @@ impl<'a> Select<'a> { /// let (s1, r1) = unbounded(); /// let (s2, r2) = unbounded(); /// + /// # let t1 = /// thread::spawn(move || { /// thread::sleep(Duration::from_secs(1)); /// s1.send(10).unwrap(); /// }); + /// # let t2 = /// thread::spawn(move || s2.send(20).unwrap()); /// /// let mut sel = Select::new(); @@ -855,6 +861,8 @@ impl<'a> Select<'a> { /// _ => unreachable!(), /// } /// } + /// # t1.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371 + /// # t2.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371 /// ``` pub fn select_timeout( &mut self, @@ -885,10 +893,12 @@ impl<'a> Select<'a> { /// let (s1, r1) = unbounded(); /// let (s2, r2) = unbounded(); /// + /// # let t1 = /// thread::spawn(move || { /// thread::sleep(Duration::from_secs(1)); /// s1.send(10).unwrap(); /// }); + /// # let t2 = /// thread::spawn(move || s2.send(20).unwrap()); /// /// let mut sel = Select::new(); @@ -907,6 +917,8 @@ impl<'a> Select<'a> { /// _ => unreachable!(), /// } /// } + /// # t1.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371 + /// # t2.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371 /// ``` pub fn select_deadline( &mut self, @@ -982,10 +994,12 @@ impl<'a> Select<'a> { /// let (s1, r1) = unbounded(); /// let (s2, r2) = unbounded(); /// + /// # let t1 = /// thread::spawn(move || { /// thread::sleep(Duration::from_secs(1)); /// s1.send(10).unwrap(); /// }); + /// # let t2 = /// thread::spawn(move || s2.send(20).unwrap()); /// /// let mut sel = Select::new(); @@ -998,6 +1012,8 @@ impl<'a> Select<'a> { /// i if i == oper2 => assert_eq!(r2.try_recv(), Ok(20)), /// _ => unreachable!(), /// } + /// # t1.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371 + /// # t2.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371 /// ``` pub fn ready(&mut self) -> usize { if self.handles.is_empty() { @@ -1029,10 +1045,12 @@ impl<'a> Select<'a> { /// let (s1, r1) = unbounded(); /// let (s2, r2) = unbounded(); /// + /// # let t1 = /// thread::spawn(move || { /// thread::sleep(Duration::from_secs(1)); /// s1.send(10).unwrap(); /// }); + /// # let t2 = /// thread::spawn(move || s2.send(20).unwrap()); /// /// let mut sel = Select::new(); @@ -1046,6 +1064,8 @@ impl<'a> Select<'a> { /// Ok(i) if i == oper2 => assert_eq!(r2.try_recv(), Ok(20)), /// Ok(_) => unreachable!(), /// } + /// # t1.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371 + /// # t2.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371 /// ``` pub fn ready_timeout(&mut self, timeout: Duration) -> Result { match Instant::now().checked_add(timeout) { @@ -1078,10 +1098,12 @@ impl<'a> Select<'a> { /// let (s1, r1) = unbounded(); /// let (s2, r2) = unbounded(); /// + /// # let t1 = /// thread::spawn(move || { /// thread::sleep(Duration::from_secs(1)); /// s1.send(10).unwrap(); /// }); + /// # let t2 = /// thread::spawn(move || s2.send(20).unwrap()); /// /// let mut sel = Select::new(); @@ -1095,6 +1117,8 @@ impl<'a> Select<'a> { /// Ok(i) if i == oper2 => assert_eq!(r2.try_recv(), Ok(20)), /// Ok(_) => unreachable!(), /// } + /// # t1.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371 + /// # t2.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371 /// ``` pub fn ready_deadline(&mut self, deadline: Instant) -> Result { match run_ready(&mut self.handles, Timeout::At(deadline)) { diff --git a/crossbeam-channel/src/select_macro.rs b/crossbeam-channel/src/select_macro.rs index efe0ae406..9ac87903d 100644 --- a/crossbeam-channel/src/select_macro.rs +++ b/crossbeam-channel/src/select_macro.rs @@ -1029,10 +1029,12 @@ macro_rules! crossbeam_channel_internal { /// let (s1, r1) = unbounded(); /// let (s2, r2) = unbounded(); /// +/// # let t1 = /// thread::spawn(move || { /// thread::sleep(Duration::from_secs(1)); /// s1.send(10).unwrap(); /// }); +/// # let t2 = /// thread::spawn(move || { /// thread::sleep(Duration::from_millis(500)); /// s2.send(20).unwrap(); @@ -1044,6 +1046,8 @@ macro_rules! crossbeam_channel_internal { /// recv(r2) -> msg => panic!(), /// default => println!("not ready"), /// } +/// # t1.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371 +/// # t2.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371 /// ``` /// /// Select over a set of operations with a timeout: @@ -1056,10 +1060,12 @@ macro_rules! crossbeam_channel_internal { /// let (s1, r1) = unbounded(); /// let (s2, r2) = unbounded(); /// +/// # let t1 = /// thread::spawn(move || { /// thread::sleep(Duration::from_secs(1)); /// s1.send(10).unwrap(); /// }); +/// # let t2 = /// thread::spawn(move || { /// thread::sleep(Duration::from_millis(500)); /// s2.send(20).unwrap(); @@ -1071,6 +1077,8 @@ macro_rules! crossbeam_channel_internal { /// recv(r2) -> msg => panic!(), /// default(Duration::from_millis(100)) => println!("timed out"), /// } +/// # t1.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371 +/// # t2.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371 /// ``` /// /// Optionally add a receive operation to `select!` using [`never`]: @@ -1083,10 +1091,12 @@ macro_rules! crossbeam_channel_internal { /// let (s1, r1) = unbounded(); /// let (s2, r2) = unbounded(); /// +/// # let t1 = /// thread::spawn(move || { /// thread::sleep(Duration::from_secs(1)); /// s1.send(10).unwrap(); /// }); +/// # let t2 = /// thread::spawn(move || { /// thread::sleep(Duration::from_millis(500)); /// s2.send(20).unwrap(); @@ -1100,6 +1110,8 @@ macro_rules! crossbeam_channel_internal { /// recv(r1) -> msg => panic!(), /// recv(r2.unwrap_or(&never())) -> msg => assert_eq!(msg, Ok(20)), /// } +/// # t1.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371 +/// # t2.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371 /// ``` /// /// To optionally add a timeout to `select!`, see the [example] for [`never`]. diff --git a/crossbeam-channel/tests/golang.rs b/crossbeam-channel/tests/golang.rs index e5b081e13..19865badc 100644 --- a/crossbeam-channel/tests/golang.rs +++ b/crossbeam-channel/tests/golang.rs @@ -767,7 +767,7 @@ mod select2 { assert!( !(ALLOCATED.load(SeqCst) > alloc && (ALLOCATED.load(SeqCst) - alloc) > (N as usize + 10000)) - ) + ); } } @@ -869,6 +869,11 @@ mod select7 { #[test] fn main() { + // https://github.com/rust-lang/miri/issues/1371 + if option_env!("MIRI_LEAK_CHECK").is_some() { + return; + } + send1(recv1); send2(recv1); send3(recv1); @@ -916,6 +921,11 @@ mod sieve1 { #[test] fn main() { + // https://github.com/rust-lang/miri/issues/1371 + if option_env!("MIRI_LEAK_CHECK").is_some() { + return; + } + let primes = make::(1); go!(primes, sieve(primes)); @@ -2125,6 +2135,11 @@ mod chan1 { #[test] fn main() { + // https://github.com/rust-lang/miri/issues/1371 + if option_env!("MIRI_LEAK_CHECK").is_some() { + return; + } + let h = Arc::new(Mutex::new([0usize; N])); let c = make::(W); for m in 0..M { diff --git a/crossbeam-channel/tests/mpsc.rs b/crossbeam-channel/tests/mpsc.rs index 0cea23393..b2c3a762a 100644 --- a/crossbeam-channel/tests/mpsc.rs +++ b/crossbeam-channel/tests/mpsc.rs @@ -330,7 +330,7 @@ mod channel_tests { for _ in 0..COUNT { assert_eq!(rx.recv().unwrap(), 1); } - t.join().ok().unwrap(); + t.join().unwrap(); } #[test] @@ -357,7 +357,7 @@ mod channel_tests { ts.push(t); } drop(tx); - t.join().ok().unwrap(); + t.join().unwrap(); for t in ts { t.join().unwrap(); } @@ -379,8 +379,8 @@ mod channel_tests { tx2.send(1).unwrap(); } }); - t1.join().ok().unwrap(); - t2.join().ok().unwrap(); + t1.join().unwrap(); + t2.join().unwrap(); } #[test] @@ -394,7 +394,7 @@ mod channel_tests { for _ in 0..40 { tx.send(1).unwrap(); } - t.join().ok().unwrap(); + t.join().unwrap(); } #[test] @@ -409,8 +409,8 @@ mod channel_tests { tx1.send(1).unwrap(); assert_eq!(rx2.recv().unwrap(), 2); }); - t1.join().ok().unwrap(); - t2.join().ok().unwrap(); + t1.join().unwrap(); + t2.join().unwrap(); } #[test] diff --git a/crossbeam-channel/tests/select_macro.rs b/crossbeam-channel/tests/select_macro.rs index ad10e99fe..c8b96c18d 100644 --- a/crossbeam-channel/tests/select_macro.rs +++ b/crossbeam-channel/tests/select_macro.rs @@ -965,6 +965,7 @@ fn references() { } } +#[allow(clippy::never_loop)] // This is intentional. #[test] fn case_blocks() { let (s, r) = unbounded::(); diff --git a/crossbeam-deque/Cargo.toml b/crossbeam-deque/Cargo.toml index 805a7e005..c25889c9e 100644 --- a/crossbeam-deque/Cargo.toml +++ b/crossbeam-deque/Cargo.toml @@ -6,7 +6,7 @@ name = "crossbeam-deque" # - Create "crossbeam-deque-X.Y.Z" git tag version = "0.8.3" edition = "2018" -rust-version = "1.38" +rust-version = "1.61" license = "MIT OR Apache-2.0" repository = "https://github.com/crossbeam-rs/crossbeam" homepage = "https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-deque" diff --git a/crossbeam-deque/README.md b/crossbeam-deque/README.md index 23c8794c2..4eae1447e 100644 --- a/crossbeam-deque/README.md +++ b/crossbeam-deque/README.md @@ -8,7 +8,7 @@ https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-deque#license) https://crates.io/crates/crossbeam-deque) [![Documentation](https://docs.rs/crossbeam-deque/badge.svg)]( https://docs.rs/crossbeam-deque) -[![Rust 1.38+](https://img.shields.io/badge/rust-1.38+-lightgray.svg)]( +[![Rust 1.61+](https://img.shields.io/badge/rust-1.61+-lightgray.svg)]( https://www.rust-lang.org) [![chat](https://img.shields.io/discord/569610676205781012.svg?logo=discord)](https://discord.com/invite/JXYwgWZ) @@ -28,7 +28,7 @@ crossbeam-deque = "0.8" Crossbeam Deque supports stable Rust releases going back at least six months, and every time the minimum supported Rust version is increased, a new minor -version is released. Currently, the minimum supported Rust version is 1.38. +version is released. Currently, the minimum supported Rust version is 1.61. ## License diff --git a/crossbeam-deque/src/deque.rs b/crossbeam-deque/src/deque.rs index c37de2dee..1356defb7 100644 --- a/crossbeam-deque/src/deque.rs +++ b/crossbeam-deque/src/deque.rs @@ -2056,10 +2056,7 @@ impl Steal { /// assert!(Empty::.is_empty()); /// ``` pub fn is_empty(&self) -> bool { - match self { - Steal::Empty => true, - _ => false, - } + matches!(self, Steal::Empty) } /// Returns `true` if at least one task was stolen. @@ -2075,10 +2072,7 @@ impl Steal { /// assert!(Success(7).is_success()); /// ``` pub fn is_success(&self) -> bool { - match self { - Steal::Success(_) => true, - _ => false, - } + matches!(self, Steal::Success(_)) } /// Returns `true` if the steal operation needs to be retried. @@ -2094,10 +2088,7 @@ impl Steal { /// assert!(Retry::.is_retry()); /// ``` pub fn is_retry(&self) -> bool { - match self { - Steal::Retry => true, - _ => false, - } + matches!(self, Steal::Retry) } /// Returns the result of the operation, if successful. diff --git a/crossbeam-epoch/Cargo.toml b/crossbeam-epoch/Cargo.toml index 68fc474fd..0c7e5b5db 100644 --- a/crossbeam-epoch/Cargo.toml +++ b/crossbeam-epoch/Cargo.toml @@ -6,7 +6,7 @@ name = "crossbeam-epoch" # - Create "crossbeam-epoch-X.Y.Z" git tag version = "0.9.15" edition = "2018" -rust-version = "1.38" +rust-version = "1.61" license = "MIT OR Apache-2.0" repository = "https://github.com/crossbeam-rs/crossbeam" homepage = "https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-epoch" @@ -55,4 +55,3 @@ default-features = false [dev-dependencies] rand = "0.8" -rustversion = "1" diff --git a/crossbeam-epoch/README.md b/crossbeam-epoch/README.md index 2840ea792..ba74c7c75 100644 --- a/crossbeam-epoch/README.md +++ b/crossbeam-epoch/README.md @@ -8,7 +8,7 @@ https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-epoch#license) https://crates.io/crates/crossbeam-epoch) [![Documentation](https://docs.rs/crossbeam-epoch/badge.svg)]( https://docs.rs/crossbeam-epoch) -[![Rust 1.38+](https://img.shields.io/badge/rust-1.38+-lightgray.svg)]( +[![Rust 1.61+](https://img.shields.io/badge/rust-1.61+-lightgray.svg)]( https://www.rust-lang.org) [![chat](https://img.shields.io/discord/569610676205781012.svg?logo=discord)](https://discord.com/invite/JXYwgWZ) @@ -35,7 +35,7 @@ crossbeam-epoch = "0.9" Crossbeam Epoch supports stable Rust releases going back at least six months, and every time the minimum supported Rust version is increased, a new minor -version is released. Currently, the minimum supported Rust version is 1.38. +version is released. Currently, the minimum supported Rust version is 1.61. ## License diff --git a/crossbeam-epoch/build-common.rs b/crossbeam-epoch/build-common.rs deleted file mode 120000 index 929510c73..000000000 --- a/crossbeam-epoch/build-common.rs +++ /dev/null @@ -1 +0,0 @@ -../build-common.rs \ No newline at end of file diff --git a/crossbeam-epoch/build.rs b/crossbeam-epoch/build.rs deleted file mode 100644 index 86c3b6ff7..000000000 --- a/crossbeam-epoch/build.rs +++ /dev/null @@ -1,57 +0,0 @@ -// The rustc-cfg listed below are considered public API, but it is *unstable* -// and outside of the normal semver guarantees: -// -// - `crossbeam_no_atomic_cas` -// Assume the target does *not* support atomic CAS operations. -// This is usually detected automatically by the build script, but you may -// need to enable it manually when building for custom targets or using -// non-cargo build systems that don't run the build script. -// -// With the exceptions mentioned above, the rustc-cfg emitted by the build -// script are *not* public API. - -#![warn(rust_2018_idioms)] - -use std::env; - -include!("no_atomic.rs"); -include!("build-common.rs"); - -fn main() { - println!("cargo:rerun-if-changed=no_atomic.rs"); - - let target = match env::var("TARGET") { - Ok(target) => convert_custom_linux_target(target), - Err(e) => { - println!( - "cargo:warning={}: unable to get TARGET environment variable: {}", - env!("CARGO_PKG_NAME"), - e - ); - return; - } - }; - - let cfg = match autocfg::AutoCfg::new() { - Ok(cfg) => cfg, - Err(e) => { - println!( - "cargo:warning={}: unable to determine rustc version: {}", - env!("CARGO_PKG_NAME"), - e - ); - return; - } - }; - - // Note that this is `no_`*, not `has_*`. This allows treating as the latest - // stable rustc is used when the build script doesn't run. This is useful - // for non-cargo build systems that don't run the build script. - if NO_ATOMIC_CAS.contains(&&*target) { - println!("cargo:rustc-cfg=crossbeam_no_atomic_cas"); - } - - if !cfg.probe_rustc_version(1, 61) { - println!("cargo:rustc-cfg=crossbeam_no_const_fn_trait_bound"); - } -} diff --git a/crossbeam-epoch/no_atomic.rs b/crossbeam-epoch/no_atomic.rs deleted file mode 120000 index 417886bb7..000000000 --- a/crossbeam-epoch/no_atomic.rs +++ /dev/null @@ -1 +0,0 @@ -../no_atomic.rs \ No newline at end of file diff --git a/crossbeam-epoch/src/atomic.rs b/crossbeam-epoch/src/atomic.rs index bdae84345..028b9bf9c 100644 --- a/crossbeam-epoch/src/atomic.rs +++ b/crossbeam-epoch/src/atomic.rs @@ -6,14 +6,13 @@ use core::mem::{self, MaybeUninit}; use core::ops::{Deref, DerefMut}; use core::ptr; use core::slice; -use core::sync::atomic::Ordering; use crate::alloc::alloc; use crate::alloc::boxed::Box; use crate::guard::Guard; -use crate::primitive::sync::atomic::AtomicPtr; #[cfg(not(miri))] use crate::primitive::sync::atomic::AtomicUsize; +use crate::primitive::sync::atomic::{AtomicPtr, Ordering}; use crossbeam_utils::atomic::AtomicConsume; /// Given ordering for the success case in a compare-exchange operation, returns the strongest @@ -303,16 +302,15 @@ impl Atomic { /// /// let a = Atomic::::null(); /// ``` - #[cfg(all(not(crossbeam_no_const_fn_trait_bound), not(crossbeam_loom)))] + #[cfg(not(crossbeam_loom))] pub const fn null() -> Atomic { Self { data: AtomicPtr::new(ptr::null_mut()), _marker: PhantomData, } } - /// Returns a new null atomic pointer. - #[cfg(not(all(not(crossbeam_no_const_fn_trait_bound), not(crossbeam_loom))))] + #[cfg(crossbeam_loom)] pub fn null() -> Atomic { Self { data: AtomicPtr::new(ptr::null_mut()), @@ -1585,7 +1583,6 @@ mod tests { Shared::::null().with_tag(7); } - #[rustversion::since(1.61)] #[test] fn const_atomic_null() { use super::Atomic; diff --git a/crossbeam-epoch/src/epoch.rs b/crossbeam-epoch/src/epoch.rs index 663508bd7..18d7418a1 100644 --- a/crossbeam-epoch/src/epoch.rs +++ b/crossbeam-epoch/src/epoch.rs @@ -7,8 +7,7 @@ //! If an object became garbage in some epoch, then we can be sure that after two advancements no //! participant will hold a reference to it. That is the crux of safe memory reclamation. -use crate::primitive::sync::atomic::AtomicUsize; -use core::sync::atomic::Ordering; +use crate::primitive::sync::atomic::{AtomicUsize, Ordering}; /// An epoch that can be marked as pinned or unpinned. /// diff --git a/crossbeam-epoch/src/internal.rs b/crossbeam-epoch/src/internal.rs index 79fbb9709..74d64808a 100644 --- a/crossbeam-epoch/src/internal.rs +++ b/crossbeam-epoch/src/internal.rs @@ -36,11 +36,10 @@ //! destroyed as soon as the data structure gets dropped. use crate::primitive::cell::UnsafeCell; -use crate::primitive::sync::atomic; +use crate::primitive::sync::atomic::{self, Ordering}; use core::cell::Cell; use core::mem::{self, ManuallyDrop}; use core::num::Wrapping; -use core::sync::atomic::Ordering; use core::{fmt, ptr}; use crossbeam_utils::CachePadded; diff --git a/crossbeam-epoch/src/lib.rs b/crossbeam-epoch/src/lib.rs index b7258f0e5..dff22f133 100644 --- a/crossbeam-epoch/src/lib.rs +++ b/crossbeam-epoch/src/lib.rs @@ -76,7 +76,7 @@ mod primitive { } pub(crate) mod sync { pub(crate) mod atomic { - pub(crate) use loom::sync::atomic::{fence, AtomicPtr, AtomicUsize}; + pub(crate) use loom::sync::atomic::{fence, AtomicPtr, AtomicUsize, Ordering}; // FIXME: loom does not support compiler_fence at the moment. // https://github.com/tokio-rs/loom/issues/117 @@ -89,7 +89,7 @@ mod primitive { } pub(crate) use loom::thread_local; } -#[cfg(not(crossbeam_no_atomic_cas))] +#[cfg(target_has_atomic = "ptr")] #[cfg(not(crossbeam_loom))] #[allow(unused_imports, dead_code)] mod primitive { @@ -122,7 +122,9 @@ mod primitive { } pub(crate) mod sync { pub(crate) mod atomic { - pub(crate) use core::sync::atomic::{compiler_fence, fence, AtomicPtr, AtomicUsize}; + pub(crate) use core::sync::atomic::{ + compiler_fence, fence, AtomicPtr, AtomicUsize, Ordering, + }; } #[cfg(feature = "alloc")] pub(crate) use alloc::sync::Arc; @@ -132,7 +134,7 @@ mod primitive { pub(crate) use std::thread_local; } -#[cfg(not(crossbeam_no_atomic_cas))] +#[cfg(target_has_atomic = "ptr")] cfg_if! { if #[cfg(feature = "alloc")] { extern crate alloc; diff --git a/crossbeam-queue/Cargo.toml b/crossbeam-queue/Cargo.toml index 72c6c7e2a..09be60e27 100644 --- a/crossbeam-queue/Cargo.toml +++ b/crossbeam-queue/Cargo.toml @@ -6,7 +6,7 @@ name = "crossbeam-queue" # - Create "crossbeam-queue-X.Y.Z" git tag version = "0.3.8" edition = "2018" -rust-version = "1.38" +rust-version = "1.61" license = "MIT OR Apache-2.0" repository = "https://github.com/crossbeam-rs/crossbeam" homepage = "https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-queue" diff --git a/crossbeam-queue/README.md b/crossbeam-queue/README.md index 238bcad32..0b698793d 100644 --- a/crossbeam-queue/README.md +++ b/crossbeam-queue/README.md @@ -8,7 +8,7 @@ https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-queue#license) https://crates.io/crates/crossbeam-queue) [![Documentation](https://docs.rs/crossbeam-queue/badge.svg)]( https://docs.rs/crossbeam-queue) -[![Rust 1.38+](https://img.shields.io/badge/rust-1.38+-lightgray.svg)]( +[![Rust 1.61+](https://img.shields.io/badge/rust-1.61+-lightgray.svg)]( https://www.rust-lang.org) [![chat](https://img.shields.io/discord/569610676205781012.svg?logo=discord)](https://discord.com/invite/JXYwgWZ) @@ -36,7 +36,7 @@ crossbeam-queue = "0.3" Crossbeam Queue supports stable Rust releases going back at least six months, and every time the minimum supported Rust version is increased, a new minor -version is released. Currently, the minimum supported Rust version is 1.38. +version is released. Currently, the minimum supported Rust version is 1.61. ## License diff --git a/crossbeam-queue/build-common.rs b/crossbeam-queue/build-common.rs deleted file mode 120000 index 929510c73..000000000 --- a/crossbeam-queue/build-common.rs +++ /dev/null @@ -1 +0,0 @@ -../build-common.rs \ No newline at end of file diff --git a/crossbeam-queue/build.rs b/crossbeam-queue/build.rs deleted file mode 100644 index ffa02a663..000000000 --- a/crossbeam-queue/build.rs +++ /dev/null @@ -1,41 +0,0 @@ -// The rustc-cfg listed below are considered public API, but it is *unstable* -// and outside of the normal semver guarantees: -// -// - `crossbeam_no_atomic_cas` -// Assume the target does *not* support atomic CAS operations. -// This is usually detected automatically by the build script, but you may -// need to enable it manually when building for custom targets or using -// non-cargo build systems that don't run the build script. -// -// With the exceptions mentioned above, the rustc-cfg emitted by the build -// script are *not* public API. - -#![warn(rust_2018_idioms)] - -use std::env; - -include!("no_atomic.rs"); -include!("build-common.rs"); - -fn main() { - println!("cargo:rerun-if-changed=no_atomic.rs"); - - let target = match env::var("TARGET") { - Ok(target) => convert_custom_linux_target(target), - Err(e) => { - println!( - "cargo:warning={}: unable to get TARGET environment variable: {}", - env!("CARGO_PKG_NAME"), - e - ); - return; - } - }; - - // Note that this is `no_`*, not `has_*`. This allows treating as the latest - // stable rustc is used when the build script doesn't run. This is useful - // for non-cargo build systems that don't run the build script. - if NO_ATOMIC_CAS.contains(&&*target) { - println!("cargo:rustc-cfg=crossbeam_no_atomic_cas"); - } -} diff --git a/crossbeam-queue/no_atomic.rs b/crossbeam-queue/no_atomic.rs deleted file mode 120000 index 417886bb7..000000000 --- a/crossbeam-queue/no_atomic.rs +++ /dev/null @@ -1 +0,0 @@ -../no_atomic.rs \ No newline at end of file diff --git a/crossbeam-queue/src/lib.rs b/crossbeam-queue/src/lib.rs index 846d7c2e1..36687282a 100644 --- a/crossbeam-queue/src/lib.rs +++ b/crossbeam-queue/src/lib.rs @@ -20,7 +20,7 @@ )] #![cfg_attr(not(feature = "std"), no_std)] -#[cfg(not(crossbeam_no_atomic_cas))] +#[cfg(target_has_atomic = "ptr")] cfg_if::cfg_if! { if #[cfg(feature = "alloc")] { extern crate alloc; diff --git a/crossbeam-skiplist/Cargo.toml b/crossbeam-skiplist/Cargo.toml index 76edc460e..776c558ff 100644 --- a/crossbeam-skiplist/Cargo.toml +++ b/crossbeam-skiplist/Cargo.toml @@ -6,7 +6,7 @@ name = "crossbeam-skiplist" # - Create "crossbeam-skiplist-X.Y.Z" git tag version = "0.1.1" edition = "2018" -rust-version = "1.38" +rust-version = "1.61" license = "MIT OR Apache-2.0" repository = "https://github.com/crossbeam-rs/crossbeam" homepage = "https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-skiplist" diff --git a/crossbeam-skiplist/README.md b/crossbeam-skiplist/README.md index 787ce87a5..8fa9dd4ee 100644 --- a/crossbeam-skiplist/README.md +++ b/crossbeam-skiplist/README.md @@ -8,7 +8,7 @@ https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-skiplist#license https://crates.io/crates/crossbeam-skiplist) [![Documentation](https://docs.rs/crossbeam-skiplist/badge.svg)]( https://docs.rs/crossbeam-skiplist) -[![Rust 1.38+](https://img.shields.io/badge/rust-1.38+-lightgray.svg)]( +[![Rust 1.61+](https://img.shields.io/badge/rust-1.61+-lightgray.svg)]( https://www.rust-lang.org) [![chat](https://img.shields.io/discord/569610676205781012.svg?logo=discord)](https://discord.com/invite/JXYwgWZ) @@ -34,7 +34,7 @@ crossbeam-skiplist = "0.1" Crossbeam Skiplist supports stable Rust releases going back at least six months, and every time the minimum supported Rust version is increased, a new minor -version is released. Currently, the minimum supported Rust version is 1.38. +version is released. Currently, the minimum supported Rust version is 1.61. ## License diff --git a/crossbeam-skiplist/build-common.rs b/crossbeam-skiplist/build-common.rs deleted file mode 120000 index 929510c73..000000000 --- a/crossbeam-skiplist/build-common.rs +++ /dev/null @@ -1 +0,0 @@ -../build-common.rs \ No newline at end of file diff --git a/crossbeam-skiplist/build.rs b/crossbeam-skiplist/build.rs deleted file mode 100644 index ffa02a663..000000000 --- a/crossbeam-skiplist/build.rs +++ /dev/null @@ -1,41 +0,0 @@ -// The rustc-cfg listed below are considered public API, but it is *unstable* -// and outside of the normal semver guarantees: -// -// - `crossbeam_no_atomic_cas` -// Assume the target does *not* support atomic CAS operations. -// This is usually detected automatically by the build script, but you may -// need to enable it manually when building for custom targets or using -// non-cargo build systems that don't run the build script. -// -// With the exceptions mentioned above, the rustc-cfg emitted by the build -// script are *not* public API. - -#![warn(rust_2018_idioms)] - -use std::env; - -include!("no_atomic.rs"); -include!("build-common.rs"); - -fn main() { - println!("cargo:rerun-if-changed=no_atomic.rs"); - - let target = match env::var("TARGET") { - Ok(target) => convert_custom_linux_target(target), - Err(e) => { - println!( - "cargo:warning={}: unable to get TARGET environment variable: {}", - env!("CARGO_PKG_NAME"), - e - ); - return; - } - }; - - // Note that this is `no_`*, not `has_*`. This allows treating as the latest - // stable rustc is used when the build script doesn't run. This is useful - // for non-cargo build systems that don't run the build script. - if NO_ATOMIC_CAS.contains(&&*target) { - println!("cargo:rustc-cfg=crossbeam_no_atomic_cas"); - } -} diff --git a/crossbeam-skiplist/no_atomic.rs b/crossbeam-skiplist/no_atomic.rs deleted file mode 120000 index 417886bb7..000000000 --- a/crossbeam-skiplist/no_atomic.rs +++ /dev/null @@ -1 +0,0 @@ -../no_atomic.rs \ No newline at end of file diff --git a/crossbeam-skiplist/src/lib.rs b/crossbeam-skiplist/src/lib.rs index cb5f0462d..194823800 100644 --- a/crossbeam-skiplist/src/lib.rs +++ b/crossbeam-skiplist/src/lib.rs @@ -245,7 +245,7 @@ use cfg_if::cfg_if; -#[cfg(not(crossbeam_no_atomic_cas))] +#[cfg(target_has_atomic = "ptr")] cfg_if! { if #[cfg(feature = "alloc")] { extern crate alloc; diff --git a/crossbeam-utils/Cargo.toml b/crossbeam-utils/Cargo.toml index f195e27a1..8e3156cdd 100644 --- a/crossbeam-utils/Cargo.toml +++ b/crossbeam-utils/Cargo.toml @@ -6,7 +6,7 @@ name = "crossbeam-utils" # - Create "crossbeam-utils-X.Y.Z" git tag version = "0.8.16" edition = "2018" -rust-version = "1.38" +rust-version = "1.61" license = "MIT OR Apache-2.0" repository = "https://github.com/crossbeam-rs/crossbeam" homepage = "https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-utils" @@ -33,4 +33,3 @@ loom = { version = "0.7.1", optional = true } [dev-dependencies] rand = "0.8" -rustversion = "1" diff --git a/crossbeam-utils/README.md b/crossbeam-utils/README.md index 5491c7213..1915015c8 100644 --- a/crossbeam-utils/README.md +++ b/crossbeam-utils/README.md @@ -8,7 +8,7 @@ https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-utils#license) https://crates.io/crates/crossbeam-utils) [![Documentation](https://docs.rs/crossbeam-utils/badge.svg)]( https://docs.rs/crossbeam-utils) -[![Rust 1.38+](https://img.shields.io/badge/rust-1.38+-lightgray.svg)]( +[![Rust 1.61+](https://img.shields.io/badge/rust-1.61+-lightgray.svg)]( https://www.rust-lang.org) [![chat](https://img.shields.io/discord/569610676205781012.svg?logo=discord)](https://discord.com/invite/JXYwgWZ) @@ -55,7 +55,7 @@ crossbeam-utils = "0.8" Crossbeam Utils supports stable Rust releases going back at least six months, and every time the minimum supported Rust version is increased, a new minor -version is released. Currently, the minimum supported Rust version is 1.38. +version is released. Currently, the minimum supported Rust version is 1.61. ## License diff --git a/crossbeam-utils/build.rs b/crossbeam-utils/build.rs index 39785f030..c71c23136 100644 --- a/crossbeam-utils/build.rs +++ b/crossbeam-utils/build.rs @@ -1,24 +1,12 @@ // The rustc-cfg listed below are considered public API, but it is *unstable* // and outside of the normal semver guarantees: // -// - `crossbeam_no_atomic_cas` -// Assume the target does *not* support atomic CAS operations. -// This is usually detected automatically by the build script, but you may -// need to enable it manually when building for custom targets or using -// non-cargo build systems that don't run the build script. -// // - `crossbeam_no_atomic` // Assume the target does *not* support any atomic operations. // This is usually detected automatically by the build script, but you may // need to enable it manually when building for custom targets or using // non-cargo build systems that don't run the build script. // -// - `crossbeam_no_atomic_64` -// Assume the target does *not* support AtomicU64/AtomicI64. -// This is usually detected automatically by the build script, but you may -// need to enable it manually when building for custom targets or using -// non-cargo build systems that don't run the build script. -// // With the exceptions mentioned above, the rustc-cfg emitted by the build // script are *not* public API. @@ -47,16 +35,8 @@ fn main() { // Note that this is `no_`*, not `has_*`. This allows treating as the latest // stable rustc is used when the build script doesn't run. This is useful // for non-cargo build systems that don't run the build script. - if NO_ATOMIC_CAS.contains(&&*target) { - println!("cargo:rustc-cfg=crossbeam_no_atomic_cas"); - } if NO_ATOMIC.contains(&&*target) { println!("cargo:rustc-cfg=crossbeam_no_atomic"); - println!("cargo:rustc-cfg=crossbeam_no_atomic_64"); - } else if NO_ATOMIC_64.contains(&&*target) { - println!("cargo:rustc-cfg=crossbeam_no_atomic_64"); - } else { - // Otherwise, assuming `"max-atomic-width" == 64` or `"max-atomic-width" == 128`. } // `cfg(sanitize = "..")` is not stabilized. diff --git a/crossbeam-utils/src/atomic/atomic_cell.rs b/crossbeam-utils/src/atomic/atomic_cell.rs index c60efbc94..6ce11fc76 100644 --- a/crossbeam-utils/src/atomic/atomic_cell.rs +++ b/crossbeam-utils/src/atomic/atomic_cell.rs @@ -1,12 +1,11 @@ // Necessary for implementing atomic methods for `AtomicUnit` #![allow(clippy::unit_arg)] -use crate::primitive::sync::atomic::{self, AtomicBool}; +use crate::primitive::sync::atomic::{self, Ordering}; use core::cell::UnsafeCell; use core::cmp; use core::fmt; use core::mem::{self, ManuallyDrop, MaybeUninit}; -use core::sync::atomic::Ordering; use core::ptr; @@ -294,6 +293,36 @@ impl Drop for AtomicCell { } } +macro_rules! atomic { + // If values of type `$t` can be transmuted into values of the primitive atomic type `$atomic`, + // declares variable `$a` of type `$atomic` and executes `$atomic_op`, breaking out of the loop. + (@check, $t:ty, $atomic:ty, $a:ident, $atomic_op:expr) => { + if can_transmute::<$t, $atomic>() { + let $a: &$atomic; + break $atomic_op; + } + }; + + // If values of type `$t` can be transmuted into values of a primitive atomic type, declares + // variable `$a` of that type and executes `$atomic_op`. Otherwise, just executes + // `$fallback_op`. + ($t:ty, $a:ident, $atomic_op:expr, $fallback_op:expr) => { + loop { + atomic!(@check, $t, AtomicUnit, $a, $atomic_op); + + atomic!(@check, $t, atomic::AtomicU8, $a, $atomic_op); + atomic!(@check, $t, atomic::AtomicU16, $a, $atomic_op); + atomic!(@check, $t, atomic::AtomicU32, $a, $atomic_op); + #[cfg(target_has_atomic = "64")] + atomic!(@check, $t, atomic::AtomicU64, $a, $atomic_op); + // TODO: AtomicU128 is unstable + // atomic!(@check, $t, atomic::AtomicU128, $a, $atomic_op); + + break $fallback_op; + } + }; +} + macro_rules! impl_arithmetic { ($t:ty, fallback, $example:tt) => { impl AtomicCell<$t> { @@ -472,7 +501,7 @@ macro_rules! impl_arithmetic { } } }; - ($t:ty, $atomic:ty, $example:tt) => { + ($t:ty, $atomic:ident, $example:tt) => { impl AtomicCell<$t> { /// Increments the current value by `val` and returns the previous value. /// @@ -490,15 +519,19 @@ macro_rules! impl_arithmetic { /// ``` #[inline] pub fn fetch_add(&self, val: $t) -> $t { - if can_transmute::<$t, $atomic>() { - let a = unsafe { &*(self.as_ptr() as *const $atomic) }; - a.fetch_add(val, Ordering::AcqRel) - } else { - let _guard = lock(self.as_ptr() as usize).write(); - let value = unsafe { &mut *(self.as_ptr()) }; - let old = *value; - *value = value.wrapping_add(val); - old + atomic! { + $t, _a, + { + let a = unsafe { &*(self.as_ptr() as *const atomic::$atomic) }; + a.fetch_add(val, Ordering::AcqRel) + }, + { + let _guard = lock(self.as_ptr() as usize).write(); + let value = unsafe { &mut *(self.as_ptr()) }; + let old = *value; + *value = value.wrapping_add(val); + old + } } } @@ -518,15 +551,19 @@ macro_rules! impl_arithmetic { /// ``` #[inline] pub fn fetch_sub(&self, val: $t) -> $t { - if can_transmute::<$t, $atomic>() { - let a = unsafe { &*(self.as_ptr() as *const $atomic) }; - a.fetch_sub(val, Ordering::AcqRel) - } else { - let _guard = lock(self.as_ptr() as usize).write(); - let value = unsafe { &mut *(self.as_ptr()) }; - let old = *value; - *value = value.wrapping_sub(val); - old + atomic! { + $t, _a, + { + let a = unsafe { &*(self.as_ptr() as *const atomic::$atomic) }; + a.fetch_sub(val, Ordering::AcqRel) + }, + { + let _guard = lock(self.as_ptr() as usize).write(); + let value = unsafe { &mut *(self.as_ptr()) }; + let old = *value; + *value = value.wrapping_sub(val); + old + } } } @@ -544,15 +581,19 @@ macro_rules! impl_arithmetic { /// ``` #[inline] pub fn fetch_and(&self, val: $t) -> $t { - if can_transmute::<$t, $atomic>() { - let a = unsafe { &*(self.as_ptr() as *const $atomic) }; - a.fetch_and(val, Ordering::AcqRel) - } else { - let _guard = lock(self.as_ptr() as usize).write(); - let value = unsafe { &mut *(self.as_ptr()) }; - let old = *value; - *value &= val; - old + atomic! { + $t, _a, + { + let a = unsafe { &*(self.as_ptr() as *const atomic::$atomic) }; + a.fetch_and(val, Ordering::AcqRel) + }, + { + let _guard = lock(self.as_ptr() as usize).write(); + let value = unsafe { &mut *(self.as_ptr()) }; + let old = *value; + *value &= val; + old + } } } @@ -570,15 +611,19 @@ macro_rules! impl_arithmetic { /// ``` #[inline] pub fn fetch_nand(&self, val: $t) -> $t { - if can_transmute::<$t, $atomic>() { - let a = unsafe { &*(self.as_ptr() as *const $atomic) }; - a.fetch_nand(val, Ordering::AcqRel) - } else { - let _guard = lock(self.as_ptr() as usize).write(); - let value = unsafe { &mut *(self.as_ptr()) }; - let old = *value; - *value = !(old & val); - old + atomic! { + $t, _a, + { + let a = unsafe { &*(self.as_ptr() as *const atomic::$atomic) }; + a.fetch_nand(val, Ordering::AcqRel) + }, + { + let _guard = lock(self.as_ptr() as usize).write(); + let value = unsafe { &mut *(self.as_ptr()) }; + let old = *value; + *value = !(old & val); + old + } } } @@ -596,15 +641,19 @@ macro_rules! impl_arithmetic { /// ``` #[inline] pub fn fetch_or(&self, val: $t) -> $t { - if can_transmute::<$t, $atomic>() { - let a = unsafe { &*(self.as_ptr() as *const $atomic) }; - a.fetch_or(val, Ordering::AcqRel) - } else { - let _guard = lock(self.as_ptr() as usize).write(); - let value = unsafe { &mut *(self.as_ptr()) }; - let old = *value; - *value |= val; - old + atomic! { + $t, _a, + { + let a = unsafe { &*(self.as_ptr() as *const atomic::$atomic) }; + a.fetch_or(val, Ordering::AcqRel) + }, + { + let _guard = lock(self.as_ptr() as usize).write(); + let value = unsafe { &mut *(self.as_ptr()) }; + let old = *value; + *value |= val; + old + } } } @@ -622,15 +671,19 @@ macro_rules! impl_arithmetic { /// ``` #[inline] pub fn fetch_xor(&self, val: $t) -> $t { - if can_transmute::<$t, $atomic>() { - let a = unsafe { &*(self.as_ptr() as *const $atomic) }; - a.fetch_xor(val, Ordering::AcqRel) - } else { - let _guard = lock(self.as_ptr() as usize).write(); - let value = unsafe { &mut *(self.as_ptr()) }; - let old = *value; - *value ^= val; - old + atomic! { + $t, _a, + { + let a = unsafe { &*(self.as_ptr() as *const atomic::$atomic) }; + a.fetch_xor(val, Ordering::AcqRel) + }, + { + let _guard = lock(self.as_ptr() as usize).write(); + let value = unsafe { &mut *(self.as_ptr()) }; + let old = *value; + *value ^= val; + old + } } } @@ -649,15 +702,19 @@ macro_rules! impl_arithmetic { /// ``` #[inline] pub fn fetch_max(&self, val: $t) -> $t { - if can_transmute::<$t, $atomic>() { - // TODO: Atomic*::fetch_max requires Rust 1.45. - self.fetch_update(|old| Some(cmp::max(old, val))).unwrap() - } else { - let _guard = lock(self.as_ptr() as usize).write(); - let value = unsafe { &mut *(self.as_ptr()) }; - let old = *value; - *value = cmp::max(old, val); - old + atomic! { + $t, _a, + { + let a = unsafe { &*(self.as_ptr() as *const atomic::$atomic) }; + a.fetch_max(val, Ordering::AcqRel) + }, + { + let _guard = lock(self.as_ptr() as usize).write(); + let value = unsafe { &mut *(self.as_ptr()) }; + let old = *value; + *value = cmp::max(old, val); + old + } } } @@ -676,51 +733,50 @@ macro_rules! impl_arithmetic { /// ``` #[inline] pub fn fetch_min(&self, val: $t) -> $t { - if can_transmute::<$t, $atomic>() { - // TODO: Atomic*::fetch_min requires Rust 1.45. - self.fetch_update(|old| Some(cmp::min(old, val))).unwrap() - } else { - let _guard = lock(self.as_ptr() as usize).write(); - let value = unsafe { &mut *(self.as_ptr()) }; - let old = *value; - *value = cmp::min(old, val); - old + atomic! { + $t, _a, + { + let a = unsafe { &*(self.as_ptr() as *const atomic::$atomic) }; + a.fetch_min(val, Ordering::AcqRel) + }, + { + let _guard = lock(self.as_ptr() as usize).write(); + let value = unsafe { &mut *(self.as_ptr()) }; + let old = *value; + *value = cmp::min(old, val); + old + } } } } }; } -impl_arithmetic!(u8, atomic::AtomicU8, "let a = AtomicCell::new(7u8);"); -impl_arithmetic!(i8, atomic::AtomicI8, "let a = AtomicCell::new(7i8);"); -impl_arithmetic!(u16, atomic::AtomicU16, "let a = AtomicCell::new(7u16);"); -impl_arithmetic!(i16, atomic::AtomicI16, "let a = AtomicCell::new(7i16);"); -impl_arithmetic!(u32, atomic::AtomicU32, "let a = AtomicCell::new(7u32);"); -impl_arithmetic!(i32, atomic::AtomicI32, "let a = AtomicCell::new(7i32);"); -#[cfg(not(crossbeam_no_atomic_64))] -impl_arithmetic!(u64, atomic::AtomicU64, "let a = AtomicCell::new(7u64);"); -#[cfg(not(crossbeam_no_atomic_64))] -impl_arithmetic!(i64, atomic::AtomicI64, "let a = AtomicCell::new(7i64);"); -#[cfg(crossbeam_no_atomic_64)] +impl_arithmetic!(u8, AtomicU8, "let a = AtomicCell::new(7u8);"); +impl_arithmetic!(i8, AtomicI8, "let a = AtomicCell::new(7i8);"); +impl_arithmetic!(u16, AtomicU16, "let a = AtomicCell::new(7u16);"); +impl_arithmetic!(i16, AtomicI16, "let a = AtomicCell::new(7i16);"); + +impl_arithmetic!(u32, AtomicU32, "let a = AtomicCell::new(7u32);"); +impl_arithmetic!(i32, AtomicI32, "let a = AtomicCell::new(7i32);"); + +#[cfg(target_has_atomic = "64")] +impl_arithmetic!(u64, AtomicU64, "let a = AtomicCell::new(7u64);"); +#[cfg(target_has_atomic = "64")] +impl_arithmetic!(i64, AtomicI64, "let a = AtomicCell::new(7i64);"); +#[cfg(not(target_has_atomic = "64"))] impl_arithmetic!(u64, fallback, "let a = AtomicCell::new(7u64);"); -#[cfg(crossbeam_no_atomic_64)] +#[cfg(not(target_has_atomic = "64"))] impl_arithmetic!(i64, fallback, "let a = AtomicCell::new(7i64);"); + // TODO: AtomicU128 is unstable -// impl_arithmetic!(u128, atomic::AtomicU128, "let a = AtomicCell::new(7u128);"); -// impl_arithmetic!(i128, atomic::AtomicI128, "let a = AtomicCell::new(7i128);"); +// impl_arithmetic!(u128, AtomicU128, "let a = AtomicCell::new(7u128);"); +// impl_arithmetic!(i128, AtomicI128, "let a = AtomicCell::new(7i128);"); impl_arithmetic!(u128, fallback, "let a = AtomicCell::new(7u128);"); impl_arithmetic!(i128, fallback, "let a = AtomicCell::new(7i128);"); -impl_arithmetic!( - usize, - atomic::AtomicUsize, - "let a = AtomicCell::new(7usize);" -); -impl_arithmetic!( - isize, - atomic::AtomicIsize, - "let a = AtomicCell::new(7isize);" -); +impl_arithmetic!(usize, AtomicUsize, "let a = AtomicCell::new(7usize);"); +impl_arithmetic!(isize, AtomicIsize, "let a = AtomicCell::new(7isize);"); impl AtomicCell { /// Applies logical "and" to the current value and returns the previous value. @@ -740,8 +796,20 @@ impl AtomicCell { /// ``` #[inline] pub fn fetch_and(&self, val: bool) -> bool { - let a = unsafe { &*(self.as_ptr() as *const AtomicBool) }; - a.fetch_and(val, Ordering::AcqRel) + atomic! { + bool, _a, + { + let a = unsafe { &*(self.as_ptr() as *const atomic::AtomicBool) }; + a.fetch_and(val, Ordering::AcqRel) + }, + { + let _guard = lock(self.as_ptr() as usize).write(); + let value = unsafe { &mut *(self.as_ptr()) }; + let old = *value; + *value &= val; + old + } + } } /// Applies logical "nand" to the current value and returns the previous value. @@ -764,8 +832,20 @@ impl AtomicCell { /// ``` #[inline] pub fn fetch_nand(&self, val: bool) -> bool { - let a = unsafe { &*(self.as_ptr() as *const AtomicBool) }; - a.fetch_nand(val, Ordering::AcqRel) + atomic! { + bool, _a, + { + let a = unsafe { &*(self.as_ptr() as *const atomic::AtomicBool) }; + a.fetch_nand(val, Ordering::AcqRel) + }, + { + let _guard = lock(self.as_ptr() as usize).write(); + let value = unsafe { &mut *(self.as_ptr()) }; + let old = *value; + *value = !(old & val); + old + } + } } /// Applies logical "or" to the current value and returns the previous value. @@ -785,8 +865,20 @@ impl AtomicCell { /// ``` #[inline] pub fn fetch_or(&self, val: bool) -> bool { - let a = unsafe { &*(self.as_ptr() as *const AtomicBool) }; - a.fetch_or(val, Ordering::AcqRel) + atomic! { + bool, _a, + { + let a = unsafe { &*(self.as_ptr() as *const atomic::AtomicBool) }; + a.fetch_or(val, Ordering::AcqRel) + }, + { + let _guard = lock(self.as_ptr() as usize).write(); + let value = unsafe { &mut *(self.as_ptr()) }; + let old = *value; + *value |= val; + old + } + } } /// Applies logical "xor" to the current value and returns the previous value. @@ -806,8 +898,20 @@ impl AtomicCell { /// ``` #[inline] pub fn fetch_xor(&self, val: bool) -> bool { - let a = unsafe { &*(self.as_ptr() as *const AtomicBool) }; - a.fetch_xor(val, Ordering::AcqRel) + atomic! { + bool, _a, + { + let a = unsafe { &*(self.as_ptr() as *const atomic::AtomicBool) }; + a.fetch_xor(val, Ordering::AcqRel) + }, + { + let _guard = lock(self.as_ptr() as usize).write(); + let value = unsafe { &mut *(self.as_ptr()) }; + let old = *value; + *value ^= val; + old + } + } } } @@ -908,48 +1012,9 @@ impl AtomicUnit { } } -macro_rules! atomic { - // If values of type `$t` can be transmuted into values of the primitive atomic type `$atomic`, - // declares variable `$a` of type `$atomic` and executes `$atomic_op`, breaking out of the loop. - (@check, $t:ty, $atomic:ty, $a:ident, $atomic_op:expr) => { - if can_transmute::<$t, $atomic>() { - let $a: &$atomic; - break $atomic_op; - } - }; - - // If values of type `$t` can be transmuted into values of a primitive atomic type, declares - // variable `$a` of that type and executes `$atomic_op`. Otherwise, just executes - // `$fallback_op`. - ($t:ty, $a:ident, $atomic_op:expr, $fallback_op:expr) => { - loop { - atomic!(@check, $t, AtomicUnit, $a, $atomic_op); - - atomic!(@check, $t, atomic::AtomicU8, $a, $atomic_op); - atomic!(@check, $t, atomic::AtomicU16, $a, $atomic_op); - atomic!(@check, $t, atomic::AtomicU32, $a, $atomic_op); - #[cfg(not(crossbeam_no_atomic_64))] - atomic!(@check, $t, atomic::AtomicU64, $a, $atomic_op); - // TODO: AtomicU128 is unstable - // atomic!(@check, $t, atomic::AtomicU128, $a, $atomic_op); - - break $fallback_op; - } - }; -} - /// Returns `true` if operations on `AtomicCell` are lock-free. const fn atomic_is_lock_free() -> bool { - // HACK(taiki-e): This is equivalent to `atomic! { T, _a, true, false }`, but can be used in const fn even in our MSRV (Rust 1.38). - let is_lock_free = can_transmute::() - | can_transmute::() - | can_transmute::() - | can_transmute::(); - #[cfg(not(crossbeam_no_atomic_64))] - let is_lock_free = is_lock_free | can_transmute::(); - // TODO: AtomicU128 is unstable - // let is_lock_free = is_lock_free | can_transmute::(); - is_lock_free + atomic! { T, _a, true, false } } /// Atomically reads data from `src`. diff --git a/crossbeam-utils/src/atomic/consume.rs b/crossbeam-utils/src/atomic/consume.rs index 80a88829b..ff8e316b2 100644 --- a/crossbeam-utils/src/atomic/consume.rs +++ b/crossbeam-utils/src/atomic/consume.rs @@ -83,11 +83,19 @@ impl_atomic!(AtomicU8, u8); impl_atomic!(AtomicI8, i8); impl_atomic!(AtomicU16, u16); impl_atomic!(AtomicI16, i16); +#[cfg(any(target_has_atomic = "32", not(target_pointer_width = "16")))] impl_atomic!(AtomicU32, u32); +#[cfg(any(target_has_atomic = "32", not(target_pointer_width = "16")))] impl_atomic!(AtomicI32, i32); -#[cfg(not(crossbeam_no_atomic_64))] +#[cfg(any( + target_has_atomic = "64", + not(any(target_pointer_width = "16", target_pointer_width = "32")), +))] impl_atomic!(AtomicU64, u64); -#[cfg(not(crossbeam_no_atomic_64))] +#[cfg(any( + target_has_atomic = "64", + not(any(target_pointer_width = "16", target_pointer_width = "32")), +))] impl_atomic!(AtomicI64, i64); #[cfg(not(crossbeam_no_atomic))] diff --git a/crossbeam-utils/src/atomic/mod.rs b/crossbeam-utils/src/atomic/mod.rs index 38967859f..4332cc3bd 100644 --- a/crossbeam-utils/src/atomic/mod.rs +++ b/crossbeam-utils/src/atomic/mod.rs @@ -3,7 +3,7 @@ //! * [`AtomicCell`], a thread-safe mutable memory location. //! * [`AtomicConsume`], for reading from primitive atomic types with "consume" ordering. -#[cfg(not(crossbeam_no_atomic_cas))] +#[cfg(target_has_atomic = "ptr")] #[cfg(not(crossbeam_loom))] cfg_if::cfg_if! { // Use "wide" sequence lock if the pointer width <= 32 for preventing its counter against wrap @@ -23,7 +23,7 @@ cfg_if::cfg_if! { } } -#[cfg(not(crossbeam_no_atomic_cas))] +#[cfg(target_has_atomic = "ptr")] // We cannot provide AtomicCell under cfg(crossbeam_loom) because loom's atomic // types have a different in-memory representation than the underlying type. // TODO: The latest loom supports fences, so fallback using seqlock may be available. @@ -31,7 +31,7 @@ cfg_if::cfg_if! { mod atomic_cell; mod consume; -#[cfg(not(crossbeam_no_atomic_cas))] +#[cfg(target_has_atomic = "ptr")] #[cfg(not(crossbeam_loom))] pub use self::atomic_cell::AtomicCell; pub use self::consume::AtomicConsume; diff --git a/crossbeam-utils/src/backoff.rs b/crossbeam-utils/src/backoff.rs index 9e256aaf2..bd85dc607 100644 --- a/crossbeam-utils/src/backoff.rs +++ b/crossbeam-utils/src/backoff.rs @@ -1,4 +1,4 @@ -use crate::primitive::sync::atomic; +use crate::primitive::hint; use core::cell::Cell; use core::fmt; @@ -145,10 +145,7 @@ impl Backoff { #[inline] pub fn spin(&self) { for _ in 0..1 << self.step.get().min(SPIN_LIMIT) { - // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, - // use [`core::hint::spin_loop`] instead. - #[allow(deprecated)] - atomic::spin_loop_hint(); + hint::spin_loop(); } if self.step.get() <= SPIN_LIMIT { @@ -193,6 +190,7 @@ impl Backoff { /// let ready = Arc::new(AtomicBool::new(false)); /// let ready2 = ready.clone(); /// + /// # let t = /// thread::spawn(move || { /// thread::sleep(Duration::from_millis(100)); /// ready2.store(true, SeqCst); @@ -201,7 +199,7 @@ impl Backoff { /// assert_eq!(ready.load(SeqCst), false); /// spin_wait(&ready); /// assert_eq!(ready.load(SeqCst), true); - /// # std::thread::sleep(std::time::Duration::from_millis(500)); // wait for background threads closed: https://github.com/rust-lang/miri/issues/1371 + /// # t.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371 /// ``` /// /// [`AtomicBool`]: std::sync::atomic::AtomicBool @@ -209,18 +207,12 @@ impl Backoff { pub fn snooze(&self) { if self.step.get() <= SPIN_LIMIT { for _ in 0..1 << self.step.get() { - // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, - // use [`core::hint::spin_loop`] instead. - #[allow(deprecated)] - atomic::spin_loop_hint(); + hint::spin_loop(); } } else { #[cfg(not(feature = "std"))] for _ in 0..1 << self.step.get() { - // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, - // use [`core::hint::spin_loop`] instead. - #[allow(deprecated)] - atomic::spin_loop_hint(); + hint::spin_loop(); } #[cfg(feature = "std")] @@ -261,6 +253,7 @@ impl Backoff { /// let ready2 = ready.clone(); /// let waiter = thread::current(); /// + /// # let t = /// thread::spawn(move || { /// thread::sleep(Duration::from_millis(100)); /// ready2.store(true, SeqCst); @@ -270,7 +263,7 @@ impl Backoff { /// assert_eq!(ready.load(SeqCst), false); /// blocking_wait(&ready); /// assert_eq!(ready.load(SeqCst), true); - /// # std::thread::sleep(std::time::Duration::from_millis(500)); // wait for background threads closed: https://github.com/rust-lang/miri/issues/1371 + /// # t.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371 /// ``` /// /// [`AtomicBool`]: std::sync::atomic::AtomicBool diff --git a/crossbeam-utils/src/lib.rs b/crossbeam-utils/src/lib.rs index 191c5a17d..6ab748f34 100644 --- a/crossbeam-utils/src/lib.rs +++ b/crossbeam-utils/src/lib.rs @@ -42,12 +42,14 @@ #[cfg(crossbeam_loom)] #[allow(unused_imports)] mod primitive { + pub(crate) mod hint { + pub(crate) use loom::hint::spin_loop; + } pub(crate) mod sync { pub(crate) mod atomic { - pub(crate) use loom::sync::atomic::spin_loop_hint; pub(crate) use loom::sync::atomic::{ AtomicBool, AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicU16, - AtomicU32, AtomicU64, AtomicU8, AtomicUsize, + AtomicU32, AtomicU64, AtomicU8, AtomicUsize, Ordering, }; // FIXME: loom does not support compiler_fence at the moment. @@ -63,19 +65,24 @@ mod primitive { #[cfg(not(crossbeam_loom))] #[allow(unused_imports)] mod primitive { + pub(crate) mod hint { + pub(crate) use core::hint::spin_loop; + } pub(crate) mod sync { pub(crate) mod atomic { - pub(crate) use core::sync::atomic::compiler_fence; - // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, - // use [`core::hint::spin_loop`] instead. - #[allow(deprecated)] - pub(crate) use core::sync::atomic::spin_loop_hint; + pub(crate) use core::sync::atomic::{compiler_fence, Ordering}; #[cfg(not(crossbeam_no_atomic))] pub(crate) use core::sync::atomic::{ - AtomicBool, AtomicI16, AtomicI32, AtomicI8, AtomicIsize, AtomicU16, AtomicU32, - AtomicU8, AtomicUsize, + AtomicBool, AtomicI16, AtomicI8, AtomicIsize, AtomicU16, AtomicU8, AtomicUsize, }; - #[cfg(not(crossbeam_no_atomic_64))] + #[cfg(not(crossbeam_no_atomic))] + #[cfg(any(target_has_atomic = "32", not(target_pointer_width = "16")))] + pub(crate) use core::sync::atomic::{AtomicI32, AtomicU32}; + #[cfg(not(crossbeam_no_atomic))] + #[cfg(any( + target_has_atomic = "64", + not(any(target_pointer_width = "16", target_pointer_width = "32")), + ))] pub(crate) use core::sync::atomic::{AtomicI64, AtomicU64}; } diff --git a/crossbeam-utils/src/sync/once_lock.rs b/crossbeam-utils/src/sync/once_lock.rs index c1fefc96c..761851b01 100644 --- a/crossbeam-utils/src/sync/once_lock.rs +++ b/crossbeam-utils/src/sync/once_lock.rs @@ -4,13 +4,10 @@ use core::cell::UnsafeCell; use core::mem::MaybeUninit; -use core::sync::atomic::{AtomicBool, Ordering}; use std::sync::Once; pub(crate) struct OnceLock { once: Once, - // Once::is_completed requires Rust 1.43, so use this to track of whether they have been initialized. - is_initialized: AtomicBool, value: UnsafeCell>, // Unlike std::sync::OnceLock, we don't need PhantomData here because // we don't use #[may_dangle]. @@ -25,7 +22,6 @@ impl OnceLock { pub(crate) const fn new() -> Self { Self { once: Once::new(), - is_initialized: AtomicBool::new(false), value: UnsafeCell::new(MaybeUninit::uninit()), } } @@ -50,37 +46,28 @@ impl OnceLock { F: FnOnce() -> T, { // Fast path check - if self.is_initialized() { + if self.once.is_completed() { // SAFETY: The inner value has been initialized return unsafe { self.get_unchecked() }; } self.initialize(f); - debug_assert!(self.is_initialized()); - // SAFETY: The inner value has been initialized unsafe { self.get_unchecked() } } - #[inline] - fn is_initialized(&self) -> bool { - self.is_initialized.load(Ordering::Acquire) - } - #[cold] fn initialize(&self, f: F) where F: FnOnce() -> T, { let slot = self.value.get().cast::(); - let is_initialized = &self.is_initialized; self.once.call_once(|| { let value = f(); unsafe { slot.write(value); } - is_initialized.store(true, Ordering::Release); }); } @@ -88,14 +75,14 @@ impl OnceLock { /// /// The value must be initialized unsafe fn get_unchecked(&self) -> &T { - debug_assert!(self.is_initialized()); + debug_assert!(self.once.is_completed()); &*self.value.get().cast::() } } impl Drop for OnceLock { fn drop(&mut self) { - if self.is_initialized() { + if self.once.is_completed() { // SAFETY: The inner value has been initialized unsafe { self.value.get().cast::().drop_in_place() }; } diff --git a/crossbeam-utils/src/sync/parker.rs b/crossbeam-utils/src/sync/parker.rs index df60783c8..399e1629c 100644 --- a/crossbeam-utils/src/sync/parker.rs +++ b/crossbeam-utils/src/sync/parker.rs @@ -1,6 +1,5 @@ -use crate::primitive::sync::atomic::AtomicUsize; +use crate::primitive::sync::atomic::{AtomicUsize, Ordering::SeqCst}; use crate::primitive::sync::{Arc, Condvar, Mutex}; -use core::sync::atomic::Ordering::SeqCst; use std::fmt; use std::marker::PhantomData; use std::time::{Duration, Instant}; @@ -37,6 +36,7 @@ use std::time::{Duration, Instant}; /// // Wakes up immediately and consumes the token. /// p.park(); /// +/// # let t = /// thread::spawn(move || { /// thread::sleep(Duration::from_millis(500)); /// u.unpark(); @@ -44,7 +44,7 @@ use std::time::{Duration, Instant}; /// /// // Wakes up when `u.unpark()` provides the token. /// p.park(); -/// # std::thread::sleep(std::time::Duration::from_millis(500)); // wait for background threads closed: https://github.com/rust-lang/miri/issues/1371 +/// # t.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371 /// ``` /// /// [`park`]: Parker::park @@ -241,6 +241,7 @@ impl Unparker { /// let p = Parker::new(); /// let u = p.unparker().clone(); /// + /// # let t = /// thread::spawn(move || { /// thread::sleep(Duration::from_millis(500)); /// u.unpark(); @@ -248,7 +249,7 @@ impl Unparker { /// /// // Wakes up when `u.unpark()` provides the token. /// p.park(); - /// # std::thread::sleep(std::time::Duration::from_millis(500)); // wait for background threads closed: https://github.com/rust-lang/miri/issues/1371 + /// # t.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371 /// ``` /// /// [`park`]: Parker::park diff --git a/crossbeam-utils/src/sync/sharded_lock.rs b/crossbeam-utils/src/sync/sharded_lock.rs index 5aee56f88..b97ace639 100644 --- a/crossbeam-utils/src/sync/sharded_lock.rs +++ b/crossbeam-utils/src/sync/sharded_lock.rs @@ -158,7 +158,7 @@ impl ShardedLock { /// let lock = Arc::new(ShardedLock::new(0)); /// let c_lock = lock.clone(); /// - /// let _ = thread::spawn(move || { + /// let _: Result<(), _> = thread::spawn(move || { /// let _lock = c_lock.write().unwrap(); /// panic!(); // the lock gets poisoned /// }).join(); diff --git a/crossbeam-utils/src/sync/wait_group.rs b/crossbeam-utils/src/sync/wait_group.rs index 37e74bb06..b50707b50 100644 --- a/crossbeam-utils/src/sync/wait_group.rs +++ b/crossbeam-utils/src/sync/wait_group.rs @@ -39,7 +39,7 @@ use std::fmt; /// /// // Block until all threads have finished their work. /// wg.wait(); -/// # std::thread::sleep(std::time::Duration::from_millis(500)); // wait for background threads closed: https://github.com/rust-lang/miri/issues/1371 +/// # if cfg!(miri) { std::thread::sleep(std::time::Duration::from_millis(500)); } // wait for background threads closed: https://github.com/rust-lang/miri/issues/1371 /// ``` /// /// [`Barrier`]: std::sync::Barrier @@ -88,6 +88,7 @@ impl WaitGroup { /// /// let wg = WaitGroup::new(); /// + /// # let t = /// thread::spawn({ /// let wg = wg.clone(); /// move || { @@ -98,7 +99,7 @@ impl WaitGroup { /// /// // Block until both threads have reached `wait()`. /// wg.wait(); - /// # std::thread::sleep(std::time::Duration::from_millis(500)); // wait for background threads closed: https://github.com/rust-lang/miri/issues/1371 + /// # t.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371 /// ``` pub fn wait(self) { if *self.inner.count.lock().unwrap() == 1 { diff --git a/crossbeam-utils/tests/atomic_cell.rs b/crossbeam-utils/tests/atomic_cell.rs index edb7a4bc0..3b76db5ba 100644 --- a/crossbeam-utils/tests/atomic_cell.rs +++ b/crossbeam-utils/tests/atomic_cell.rs @@ -35,13 +35,13 @@ fn is_lock_free() { // of `AtomicU64` is `8`, so `AtomicCell` is not lock-free. assert_eq!( AtomicCell::::is_lock_free(), - cfg!(not(crossbeam_no_atomic_64)) && std::mem::align_of::() == 8 + cfg!(target_has_atomic = "64") && std::mem::align_of::() == 8 ); assert_eq!(mem::size_of::(), 8); assert_eq!(mem::align_of::(), 8); assert_eq!( AtomicCell::::is_lock_free(), - cfg!(not(crossbeam_no_atomic_64)) + cfg!(target_has_atomic = "64") ); // AtomicU128 is unstable @@ -307,7 +307,6 @@ test_arithmetic!(arithmetic_i128, i128); // https://github.com/crossbeam-rs/crossbeam/issues/748 #[cfg_attr(miri, ignore)] // TODO -#[rustversion::since(1.37)] // #[repr(align(N))] requires Rust 1.37 #[test] fn issue_748() { #[allow(dead_code)] @@ -321,14 +320,13 @@ fn issue_748() { assert_eq!(mem::size_of::(), 8); assert_eq!( AtomicCell::::is_lock_free(), - cfg!(not(crossbeam_no_atomic_64)) + cfg!(target_has_atomic = "64") ); let x = AtomicCell::new(Test::FieldLess); assert_eq!(x.load(), Test::FieldLess); } // https://github.com/crossbeam-rs/crossbeam/issues/833 -#[rustversion::since(1.40)] // const_constructor requires Rust 1.40 #[test] fn issue_833() { use std::num::NonZeroU128; @@ -372,5 +370,5 @@ fn issue_833() { } FINISHED.store(true, Ordering::Relaxed); - handle.join().unwrap(); + handle.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371 } diff --git a/crossbeam-utils/tests/sharded_lock.rs b/crossbeam-utils/tests/sharded_lock.rs index 002f7f5e1..488a7be8f 100644 --- a/crossbeam-utils/tests/sharded_lock.rs +++ b/crossbeam-utils/tests/sharded_lock.rs @@ -141,7 +141,7 @@ fn arc() { fn arc_access_in_unwind() { let arc = Arc::new(ShardedLock::new(1)); let arc2 = arc.clone(); - let _ = thread::spawn(move || { + let _: Result<(), _> = thread::spawn(move || { struct Unwinder { i: Arc>, } @@ -214,7 +214,7 @@ fn test_into_inner_drop() { fn test_into_inner_poison() { let m = Arc::new(ShardedLock::new(NonCopy(10))); let m2 = m.clone(); - let _ = thread::spawn(move || { + let _: Result<(), _> = thread::spawn(move || { let _lock = m2.write().unwrap(); panic!("test panic in inner thread to poison ShardedLock"); }) @@ -238,7 +238,7 @@ fn test_get_mut() { fn test_get_mut_poison() { let m = Arc::new(ShardedLock::new(NonCopy(10))); let m2 = m.clone(); - let _ = thread::spawn(move || { + let _: Result<(), _> = thread::spawn(move || { let _lock = m2.write().unwrap(); panic!("test panic in inner thread to poison ShardedLock"); }) diff --git a/no_atomic.rs b/no_atomic.rs index ca164f54f..b97f39706 100644 --- a/no_atomic.rs +++ b/no_atomic.rs @@ -1,76 +1,7 @@ // This file is @generated by no_atomic.sh. // It is not intended for manual editing. -const NO_ATOMIC_CAS: &[&str] = &[ - "armv4t-none-eabi", - "armv5te-none-eabi", - "avr-unknown-gnu-atmega328", - "bpfeb-unknown-none", - "bpfel-unknown-none", - "msp430-none-elf", - "riscv32i-unknown-none-elf", - "riscv32im-unknown-none-elf", - "riscv32imc-unknown-none-elf", - "thumbv4t-none-eabi", - "thumbv5te-none-eabi", - "thumbv6m-none-eabi", -]; - -#[allow(dead_code)] // Only crossbeam-utils uses this. -const NO_ATOMIC_64: &[&str] = &[ - "arm-linux-androideabi", - "armv4t-none-eabi", - "armv4t-unknown-linux-gnueabi", - "armv5te-none-eabi", - "armv5te-unknown-linux-gnueabi", - "armv5te-unknown-linux-musleabi", - "armv5te-unknown-linux-uclibceabi", - "armv6k-nintendo-3ds", - "csky-unknown-linux-gnuabiv2", - "csky-unknown-linux-gnuabiv2hf", - "hexagon-unknown-linux-musl", - "m68k-unknown-linux-gnu", - "mips-unknown-linux-gnu", - "mips-unknown-linux-musl", - "mips-unknown-linux-uclibc", - "mipsel-sony-psp", - "mipsel-unknown-linux-gnu", - "mipsel-unknown-linux-musl", - "mipsel-unknown-linux-uclibc", - "mipsel-unknown-netbsd", - "mipsel-unknown-none", - "mipsisa32r6-unknown-linux-gnu", - "mipsisa32r6el-unknown-linux-gnu", - "powerpc-unknown-freebsd", - "powerpc-unknown-linux-gnu", - "powerpc-unknown-linux-gnuspe", - "powerpc-unknown-linux-musl", - "powerpc-unknown-netbsd", - "powerpc-unknown-openbsd", - "powerpc-wrs-vxworks", - "powerpc-wrs-vxworks-spe", - "riscv32gc-unknown-linux-gnu", - "riscv32gc-unknown-linux-musl", - "riscv32imac-esp-espidf", - "riscv32imac-unknown-none-elf", - "riscv32imac-unknown-xous-elf", - "riscv32imc-esp-espidf", - "sparc-unknown-linux-gnu", - "sparc-unknown-none-elf", - "thumbv4t-none-eabi", - "thumbv5te-none-eabi", - "thumbv6m-none-eabi", - "thumbv7em-none-eabi", - "thumbv7em-none-eabihf", - "thumbv7m-none-eabi", - "thumbv8m.base-none-eabi", - "thumbv8m.main-none-eabi", - "thumbv8m.main-none-eabihf", -]; - -#[allow(dead_code)] // Only crossbeam-utils uses this. const NO_ATOMIC: &[&str] = &[ - "avr-unknown-gnu-atmega328", "bpfeb-unknown-none", "bpfel-unknown-none", "mipsel-sony-psx",