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
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
@@ -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
25 changes: 25 additions & 0 deletions ci/no_atomic.sh
Original file line number Diff line number Diff line change
@@ -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.
6 changes: 3 additions & 3 deletions ci/test.sh
Original file line number Diff line number Diff line change
@@ -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
3 changes: 0 additions & 3 deletions crossbeam-utils/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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
@@ -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
@@ -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
@@ -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<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
}

10 changes: 2 additions & 8 deletions crossbeam-utils/src/atomic/consume.rs
Original file line number Diff line number Diff line change
@@ -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))]
20 changes: 7 additions & 13 deletions crossbeam-utils/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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.
@@ -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")]
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;

@@ -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]
41 changes: 41 additions & 0 deletions no_atomic.rs
Original file line number Diff line number Diff line change
@@ -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",

0 comments on commit 02a41ef

Please sign in to comment.