Skip to content

Commit

Permalink
Remove uses of autocfg
Browse files Browse the repository at this point in the history
Detect platforms that do not support AtomicU64 by using the same way.
AFAIK, this is more robust than the current way that uses autocfg.
See also rust-lang/futures-rs#2294.
  • Loading branch information
taiki-e committed May 27, 2021
1 parent 7e6c097 commit 02a41ef
Show file tree
Hide file tree
Showing 10 changed files with 144 additions and 89 deletions.
4 changes: 3 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -63,6 +64,7 @@ jobs:
env:
RUST_VERSION: ${{ matrix.rust }}
strategy:
fail-fast: false
matrix:
rust:
- 1.36.0
Expand Down
25 changes: 25 additions & 0 deletions ci/no_atomic.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,31 @@ for target in $(rustc --print target-list); do
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.
Expand Down
6 changes: 3 additions & 3 deletions ci/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 0 additions & 3 deletions crossbeam-utils/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,5 @@ lazy_static = { version = "1.4.0", optional = true }
[target.'cfg(crossbeam_loom)'.dependencies]
loom = { version = "0.5", optional = true }

[build-dependencies]
autocfg = "1.0.0"

[dev-dependencies]
rand = "0.8"
25 changes: 5 additions & 20 deletions crossbeam-utils/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

use std::env;

use autocfg::AutoCfg;

include!("no_atomic.rs");

// The rustc-cfg strings below are *not* public API. Please let us know by
Expand Down Expand Up @@ -31,25 +29,12 @@ fn main() {
}
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`.
}

let cfg = match AutoCfg::new() {
Ok(cfg) => cfg,
Err(e) => {
println!(
"cargo:warning={}: unable to determine rustc version: {}",
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");

println!("cargo:rerun-if-changed=no_atomic.rs");
}
45 changes: 16 additions & 29 deletions crossbeam-utils/src/atomic/atomic_cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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");
Expand All @@ -831,17 +820,15 @@ macro_rules! atomic {
/// Returns `true` if operations on `AtomicCell<T>` are lock-free.
const fn atomic_is_lock_free<T>() -> 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::<T, AtomicUnit>() | can_transmute::<T, atomic::AtomicUsize>();
#[cfg(has_atomic_u8)]
let is_lock_free = is_lock_free | can_transmute::<T, atomic::AtomicU8>();
#[cfg(has_atomic_u16)]
let is_lock_free = is_lock_free | can_transmute::<T, atomic::AtomicU16>();
#[cfg(has_atomic_u32)]
let is_lock_free = is_lock_free | can_transmute::<T, atomic::AtomicU32>();
#[cfg(has_atomic_u64)]
let is_lock_free = can_transmute::<T, AtomicUnit>()
| can_transmute::<T, atomic::AtomicUsize>()
| can_transmute::<T, atomic::AtomicU8>()
| can_transmute::<T, atomic::AtomicU16>()
| can_transmute::<T, atomic::AtomicU32>();
#[cfg(not(crossbeam_no_atomic_64))]
let is_lock_free = is_lock_free | can_transmute::<T, atomic::AtomicU64>();
#[cfg(has_atomic_u128)]
let is_lock_free = is_lock_free | can_transmute::<T, atomic::AtomicU128>();
// TODO: AtomicU128 is unstable
// let is_lock_free = is_lock_free | can_transmute::<T, atomic::AtomicU128>();
is_lock_free
}

Expand Down
10 changes: 2 additions & 8 deletions crossbeam-utils/src/atomic/consume.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,21 +68,15 @@ macro_rules! impl_atomic {
impl_atomic!(AtomicBool, bool);
impl_atomic!(AtomicUsize, usize);
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);

#[cfg(not(crossbeam_no_atomic))]
Expand Down
20 changes: 7 additions & 13 deletions crossbeam-utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,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.
Expand All @@ -70,19 +71,12 @@ mod primitive {
#[allow(deprecated)]
pub(crate) use core::sync::atomic::spin_loop_hint;
#[cfg(not(crossbeam_no_atomic))]
pub(crate) use core::sync::atomic::{AtomicBool, AtomicIsize, AtomicUsize};
#[cfg(not(crossbeam_no_atomic))]
#[cfg(has_atomic_u16)]
pub(crate) use core::sync::atomic::{AtomicI16, AtomicU16};
#[cfg(not(crossbeam_no_atomic))]
#[cfg(has_atomic_u32)]
pub(crate) use core::sync::atomic::{AtomicI32, AtomicU32};
#[cfg(not(crossbeam_no_atomic))]
#[cfg(has_atomic_u64)]
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(not(crossbeam_no_atomic))]
#[cfg(has_atomic_u8)]
pub(crate) use core::sync::atomic::{AtomicI8, AtomicU8};
}

#[cfg(feature = "std")]
Expand Down
54 changes: 42 additions & 12 deletions crossbeam-utils/tests/atomic_cell.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::mem;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::SeqCst;

Expand All @@ -8,18 +9,47 @@ fn is_lock_free() {
struct UsizeWrap(usize);
struct U8Wrap(bool);
struct I16Wrap(i16);

assert_eq!(AtomicCell::<usize>::is_lock_free(), true);
assert_eq!(AtomicCell::<isize>::is_lock_free(), true);
assert_eq!(AtomicCell::<UsizeWrap>::is_lock_free(), true);

assert_eq!(AtomicCell::<u8>::is_lock_free(), cfg!(has_atomic_u8));
assert_eq!(AtomicCell::<bool>::is_lock_free(), cfg!(has_atomic_u8));
assert_eq!(AtomicCell::<U8Wrap>::is_lock_free(), cfg!(has_atomic_u8));

assert_eq!(AtomicCell::<I16Wrap>::is_lock_free(), cfg!(has_atomic_u16));

assert_eq!(AtomicCell::<u128>::is_lock_free(), cfg!(has_atomic_u128));
#[repr(align(8))]
struct U64Align8(u64);

assert!(AtomicCell::<usize>::is_lock_free());
assert!(AtomicCell::<isize>::is_lock_free());
assert!(AtomicCell::<UsizeWrap>::is_lock_free());

assert!(AtomicCell::<()>::is_lock_free());

assert!(AtomicCell::<u8>::is_lock_free());
assert!(AtomicCell::<i8>::is_lock_free());
assert!(AtomicCell::<bool>::is_lock_free());
assert!(AtomicCell::<U8Wrap>::is_lock_free());

assert!(AtomicCell::<u16>::is_lock_free());
assert!(AtomicCell::<i16>::is_lock_free());
assert!(AtomicCell::<I16Wrap>::is_lock_free());

assert!(AtomicCell::<u32>::is_lock_free());
assert!(AtomicCell::<i32>::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<u64>` is not lock-free.
assert_eq!(
AtomicCell::<u64>::is_lock_free(),
cfg!(not(crossbeam_no_atomic_64))
&& cfg!(any(
target_pointer_width = "64",
target_pointer_width = "128"
))
);
assert_eq!(mem::size_of::<U64Align8>(), 8);
assert_eq!(mem::align_of::<U64Align8>(), 8);
assert_eq!(
AtomicCell::<U64Align8>::is_lock_free(),
cfg!(not(crossbeam_no_atomic_64))
);

// AtomicU128 is unstable
assert!(!AtomicCell::<u128>::is_lock_free());
}

#[test]
Expand Down
41 changes: 41 additions & 0 deletions no_atomic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,47 @@ const NO_ATOMIC_CAS: &[&str] = &[
"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",
Expand Down

0 comments on commit 02a41ef

Please sign in to comment.