diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9ceb50f57..d54f26b8c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,8 +23,9 @@ jobs: name: test env: RUST_VERSION: ${{ matrix.rust }} - TARGET: ${{ matrix.target }} + RUST_TARGET: ${{ matrix.target }} strategy: + fail-fast: false matrix: include: - rust: 1.36.0 @@ -63,6 +64,7 @@ jobs: env: RUST_VERSION: ${{ matrix.rust }} strategy: + fail-fast: false matrix: rust: - 1.36.0 @@ -86,6 +88,19 @@ jobs: - name: dependency tree check run: ./ci/dependencies.sh + # When this job failed, run ci/no_atomic.sh and commit result changes. + # TODO(taiki-e): Ideally, this should be automated using a bot that creates + # PR when failed, but there is no bandwidth to implement it + # right now... + codegen: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install Rust + run: rustup update nightly && rustup default nightly + - run: ci/no_atomic.sh + - run: git diff --exit-code + # Check formatting. rustfmt: name: rustfmt @@ -93,7 +108,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: Install Rust - run: rustup update stable && rustup default stable + run: rustup update stable - name: rustfmt run: ./ci/rustfmt.sh @@ -104,7 +119,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: Install Rust - run: rustup update stable && rustup default stable + run: rustup update stable - name: clippy run: ./ci/clippy.sh @@ -126,7 +141,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: Install Rust - run: rustup update stable && rustup default stable + run: rustup update stable - name: loom run: ./ci/crossbeam-epoch-loom.sh @@ -154,6 +169,7 @@ jobs: - test - features - dependencies + - codegen - rustfmt - clippy - san diff --git a/Cargo.toml b/Cargo.toml index 4389b7931..1a490e5ee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,8 +36,9 @@ alloc = ["crossbeam-epoch/alloc", "crossbeam-queue/alloc"] # Enable to use of unstable functionality. # This is disabled by default and requires recent nightly compiler. -# Note that this is outside of the normal semver guarantees and minor versions -# of crossbeam may make breaking changes to them at any time. +# +# NOTE: This feature is outside of the normal semver guarantees and minor or +# patch versions of crossbeam may make breaking changes to them at any time. nightly = ["crossbeam-epoch/nightly", "crossbeam-utils/nightly", "crossbeam-queue/nightly"] [dependencies] diff --git a/ci/check-features.sh b/ci/check-features.sh index 1eeddc520..17fc1a8c1 100755 --- a/ci/check-features.sh +++ b/ci/check-features.sh @@ -13,16 +13,19 @@ if [[ "$RUST_VERSION" != "nightly"* ]]; then # * `--no-dev-deps` - build without dev-dependencies to avoid https://github.com/rust-lang/cargo/issues/4866 # * `--exclude benchmarks` - benchmarks doesn't published. # * `--skip nightly` - skip `nightly` feature as requires nightly compilers. - cargo hack check --all --feature-powerset --no-dev-deps --exclude benchmarks --skip nightly + cargo hack build --all --feature-powerset --no-dev-deps --exclude benchmarks --skip nightly else # On nightly, all feature combinations should work. - cargo hack check --all --feature-powerset --no-dev-deps --exclude benchmarks + cargo hack build --all --feature-powerset --no-dev-deps --exclude benchmarks - # Check for no_std environment. + # Build for no_std environment. + # thumbv7m-none-eabi supports atomic CAS. + # thumbv6m-none-eabi supports atomic, but not atomic CAS. + # riscv32i-unknown-none-elf does not support atomic at all. rustup target add thumbv7m-none-eabi rustup target add thumbv6m-none-eabi - cargo hack check --all --feature-powerset --no-dev-deps --exclude benchmarks --target thumbv7m-none-eabi --skip std,default - # * `--features nightly` is required for enable `cfg_target_has_atomic`. - # * `--ignore-unknown-features` - some crates doesn't have 'nightly' feature - cargo hack check --all --feature-powerset --no-dev-deps --exclude benchmarks --target thumbv6m-none-eabi --skip std,default --features nightly --ignore-unknown-features + rustup target add riscv32i-unknown-none-elf + cargo hack build --all --feature-powerset --no-dev-deps --exclude benchmarks --target thumbv7m-none-eabi --skip std,default + cargo hack build --all --feature-powerset --no-dev-deps --exclude benchmarks --target thumbv6m-none-eabi --skip std,default + cargo hack build --all --feature-powerset --no-dev-deps --exclude benchmarks --target riscv32i-unknown-none-elf --skip std,default fi diff --git a/ci/no_atomic.sh b/ci/no_atomic.sh new file mode 100755 index 000000000..c423ea3c4 --- /dev/null +++ b/ci/no_atomic.sh @@ -0,0 +1,65 @@ +#!/bin/bash + +# Update the list of targets that do not support atomic/CAS operations. +# +# Usage: +# ./ci/no_atomic.sh + +set -euo pipefail +IFS=$'\n\t' + +cd "$(cd "$(dirname "$0")" && pwd)"/.. + +file="no_atomic.rs" + +{ + echo "// This file is @generated by $(basename "$0")." + echo "// It is not intended for manual editing." + echo "" +} >"$file" + +echo "const NO_ATOMIC_CAS: &[&str] = &[" >>"$file" +for target in $(rustc --print target-list); do + res=$(rustc --print target-spec-json -Z unstable-options --target "$target" \ + | jq -r "select(.\"atomic-cas\" == false)") + [[ -z "$res" ]] || echo " \"$target\"," >>"$file" +done +echo "];" >>"$file" + +{ + # Only crossbeam-utils actually uses this const. + echo "#[allow(dead_code)]" + echo "const NO_ATOMIC_64: &[&str] = &[" +} >>"$file" +for target in $(rustc --print target-list); do + res=$(rustc --print target-spec-json -Z unstable-options --target "$target" \ + | jq -r "select(.\"max-atomic-width\" == 32)") + [[ -z "$res" ]] || echo " \"$target\"," >>"$file" +done +# 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. +for target in $(rustc --print target-list); do + res=$(rustc --print target-spec-json -Z unstable-options --target "$target" \ + | jq -r "select(.\"max-atomic-width\" == null)") + [[ -z "$res" ]] || echo " \"$target\"," >>"$file" +done +echo "];" >>"$file" + +# There is no `"max-atomic-width" == 16` or `"max-atomic-width" == 8` targets. + +# `"max-atomic-width" == 0` means that atomic is not supported at all. +{ + # Only crossbeam-utils actually uses this const. + echo "#[allow(dead_code)]" + echo "const NO_ATOMIC: &[&str] = &[" +} >>"$file" +for target in $(rustc --print target-list); do + res=$(rustc --print target-spec-json -Z unstable-options --target "$target" \ + | jq -r "select(.\"max-atomic-width\" == 0)") + [[ -z "$res" ]] || echo " \"$target\"," >>"$file" +done +echo "];" >>"$file" diff --git a/ci/test.sh b/ci/test.sh index c0c633d30..5bda4ff05 100755 --- a/ci/test.sh +++ b/ci/test.sh @@ -5,10 +5,10 @@ set -ex export RUSTFLAGS="-D warnings" -if [[ -n "$TARGET" ]]; then - # If TARGET is specified, use cross for testing. +if [[ -n "$RUST_TARGET" ]]; then + # If RUST_TARGET is specified, use cross for testing. cargo install cross - cross test --all --target "$TARGET" --exclude benchmarks -- --test-threads=1 + cross test --all --target "$RUST_TARGET" --exclude benchmarks -- --test-threads=1 # For now, the non-host target only runs tests. exit 0 diff --git a/crossbeam-channel/Cargo.toml b/crossbeam-channel/Cargo.toml index 0e048a262..c2812fef4 100644 --- a/crossbeam-channel/Cargo.toml +++ b/crossbeam-channel/Cargo.toml @@ -20,6 +20,8 @@ default = ["std"] # Enable to use APIs that require `std`. # This is enabled by default. +# +# NOTE: Disabling `std` feature is not supported yet. std = ["crossbeam-utils/std"] [dependencies] diff --git a/crossbeam-deque/Cargo.toml b/crossbeam-deque/Cargo.toml index 55e22351b..cba710e74 100644 --- a/crossbeam-deque/Cargo.toml +++ b/crossbeam-deque/Cargo.toml @@ -20,6 +20,8 @@ default = ["std"] # Enable to use APIs that require `std`. # This is enabled by default. +# +# NOTE: Disabling `std` feature is not supported yet. std = ["crossbeam-epoch/std", "crossbeam-utils/std"] [dependencies] diff --git a/crossbeam-epoch/Cargo.toml b/crossbeam-epoch/Cargo.toml index de70ebb87..18154259b 100644 --- a/crossbeam-epoch/Cargo.toml +++ b/crossbeam-epoch/Cargo.toml @@ -24,18 +24,21 @@ std = ["alloc", "crossbeam-utils/std", "lazy_static"] # Enable to use APIs that require `alloc`. # This is enabled by default and also enabled if the `std` feature is enabled. +# +# NOTE: Disabling both `std` *and* `alloc` features is not supported yet. alloc = [] # Enable to use of unstable functionality. # This is disabled by default and requires recent nightly compiler. -# Note that this is outside of the normal semver guarantees and minor versions -# of crossbeam may make breaking changes to them at any time. +# +# NOTE: This feature is outside of the normal semver guarantees and minor or +# patch versions of crossbeam may make breaking changes to them at any time. nightly = ["crossbeam-utils/nightly", "const_fn"] # Enable the use of loom for concurrency testing. # -# This configuration option is outside of the normal semver guarantees: minor -# versions of crossbeam may make breaking changes to it at any time. +# NOTE: This feature is outside of the normal semver guarantees and minor or +# patch versions of crossbeam may make breaking changes to them at any time. loom = ["loom-crate", "crossbeam-utils/loom"] [dependencies] @@ -45,8 +48,8 @@ memoffset = "0.6" # Enable the use of loom for concurrency testing. # -# This configuration option is outside of the normal semver guarantees: minor -# versions of crossbeam may make breaking changes to it at any time. +# NOTE: This feature is outside of the normal semver guarantees and minor or +# patch versions of crossbeam may make breaking changes to them at any time. [target.'cfg(crossbeam_loom)'.dependencies] loom-crate = { package = "loom", version = "0.5", optional = true } diff --git a/crossbeam-epoch/build.rs b/crossbeam-epoch/build.rs new file mode 100644 index 000000000..4ef1279fc --- /dev/null +++ b/crossbeam-epoch/build.rs @@ -0,0 +1,32 @@ +#![warn(rust_2018_idioms)] + +use std::env; + +include!("no_atomic.rs"); + +// The rustc-cfg strings below are *not* public API. Please let us know by +// opening a GitHub issue if your build environment requires some way to enable +// these cfgs other than by executing our build script. +fn main() { + let target = match env::var("TARGET") { + Ok(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 + // `cfg(target_has_atomic = "ptr")` as true when the build script doesn't + // run. This is needed for compatibility with 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"); + } + + println!("cargo:rerun-if-changed=no_atomic.rs"); +} diff --git a/crossbeam-epoch/no_atomic.rs b/crossbeam-epoch/no_atomic.rs new file mode 120000 index 000000000..417886bb7 --- /dev/null +++ b/crossbeam-epoch/no_atomic.rs @@ -0,0 +1 @@ +../no_atomic.rs \ No newline at end of file diff --git a/crossbeam-epoch/src/lib.rs b/crossbeam-epoch/src/lib.rs index 81b6b37c9..ba1d3311f 100644 --- a/crossbeam-epoch/src/lib.rs +++ b/crossbeam-epoch/src/lib.rs @@ -62,7 +62,6 @@ unreachable_pub )] #![cfg_attr(not(feature = "std"), no_std)] -#![cfg_attr(feature = "nightly", feature(cfg_target_has_atomic))] #![cfg_attr(feature = "nightly", feature(const_fn_trait_bound))] #[cfg(crossbeam_loom)] @@ -105,10 +104,11 @@ mod primitive { pub(crate) use loom::lazy_static; pub(crate) use loom::thread_local; } +#[cfg(not(crossbeam_no_atomic_cas))] #[cfg(not(crossbeam_loom))] #[allow(unused_imports, dead_code)] mod primitive { - #[cfg(any(feature = "alloc", feature = "std"))] + #[cfg(feature = "alloc")] pub(crate) mod cell { #[derive(Debug)] #[repr(transparent)] @@ -136,14 +136,13 @@ mod primitive { } } } - #[cfg(any(feature = "alloc", feature = "std"))] + #[cfg(feature = "alloc")] pub(crate) mod sync { pub(crate) mod atomic { pub(crate) use core::sync::atomic::compiler_fence; pub(crate) use core::sync::atomic::fence; pub(crate) use core::sync::atomic::AtomicUsize; } - #[cfg_attr(feature = "nightly", cfg(target_has_atomic = "ptr"))] pub(crate) use alloc::sync::Arc; } @@ -154,7 +153,7 @@ mod primitive { pub(crate) use lazy_static::lazy_static; } -#[cfg_attr(feature = "nightly", cfg(target_has_atomic = "ptr"))] +#[cfg(not(crossbeam_no_atomic_cas))] cfg_if! { if #[cfg(feature = "alloc")] { extern crate alloc; diff --git a/crossbeam-queue/Cargo.toml b/crossbeam-queue/Cargo.toml index 622536eb8..b79778d83 100644 --- a/crossbeam-queue/Cargo.toml +++ b/crossbeam-queue/Cargo.toml @@ -24,12 +24,17 @@ std = ["alloc", "crossbeam-utils/std"] # Enable to use APIs that require `alloc`. # This is enabled by default and also enabled if the `std` feature is enabled. +# +# NOTE: Disabling both `std` *and* `alloc` features is not supported yet. alloc = [] +# These features are no longer used. +# TODO: remove in the next major version. # Enable to use of unstable functionality. # This is disabled by default and requires recent nightly compiler. -# Note that this is outside of the normal semver guarantees and minor versions -# of crossbeam may make breaking changes to them at any time. +# +# NOTE: This feature is outside of the normal semver guarantees and minor or +# patch versions of crossbeam may make breaking changes to them at any time. nightly = ["crossbeam-utils/nightly"] [dependencies] diff --git a/crossbeam-queue/build.rs b/crossbeam-queue/build.rs new file mode 100644 index 000000000..4ef1279fc --- /dev/null +++ b/crossbeam-queue/build.rs @@ -0,0 +1,32 @@ +#![warn(rust_2018_idioms)] + +use std::env; + +include!("no_atomic.rs"); + +// The rustc-cfg strings below are *not* public API. Please let us know by +// opening a GitHub issue if your build environment requires some way to enable +// these cfgs other than by executing our build script. +fn main() { + let target = match env::var("TARGET") { + Ok(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 + // `cfg(target_has_atomic = "ptr")` as true when the build script doesn't + // run. This is needed for compatibility with 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"); + } + + println!("cargo:rerun-if-changed=no_atomic.rs"); +} diff --git a/crossbeam-queue/no_atomic.rs b/crossbeam-queue/no_atomic.rs new file mode 120000 index 000000000..417886bb7 --- /dev/null +++ b/crossbeam-queue/no_atomic.rs @@ -0,0 +1 @@ +../no_atomic.rs \ No newline at end of file diff --git a/crossbeam-queue/src/lib.rs b/crossbeam-queue/src/lib.rs index cba6416f6..846d7c2e1 100644 --- a/crossbeam-queue/src/lib.rs +++ b/crossbeam-queue/src/lib.rs @@ -19,9 +19,8 @@ unreachable_pub )] #![cfg_attr(not(feature = "std"), no_std)] -#![cfg_attr(feature = "nightly", feature(cfg_target_has_atomic))] -#[cfg_attr(feature = "nightly", cfg(target_has_atomic = "ptr"))] +#[cfg(not(crossbeam_no_atomic_cas))] cfg_if::cfg_if! { if #[cfg(feature = "alloc")] { extern crate alloc; diff --git a/crossbeam-skiplist/Cargo.toml b/crossbeam-skiplist/Cargo.toml index f6c46efaa..beae558d9 100644 --- a/crossbeam-skiplist/Cargo.toml +++ b/crossbeam-skiplist/Cargo.toml @@ -24,14 +24,10 @@ std = ["alloc", "crossbeam-epoch/std", "crossbeam-utils/std"] # Enable to use APIs that require `alloc`. # This is enabled by default and also enabled if the `std` feature is enabled. +# +# NOTE: Disabling both `std` *and* `alloc` features is not supported yet. alloc = ["crossbeam-epoch/alloc"] -# Enable to use of unstable functionality. -# This is disabled by default and requires recent nightly compiler. -# Note that this is outside of the normal semver guarantees and minor versions -# of crossbeam may make breaking changes to them at any time. -nightly = ["crossbeam-epoch/nightly", "crossbeam-utils/nightly"] - [dependencies] cfg-if = "1" diff --git a/crossbeam-skiplist/build.rs b/crossbeam-skiplist/build.rs new file mode 100644 index 000000000..4ef1279fc --- /dev/null +++ b/crossbeam-skiplist/build.rs @@ -0,0 +1,32 @@ +#![warn(rust_2018_idioms)] + +use std::env; + +include!("no_atomic.rs"); + +// The rustc-cfg strings below are *not* public API. Please let us know by +// opening a GitHub issue if your build environment requires some way to enable +// these cfgs other than by executing our build script. +fn main() { + let target = match env::var("TARGET") { + Ok(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 + // `cfg(target_has_atomic = "ptr")` as true when the build script doesn't + // run. This is needed for compatibility with 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"); + } + + println!("cargo:rerun-if-changed=no_atomic.rs"); +} diff --git a/crossbeam-skiplist/no_atomic.rs b/crossbeam-skiplist/no_atomic.rs new file mode 120000 index 000000000..417886bb7 --- /dev/null +++ b/crossbeam-skiplist/no_atomic.rs @@ -0,0 +1 @@ +../no_atomic.rs \ No newline at end of file diff --git a/crossbeam-skiplist/src/lib.rs b/crossbeam-skiplist/src/lib.rs index 13988fa32..cb5f0462d 100644 --- a/crossbeam-skiplist/src/lib.rs +++ b/crossbeam-skiplist/src/lib.rs @@ -242,11 +242,10 @@ unreachable_pub )] #![cfg_attr(not(feature = "std"), no_std)] -#![cfg_attr(feature = "nightly", feature(cfg_target_has_atomic))] use cfg_if::cfg_if; -#[cfg_attr(feature = "nightly", cfg(target_has_atomic = "ptr"))] +#[cfg(not(crossbeam_no_atomic_cas))] cfg_if! { if #[cfg(feature = "alloc")] { extern crate alloc; diff --git a/crossbeam-utils/Cargo.toml b/crossbeam-utils/Cargo.toml index 4962b7141..14526cadf 100644 --- a/crossbeam-utils/Cargo.toml +++ b/crossbeam-utils/Cargo.toml @@ -22,10 +22,13 @@ default = ["std"] # This is enabled by default. std = ["lazy_static"] +# These features are no longer used. +# TODO: remove in the next major version. # Enable to use of unstable functionality. # This is disabled by default and requires recent nightly compiler. -# Note that this is outside of the normal semver guarantees and minor versions -# of crossbeam may make breaking changes to them at any time. +# +# NOTE: This feature is outside of the normal semver guarantees and minor or +# patch versions of crossbeam may make breaking changes to them at any time. nightly = [] [dependencies] @@ -34,13 +37,10 @@ lazy_static = { version = "1.4.0", optional = true } # Enable the use of loom for concurrency testing. # -# This configuration option is outside of the normal semver guarantees: minor -# versions of crossbeam may make breaking changes to it at any time. +# NOTE: This feature is outside of the normal semver guarantees and minor or +# patch versions of crossbeam may make breaking changes to them at any time. [target.'cfg(crossbeam_loom)'.dependencies] loom = { version = "0.5", optional = true } -[build-dependencies] -autocfg = "1.0.0" - [dev-dependencies] rand = "0.8" diff --git a/crossbeam-utils/build.rs b/crossbeam-utils/build.rs index 3e5102183..9c924adeb 100644 --- a/crossbeam-utils/build.rs +++ b/crossbeam-utils/build.rs @@ -1,23 +1,40 @@ -use autocfg::AutoCfg; +#![warn(rust_2018_idioms)] + +use std::env; + +include!("no_atomic.rs"); // The rustc-cfg strings below are *not* public API. Please let us know by // opening a GitHub issue if your build environment requires some way to enable // these cfgs other than by executing our build script. fn main() { - let cfg = match AutoCfg::new() { - Ok(cfg) => cfg, + let target = match env::var("TARGET") { + Ok(target) => target, Err(e) => { println!( - "cargo:warning=crossbeam-utils: unable to determine rustc version: {}", + "cargo:warning={}: unable to get TARGET environment variable: {}", + env!("CARGO_PKG_NAME"), e ); return; } }; - cfg.emit_type_cfg("core::sync::atomic::AtomicU8", "has_atomic_u8"); - cfg.emit_type_cfg("core::sync::atomic::AtomicU16", "has_atomic_u16"); - cfg.emit_type_cfg("core::sync::atomic::AtomicU32", "has_atomic_u32"); - cfg.emit_type_cfg("core::sync::atomic::AtomicU64", "has_atomic_u64"); - cfg.emit_type_cfg("core::sync::atomic::AtomicU128", "has_atomic_u128"); + // Note that this is `no_*`, not `has_*`. This allows treating + // `cfg(target_has_atomic = "ptr")` as true when the build script doesn't + // run. This is needed for compatibility with 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`. + } + + println!("cargo:rerun-if-changed=no_atomic.rs"); } diff --git a/crossbeam-utils/no_atomic.rs b/crossbeam-utils/no_atomic.rs new file mode 120000 index 000000000..417886bb7 --- /dev/null +++ b/crossbeam-utils/no_atomic.rs @@ -0,0 +1 @@ +../no_atomic.rs \ No newline at end of file diff --git a/crossbeam-utils/src/atomic/atomic_cell.rs b/crossbeam-utils/src/atomic/atomic_cell.rs index ad094b277..e1771382b 100644 --- a/crossbeam-utils/src/atomic/atomic_cell.rs +++ b/crossbeam-utils/src/atomic/atomic_cell.rs @@ -497,33 +497,25 @@ macro_rules! impl_arithmetic { }; } -#[cfg(has_atomic_u8)] impl_arithmetic!(u8, atomic::AtomicU8, "let a = AtomicCell::new(7u8);"); -#[cfg(all(has_atomic_u8, not(crossbeam_loom)))] impl_arithmetic!(i8, atomic::AtomicI8, "let a = AtomicCell::new(7i8);"); -#[cfg(has_atomic_u16)] impl_arithmetic!(u16, atomic::AtomicU16, "let a = AtomicCell::new(7u16);"); -#[cfg(all(has_atomic_u16, not(crossbeam_loom)))] impl_arithmetic!(i16, atomic::AtomicI16, "let a = AtomicCell::new(7i16);"); -#[cfg(has_atomic_u32)] impl_arithmetic!(u32, atomic::AtomicU32, "let a = AtomicCell::new(7u32);"); -#[cfg(all(has_atomic_u32, not(crossbeam_loom)))] impl_arithmetic!(i32, atomic::AtomicI32, "let a = AtomicCell::new(7i32);"); -#[cfg(has_atomic_u64)] +#[cfg(not(crossbeam_no_atomic_64))] impl_arithmetic!(u64, atomic::AtomicU64, "let a = AtomicCell::new(7u64);"); -#[cfg(all(has_atomic_u64, not(crossbeam_loom)))] +#[cfg(not(crossbeam_no_atomic_64))] impl_arithmetic!(i64, atomic::AtomicI64, "let a = AtomicCell::new(7i64);"); -#[cfg(all(has_atomic_u128, not(crossbeam_loom)))] -impl_arithmetic!(u128, atomic::AtomicU128, "let a = AtomicCell::new(7u128);"); -#[cfg(all(has_atomic_u128, not(crossbeam_loom)))] -impl_arithmetic!(i128, atomic::AtomicI128, "let a = AtomicCell::new(7i128);"); +// 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!( usize, atomic::AtomicUsize, "let a = AtomicCell::new(7usize);" ); -#[cfg(not(crossbeam_loom))] impl_arithmetic!( isize, atomic::AtomicIsize, @@ -809,16 +801,13 @@ macro_rules! atomic { atomic!(@check, $t, AtomicUnit, $a, $atomic_op); atomic!(@check, $t, atomic::AtomicUsize, $a, $atomic_op); - #[cfg(has_atomic_u8)] atomic!(@check, $t, atomic::AtomicU8, $a, $atomic_op); - #[cfg(has_atomic_u16)] atomic!(@check, $t, atomic::AtomicU16, $a, $atomic_op); - #[cfg(has_atomic_u32)] atomic!(@check, $t, atomic::AtomicU32, $a, $atomic_op); - #[cfg(has_atomic_u64)] + #[cfg(not(crossbeam_no_atomic_64))] atomic!(@check, $t, atomic::AtomicU64, $a, $atomic_op); - #[cfg(has_atomic_u128)] - atomic!(@check, $t, atomic::AtomicU128, $a, $atomic_op); + // TODO: AtomicU128 is unstable + // atomic!(@check, $t, atomic::AtomicU128, $a, $atomic_op); #[cfg(crossbeam_loom)] unimplemented!("loom does not support non-atomic atomic ops"); @@ -831,17 +820,15 @@ macro_rules! atomic { /// 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 Rust 1.36. - let is_lock_free = can_transmute::() | can_transmute::(); - #[cfg(has_atomic_u8)] - let is_lock_free = is_lock_free | can_transmute::(); - #[cfg(has_atomic_u16)] - let is_lock_free = is_lock_free | can_transmute::(); - #[cfg(has_atomic_u32)] - let is_lock_free = is_lock_free | can_transmute::(); - #[cfg(has_atomic_u64)] + let is_lock_free = can_transmute::() + | can_transmute::() + | can_transmute::() + | can_transmute::() + | can_transmute::(); + #[cfg(not(crossbeam_no_atomic_64))] let is_lock_free = is_lock_free | can_transmute::(); - #[cfg(has_atomic_u128)] - 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 } diff --git a/crossbeam-utils/src/atomic/consume.rs b/crossbeam-utils/src/atomic/consume.rs index 0fbd93e9f..277b370a5 100644 --- a/crossbeam-utils/src/atomic/consume.rs +++ b/crossbeam-utils/src/atomic/consume.rs @@ -1,5 +1,6 @@ #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] use crate::primitive::sync::atomic::compiler_fence; +#[cfg(not(crossbeam_no_atomic))] use core::sync::atomic::Ordering; /// Trait which allows reading from primitive atomic types with "consume" ordering. @@ -25,6 +26,7 @@ pub trait AtomicConsume { fn load_consume(&self) -> Self::Val; } +#[cfg(not(crossbeam_no_atomic))] #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] macro_rules! impl_consume { () => { @@ -37,6 +39,7 @@ macro_rules! impl_consume { }; } +#[cfg(not(crossbeam_no_atomic))] #[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))] macro_rules! impl_consume { () => { @@ -49,12 +52,13 @@ macro_rules! impl_consume { macro_rules! impl_atomic { ($atomic:ident, $val:ty) => { - impl AtomicConsume for ::core::sync::atomic::$atomic { + #[cfg(not(crossbeam_no_atomic))] + impl AtomicConsume for core::sync::atomic::$atomic { type Val = $val; impl_consume!(); } #[cfg(crossbeam_loom)] - impl AtomicConsume for ::loom::sync::atomic::$atomic { + impl AtomicConsume for loom::sync::atomic::$atomic { type Val = $val; impl_consume!(); } @@ -63,32 +67,26 @@ macro_rules! impl_atomic { impl_atomic!(AtomicBool, bool); impl_atomic!(AtomicUsize, usize); -#[cfg(not(crossbeam_loom))] impl_atomic!(AtomicIsize, isize); -#[cfg(has_atomic_u8)] impl_atomic!(AtomicU8, u8); -#[cfg(has_atomic_u8)] impl_atomic!(AtomicI8, i8); -#[cfg(has_atomic_u16)] impl_atomic!(AtomicU16, u16); -#[cfg(has_atomic_u16)] impl_atomic!(AtomicI16, i16); -#[cfg(has_atomic_u32)] impl_atomic!(AtomicU32, u32); -#[cfg(has_atomic_u32)] impl_atomic!(AtomicI32, i32); -#[cfg(has_atomic_u64)] +#[cfg(not(crossbeam_no_atomic_64))] impl_atomic!(AtomicU64, u64); -#[cfg(has_atomic_u64)] +#[cfg(not(crossbeam_no_atomic_64))] impl_atomic!(AtomicI64, i64); -impl AtomicConsume for ::core::sync::atomic::AtomicPtr { +#[cfg(not(crossbeam_no_atomic))] +impl AtomicConsume for core::sync::atomic::AtomicPtr { type Val = *mut T; impl_consume!(); } #[cfg(crossbeam_loom)] -impl AtomicConsume for ::loom::sync::atomic::AtomicPtr { +impl AtomicConsume for loom::sync::atomic::AtomicPtr { type Val = *mut T; impl_consume!(); } diff --git a/crossbeam-utils/src/atomic/mod.rs b/crossbeam-utils/src/atomic/mod.rs index 874eaf216..fc713fcac 100644 --- a/crossbeam-utils/src/atomic/mod.rs +++ b/crossbeam-utils/src/atomic/mod.rs @@ -3,11 +3,9 @@ //! * [`AtomicCell`], a thread-safe mutable memory location. //! * [`AtomicConsume`], for reading from primitive atomic types with "consume" ordering. +#[cfg(not(crossbeam_no_atomic_cas))] #[cfg(not(crossbeam_loom))] -use cfg_if::cfg_if; - -#[cfg(not(crossbeam_loom))] -cfg_if! { +cfg_if::cfg_if! { // Use "wide" sequence lock if the pointer width <= 32 for preventing its counter against wrap // around. // @@ -25,8 +23,10 @@ cfg_if! { } } +#[cfg(not(crossbeam_no_atomic_cas))] mod atomic_cell; mod consume; +#[cfg(not(crossbeam_no_atomic_cas))] pub use self::atomic_cell::AtomicCell; pub use self::consume::AtomicConsume; diff --git a/crossbeam-utils/src/lib.rs b/crossbeam-utils/src/lib.rs index 880d37ec6..191c5a17d 100644 --- a/crossbeam-utils/src/lib.rs +++ b/crossbeam-utils/src/lib.rs @@ -38,7 +38,6 @@ unreachable_pub )] #![cfg_attr(not(feature = "std"), no_std)] -#![cfg_attr(feature = "nightly", feature(cfg_target_has_atomic))] #[cfg(crossbeam_loom)] #[allow(unused_imports)] @@ -47,7 +46,8 @@ mod primitive { pub(crate) mod atomic { pub(crate) use loom::sync::atomic::spin_loop_hint; pub(crate) use loom::sync::atomic::{ - AtomicBool, AtomicU16, AtomicU32, AtomicU64, AtomicU8, AtomicUsize, + AtomicBool, AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicU16, + AtomicU32, AtomicU64, AtomicU8, AtomicUsize, }; // FIXME: loom does not support compiler_fence at the moment. @@ -70,15 +70,13 @@ mod primitive { // use [`core::hint::spin_loop`] instead. #[allow(deprecated)] pub(crate) use core::sync::atomic::spin_loop_hint; - pub(crate) use core::sync::atomic::{AtomicBool, AtomicIsize, AtomicUsize}; - #[cfg(has_atomic_u16)] - pub(crate) use core::sync::atomic::{AtomicI16, AtomicU16}; - #[cfg(has_atomic_u32)] - pub(crate) use core::sync::atomic::{AtomicI32, AtomicU32}; - #[cfg(has_atomic_u64)] + #[cfg(not(crossbeam_no_atomic))] + pub(crate) use core::sync::atomic::{ + AtomicBool, AtomicI16, AtomicI32, AtomicI8, AtomicIsize, AtomicU16, AtomicU32, + AtomicU8, AtomicUsize, + }; + #[cfg(not(crossbeam_no_atomic_64))] pub(crate) use core::sync::atomic::{AtomicI64, AtomicU64}; - #[cfg(has_atomic_u8)] - pub(crate) use core::sync::atomic::{AtomicI8, AtomicU8}; } #[cfg(feature = "std")] @@ -86,15 +84,6 @@ mod primitive { } } -cfg_if! { - if #[cfg(feature = "alloc")] { - extern crate alloc; - } else if #[cfg(feature = "std")] { - extern crate std as alloc; - } -} - -#[cfg_attr(feature = "nightly", cfg(target_has_atomic = "ptr"))] pub mod atomic; mod cache_padded; diff --git a/crossbeam-utils/tests/atomic_cell.rs b/crossbeam-utils/tests/atomic_cell.rs index 3d91d81d6..28208ee76 100644 --- a/crossbeam-utils/tests/atomic_cell.rs +++ b/crossbeam-utils/tests/atomic_cell.rs @@ -1,3 +1,4 @@ +use std::mem; use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering::SeqCst; @@ -8,18 +9,47 @@ fn is_lock_free() { struct UsizeWrap(usize); struct U8Wrap(bool); struct I16Wrap(i16); - - assert_eq!(AtomicCell::::is_lock_free(), true); - assert_eq!(AtomicCell::::is_lock_free(), true); - assert_eq!(AtomicCell::::is_lock_free(), true); - - assert_eq!(AtomicCell::::is_lock_free(), cfg!(has_atomic_u8)); - assert_eq!(AtomicCell::::is_lock_free(), cfg!(has_atomic_u8)); - assert_eq!(AtomicCell::::is_lock_free(), cfg!(has_atomic_u8)); - - assert_eq!(AtomicCell::::is_lock_free(), cfg!(has_atomic_u16)); - - assert_eq!(AtomicCell::::is_lock_free(), cfg!(has_atomic_u128)); + #[repr(align(8))] + struct U64Align8(u64); + + assert!(AtomicCell::::is_lock_free()); + assert!(AtomicCell::::is_lock_free()); + assert!(AtomicCell::::is_lock_free()); + + assert!(AtomicCell::<()>::is_lock_free()); + + assert!(AtomicCell::::is_lock_free()); + assert!(AtomicCell::::is_lock_free()); + assert!(AtomicCell::::is_lock_free()); + assert!(AtomicCell::::is_lock_free()); + + assert!(AtomicCell::::is_lock_free()); + assert!(AtomicCell::::is_lock_free()); + assert!(AtomicCell::::is_lock_free()); + + assert!(AtomicCell::::is_lock_free()); + assert!(AtomicCell::::is_lock_free()); + + // Sizes of both types must be equal, and the alignment of `u64` must be greater or equal than + // that of `AtomicU64`. In i686-unknown-linux-gnu, the alignment of `u64` is `4` and alignment + // of `AtomicU64` is `8`, so `AtomicCell` is not lock-free. + assert_eq!( + AtomicCell::::is_lock_free(), + cfg!(not(crossbeam_no_atomic_64)) + && cfg!(any( + target_pointer_width = "64", + target_pointer_width = "128" + )) + ); + assert_eq!(mem::size_of::(), 8); + assert_eq!(mem::align_of::(), 8); + assert_eq!( + AtomicCell::::is_lock_free(), + cfg!(not(crossbeam_no_atomic_64)) + ); + + // AtomicU128 is unstable + assert!(!AtomicCell::::is_lock_free()); } #[test] diff --git a/no_atomic.rs b/no_atomic.rs new file mode 100644 index 000000000..522b3b8ac --- /dev/null +++ b/no_atomic.rs @@ -0,0 +1,59 @@ +// This file is @generated by no_atomic.sh. +// It is not intended for manual editing. + +const NO_ATOMIC_CAS: &[&str] = &[ + "avr-unknown-gnu-atmega328", + "msp430-none-elf", + "riscv32i-unknown-none-elf", + "riscv32imc-unknown-none-elf", + "thumbv4t-none-eabi", + "thumbv6m-none-eabi", +]; +#[allow(dead_code)] +const NO_ATOMIC_64: &[&str] = &[ + "arm-linux-androideabi", + "armebv7r-none-eabi", + "armebv7r-none-eabihf", + "armv4t-unknown-linux-gnueabi", + "armv5te-unknown-linux-gnueabi", + "armv5te-unknown-linux-musleabi", + "armv5te-unknown-linux-uclibceabi", + "armv7r-none-eabi", + "armv7r-none-eabihf", + "hexagon-unknown-linux-musl", + "mips-unknown-linux-gnu", + "mips-unknown-linux-musl", + "mips-unknown-linux-uclibc", + "mipsel-unknown-linux-gnu", + "mipsel-unknown-linux-musl", + "mipsel-unknown-linux-uclibc", + "mipsel-unknown-none", + "mipsisa32r6-unknown-linux-gnu", + "mipsisa32r6el-unknown-linux-gnu", + "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-unknown-none-elf", + "thumbv7em-none-eabi", + "thumbv7em-none-eabihf", + "thumbv7m-none-eabi", + "thumbv8m.base-none-eabi", + "thumbv8m.main-none-eabi", + "thumbv8m.main-none-eabihf", + "mipsel-sony-psp", + "thumbv4t-none-eabi", + "thumbv6m-none-eabi", +]; +#[allow(dead_code)] +const NO_ATOMIC: &[&str] = &[ + "avr-unknown-gnu-atmega328", + "msp430-none-elf", + "riscv32i-unknown-none-elf", + "riscv32imc-unknown-none-elf", +]; diff --git a/src/lib.rs b/src/lib.rs index 9d7d37416..9bc3ec111 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -52,9 +52,7 @@ unreachable_pub )] #![cfg_attr(not(feature = "std"), no_std)] -#![cfg_attr(feature = "nightly", feature(cfg_target_has_atomic))] -#[cfg_attr(feature = "nightly", cfg(target_has_atomic = "ptr"))] pub use crossbeam_utils::atomic; pub mod utils {