diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 46cb6cb8b..e637ed889 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,6 +20,10 @@ defaults: run: shell: bash +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} + cancel-in-progress: true + jobs: # Test crates on their minimum Rust versions and nightly Rust. test: @@ -75,13 +79,14 @@ jobs: fail-fast: false matrix: rust: - - '1.61' + - msrv - nightly runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install Rust run: rustup update ${{ matrix.rust }} && rustup default ${{ matrix.rust }} + if: matrix.rust != 'msrv' - name: Install cargo-hack uses: taiki-e/install-action@cargo-hack - name: Check features diff --git a/CHANGELOG.md b/CHANGELOG.md index 29f85b7b3..7192ccad7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# Version 0.8.3 + +- Bump the minimum supported Rust version to 1.61. (#1037) + # Version 0.8.2 - Bump the minimum supported Rust version to 1.38. (#877) diff --git a/Cargo.toml b/Cargo.toml index c93ca1ff9..94b63b6e5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,8 +4,8 @@ name = "crossbeam" # - Update CHANGELOG.md # - Update README.md # - Create "crossbeam-X.Y.Z" git tag -version = "0.8.2" -edition = "2018" +version = "0.8.3" +edition = "2021" rust-version = "1.61" license = "MIT OR Apache-2.0" repository = "https://github.com/crossbeam-rs/crossbeam" @@ -41,41 +41,19 @@ alloc = ["crossbeam-epoch/alloc", "crossbeam-queue/alloc"] nightly = ["crossbeam-epoch/nightly", "crossbeam-utils/nightly", "crossbeam-queue/nightly"] [dependencies] -cfg-if = "1" - -[dependencies.crossbeam-channel] -version = "0.5.9" -path = "./crossbeam-channel" -default-features = false -optional = true - -[dependencies.crossbeam-deque] -version = "0.8.4" -path = "./crossbeam-deque" -default-features = false -optional = true +crossbeam-channel = { version = "0.5.10", path = "crossbeam-channel", default-features = false, optional = true } +crossbeam-deque = { version = "0.8.4", path = "crossbeam-deque", default-features = false, optional = true } +crossbeam-epoch = { version = "0.9.17", path = "crossbeam-epoch", default-features = false, optional = true } +crossbeam-queue = { version = "0.3.10", path = "crossbeam-queue", default-features = false, optional = true } +crossbeam-utils = { version = "0.8.18", path = "crossbeam-utils", default-features = false } -[dependencies.crossbeam-epoch] -version = "0.9.16" -path = "./crossbeam-epoch" -default-features = false -optional = true - -[dependencies.crossbeam-queue] -version = "0.3.9" -path = "./crossbeam-queue" -default-features = false -optional = true - -[dependencies.crossbeam-utils] -version = "0.8.17" -path = "./crossbeam-utils" -default-features = false +cfg-if = "1" [dev-dependencies] rand = "0.8" [workspace] +resolver = "2" members = [ ".", "crossbeam-channel", diff --git a/ci/check-features.sh b/ci/check-features.sh index 6c4a02978..5395b0342 100755 --- a/ci/check-features.sh +++ b/ci/check-features.sh @@ -3,17 +3,20 @@ set -euxo pipefail IFS=$'\n\t' cd "$(dirname "$0")"/.. -if [[ "$RUST_VERSION" != "nightly"* ]]; then - # On MSRV, features other than nightly should work. - # * `--feature-powerset` - run for the feature powerset which includes --no-default-features and default features of package - # * `--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. +# * `--feature-powerset` - run for the feature powerset which includes --no-default-features and default features of package +# * `--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. +if [[ "${RUST_VERSION}" == "msrv" ]]; then + cargo hack build --all --feature-powerset --no-dev-deps --exclude benchmarks --skip nightly --rust-version +elif [[ "$RUST_VERSION" != "nightly"* ]]; then cargo hack build --all --feature-powerset --no-dev-deps --exclude benchmarks --skip nightly else # On nightly, all feature combinations should work. cargo hack build --all --feature-powerset --no-dev-deps --exclude benchmarks +fi +if [[ "${RUST_VERSION}" == "nightly"* ]]; then # Build for no_std environment. # thumbv7m-none-eabi supports atomic CAS. # thumbv6m-none-eabi supports atomic, but not atomic CAS. diff --git a/crossbeam-channel/CHANGELOG.md b/crossbeam-channel/CHANGELOG.md index 2dec6ca4c..6029b2a81 100644 --- a/crossbeam-channel/CHANGELOG.md +++ b/crossbeam-channel/CHANGELOG.md @@ -1,3 +1,8 @@ +# Version 0.5.10 + +- Relax the minimum supported Rust version to 1.60. (#1056) +- Optimize `Drop` implementation of bounded channel. (#1057) + # Version 0.5.9 - Bump the minimum supported Rust version to 1.61. (#1037) diff --git a/crossbeam-channel/Cargo.toml b/crossbeam-channel/Cargo.toml index f8a25a26c..804600ddd 100644 --- a/crossbeam-channel/Cargo.toml +++ b/crossbeam-channel/Cargo.toml @@ -4,9 +4,9 @@ name = "crossbeam-channel" # - Update CHANGELOG.md # - Update README.md # - Create "crossbeam-channel-X.Y.Z" git tag -version = "0.5.9" -edition = "2018" -rust-version = "1.61" +version = "0.5.10" +edition = "2021" +rust-version = "1.60" license = "MIT OR Apache-2.0" repository = "https://github.com/crossbeam-rs/crossbeam" homepage = "https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-channel" @@ -24,13 +24,9 @@ default = ["std"] std = ["crossbeam-utils/std"] [dependencies] -cfg-if = "1" +crossbeam-utils = { version = "0.8.18", path = "../crossbeam-utils", default-features = false } -[dependencies.crossbeam-utils] -version = "0.8.17" -path = "../crossbeam-utils" -default-features = false -optional = true +cfg-if = "1" [dev-dependencies] num_cpus = "1.13.0" diff --git a/crossbeam-channel/README.md b/crossbeam-channel/README.md index 90ed205e3..a8a1a7831 100644 --- a/crossbeam-channel/README.md +++ b/crossbeam-channel/README.md @@ -8,7 +8,7 @@ https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-channel#license) https://crates.io/crates/crossbeam-channel) [![Documentation](https://docs.rs/crossbeam-channel/badge.svg)]( https://docs.rs/crossbeam-channel) -[![Rust 1.61+](https://img.shields.io/badge/rust-1.61+-lightgray.svg)]( +[![Rust 1.60+](https://img.shields.io/badge/rust-1.60+-lightgray.svg)]( https://www.rust-lang.org) [![chat](https://img.shields.io/discord/569610676205781012.svg?logo=discord)](https://discord.com/invite/JXYwgWZ) @@ -48,7 +48,7 @@ crossbeam-channel = "0.5" Crossbeam Channel 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.61. +version is released. Currently, the minimum supported Rust version is 1.60. ## License diff --git a/crossbeam-channel/benchmarks/Cargo.toml b/crossbeam-channel/benchmarks/Cargo.toml index d42c645ce..751fdcedc 100644 --- a/crossbeam-channel/benchmarks/Cargo.toml +++ b/crossbeam-channel/benchmarks/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "benchmarks" -version = "0.1.0" -edition = "2018" +version = "0.0.0" +edition = "2021" publish = false [dependencies] diff --git a/crossbeam-channel/src/flavors/array.rs b/crossbeam-channel/src/flavors/array.rs index 63b82eb85..ccc47b527 100644 --- a/crossbeam-channel/src/flavors/array.rs +++ b/crossbeam-channel/src/flavors/array.rs @@ -9,7 +9,7 @@ //! - use std::cell::UnsafeCell; -use std::mem::MaybeUninit; +use std::mem::{self, MaybeUninit}; use std::ptr; use std::sync::atomic::{self, AtomicUsize, Ordering}; use std::time::Instant; @@ -520,37 +520,38 @@ impl Channel { impl Drop for Channel { fn drop(&mut self) { - // Get the index of the head. - let head = *self.head.get_mut(); - let tail = *self.tail.get_mut(); - - let hix = head & (self.mark_bit - 1); - let tix = tail & (self.mark_bit - 1); - - let len = if hix < tix { - tix - hix - } else if hix > tix { - self.cap - hix + tix - } else if (tail & !self.mark_bit) == head { - 0 - } else { - self.cap - }; - - // Loop over all slots that hold a message and drop them. - for i in 0..len { - // Compute the index of the next slot holding a message. - let index = if hix + i < self.cap { - hix + i + if mem::needs_drop::() { + // Get the index of the head. + let head = *self.head.get_mut(); + let tail = *self.tail.get_mut(); + + let hix = head & (self.mark_bit - 1); + let tix = tail & (self.mark_bit - 1); + + let len = if hix < tix { + tix - hix + } else if hix > tix { + self.cap - hix + tix + } else if (tail & !self.mark_bit) == head { + 0 } else { - hix + i - self.cap + self.cap }; - unsafe { - debug_assert!(index < self.buffer.len()); - let slot = self.buffer.get_unchecked_mut(index); - let msg = &mut *slot.msg.get(); - msg.as_mut_ptr().drop_in_place(); + // Loop over all slots that hold a message and drop them. + for i in 0..len { + // Compute the index of the next slot holding a message. + let index = if hix + i < self.cap { + hix + i + } else { + hix + i - self.cap + }; + + unsafe { + debug_assert!(index < self.buffer.len()); + let slot = self.buffer.get_unchecked_mut(index); + (*slot.msg.get()).assume_init_drop(); + } } } } diff --git a/crossbeam-channel/src/flavors/list.rs b/crossbeam-channel/src/flavors/list.rs index 230edd8d2..638d6c2ba 100644 --- a/crossbeam-channel/src/flavors/list.rs +++ b/crossbeam-channel/src/flavors/list.rs @@ -604,8 +604,7 @@ impl Channel { // Drop the message in the slot. let slot = (*block).slots.get_unchecked(offset); slot.wait_write(); - let p = &mut *slot.msg.get(); - p.as_mut_ptr().drop_in_place(); + (*slot.msg.get()).assume_init_drop(); } else { (*block).wait_next(); // Deallocate the block and move to the next one. @@ -663,8 +662,7 @@ impl Drop for Channel { if offset < BLOCK_CAP { // Drop the message in the slot. let slot = (*block).slots.get_unchecked(offset); - let p = &mut *slot.msg.get(); - p.as_mut_ptr().drop_in_place(); + (*slot.msg.get()).assume_init_drop(); } else { // Deallocate the block and move to the next one. let next = *(*block).next.get_mut(); diff --git a/crossbeam-channel/src/select_macro.rs b/crossbeam-channel/src/select_macro.rs index efe0ae406..43932a668 100644 --- a/crossbeam-channel/src/select_macro.rs +++ b/crossbeam-channel/src/select_macro.rs @@ -685,7 +685,7 @@ macro_rules! crossbeam_channel_internal { $default:tt ) => {{ const _LEN: usize = $crate::crossbeam_channel_internal!(@count ($($cases)*)); - let _handle: &$crate::internal::SelectHandle = &$crate::never::<()>(); + let _handle: &dyn $crate::internal::SelectHandle = &$crate::never::<()>(); #[allow(unused_mut)] let mut _sel = [(_handle, 0, ::std::ptr::null()); _LEN]; diff --git a/crossbeam-deque/Cargo.toml b/crossbeam-deque/Cargo.toml index 859a57705..d20ee0233 100644 --- a/crossbeam-deque/Cargo.toml +++ b/crossbeam-deque/Cargo.toml @@ -5,7 +5,7 @@ name = "crossbeam-deque" # - Update README.md # - Create "crossbeam-deque-X.Y.Z" git tag version = "0.8.4" -edition = "2018" +edition = "2021" rust-version = "1.61" license = "MIT OR Apache-2.0" repository = "https://github.com/crossbeam-rs/crossbeam" @@ -24,19 +24,10 @@ default = ["std"] std = ["crossbeam-epoch/std", "crossbeam-utils/std"] [dependencies] -cfg-if = "1" - -[dependencies.crossbeam-epoch] -version = "0.9.16" -path = "../crossbeam-epoch" -default-features = false -optional = true +crossbeam-epoch = { version = "0.9.17", path = "../crossbeam-epoch", default-features = false } +crossbeam-utils = { version = "0.8.18", path = "../crossbeam-utils", default-features = false } -[dependencies.crossbeam-utils] -version = "0.8.17" -path = "../crossbeam-utils" -default-features = false -optional = true +cfg-if = "1" [dev-dependencies] rand = "0.8" diff --git a/crossbeam-deque/src/deque.rs b/crossbeam-deque/src/deque.rs index c37de2dee..9344219ea 100644 --- a/crossbeam-deque/src/deque.rs +++ b/crossbeam-deque/src/deque.rs @@ -1,7 +1,6 @@ use std::cell::{Cell, UnsafeCell}; use std::cmp; use std::fmt; -use std::iter::FromIterator; use std::marker::PhantomData; use std::mem::{self, ManuallyDrop, MaybeUninit}; use std::ptr; @@ -1987,8 +1986,7 @@ impl Drop for Injector { if offset < BLOCK_CAP { // Drop the task in the slot. let slot = (*block).slots.get_unchecked(offset); - let p = &mut *slot.task.get(); - p.as_mut_ptr().drop_in_place(); + (*slot.task.get()).assume_init_drop(); } else { // Deallocate the block and move to the next one. let next = *(*block).next.get_mut(); diff --git a/crossbeam-epoch/CHANGELOG.md b/crossbeam-epoch/CHANGELOG.md index c81580e51..efd0de97f 100644 --- a/crossbeam-epoch/CHANGELOG.md +++ b/crossbeam-epoch/CHANGELOG.md @@ -1,3 +1,7 @@ +# Version 0.9.17 + +- Remove dependency on `memoffset`. (#1058) + # Version 0.9.16 - Bump the minimum supported Rust version to 1.61. (#1037) diff --git a/crossbeam-epoch/Cargo.toml b/crossbeam-epoch/Cargo.toml index be4628d03..80d7e4e6f 100644 --- a/crossbeam-epoch/Cargo.toml +++ b/crossbeam-epoch/Cargo.toml @@ -4,8 +4,8 @@ name = "crossbeam-epoch" # - Update CHANGELOG.md # - Update README.md # - Create "crossbeam-epoch-X.Y.Z" git tag -version = "0.9.16" -edition = "2018" +version = "0.9.17" +edition = "2021" rust-version = "1.61" license = "MIT OR Apache-2.0" repository = "https://github.com/crossbeam-rs/crossbeam" @@ -46,8 +46,9 @@ loom = ["loom-crate", "crossbeam-utils/loom"] autocfg = "1" [dependencies] +crossbeam-utils = { version = "0.8.18", path = "../crossbeam-utils", default-features = false } + cfg-if = "1" -memoffset = "0.9" # Enable the use of loom for concurrency testing. # @@ -56,10 +57,5 @@ memoffset = "0.9" [target.'cfg(crossbeam_loom)'.dependencies] loom-crate = { package = "loom", version = "0.7.1", optional = true } -[dependencies.crossbeam-utils] -version = "0.8.17" -path = "../crossbeam-utils" -default-features = false - [dev-dependencies] rand = "0.8" diff --git a/crossbeam-epoch/src/atomic.rs b/crossbeam-epoch/src/atomic.rs index 0dc61021a..41b4cd910 100644 --- a/crossbeam-epoch/src/atomic.rs +++ b/crossbeam-epoch/src/atomic.rs @@ -1,13 +1,14 @@ +use alloc::boxed::Box; +use core::alloc::Layout; use core::borrow::{Borrow, BorrowMut}; use core::cmp; use core::fmt; use core::marker::PhantomData; use core::mem::{self, MaybeUninit}; use core::ops::{Deref, DerefMut}; +use core::ptr; use core::slice; -use crate::alloc::alloc; -use crate::alloc::boxed::Box; use crate::guard::Guard; use crate::primitive::sync::atomic::{AtomicUsize, Ordering}; use crossbeam_utils::atomic::AtomicConsume; @@ -232,9 +233,6 @@ impl Pointable for T { /// /// Elements are not present in the type, but they will be in the allocation. /// ``` -/// -// TODO(@jeehoonkang): once we bump the minimum required Rust version to 1.44 or newer, use -// [`alloc::alloc::Layout::extend`] instead. #[repr(C)] struct Array { /// The number of elements (not the number of bytes). @@ -242,20 +240,28 @@ struct Array { elements: [MaybeUninit; 0], } +impl Array { + fn layout(len: usize) -> Layout { + Layout::new::() + .extend(Layout::array::>(len).unwrap()) + .unwrap() + .0 + .pad_to_align() + } +} + impl Pointable for [MaybeUninit] { const ALIGN: usize = mem::align_of::>(); type Init = usize; unsafe fn init(len: Self::Init) -> usize { - let size = mem::size_of::>() + mem::size_of::>() * len; - let align = mem::align_of::>(); - let layout = alloc::Layout::from_size_align(size, align).unwrap(); - let ptr = alloc::alloc(layout).cast::>(); + let layout = Array::::layout(len); + let ptr = alloc::alloc::alloc(layout).cast::>(); if ptr.is_null() { - alloc::handle_alloc_error(layout); + alloc::alloc::handle_alloc_error(layout); } - (*ptr).len = len; + ptr::addr_of_mut!((*ptr).len).write(len); ptr as usize } @@ -270,11 +276,9 @@ impl Pointable for [MaybeUninit] { } unsafe fn drop(ptr: usize) { - let array = &*(ptr as *mut Array); - let size = mem::size_of::>() + mem::size_of::>() * array.len; - let align = mem::align_of::>(); - let layout = alloc::Layout::from_size_align(size, align).unwrap(); - alloc::dealloc(ptr as *mut u8, layout); + let len = (*(ptr as *mut Array)).len; + let layout = Array::::layout(len); + alloc::alloc::dealloc(ptr as *mut u8, layout); } } diff --git a/crossbeam-epoch/src/internal.rs b/crossbeam-epoch/src/internal.rs index 93065fa6b..b2e9e71bc 100644 --- a/crossbeam-epoch/src/internal.rs +++ b/crossbeam-epoch/src/internal.rs @@ -43,7 +43,6 @@ use core::num::Wrapping; use core::{fmt, ptr}; use crossbeam_utils::CachePadded; -use memoffset::offset_of; use crate::atomic::{Owned, Shared}; use crate::collector::{Collector, LocalHandle}; @@ -268,6 +267,7 @@ impl Global { } /// Participant for garbage collection. +#[repr(C)] // Note: `entry` must be the first field pub(crate) struct Local { /// A node in the intrusive linked list of `Local`s. entry: Entry, @@ -534,16 +534,18 @@ impl Local { } } -impl IsElement for Local { - fn entry_of(local: &Local) -> &Entry { - let entry_ptr = (local as *const Local as usize + offset_of!(Local, entry)) as *const Entry; - unsafe { &*entry_ptr } +impl IsElement for Local { + fn entry_of(local: &Self) -> &Entry { + // SAFETY: `Local` is `repr(C)` and `entry` is the first field of it. + unsafe { + let entry_ptr = (local as *const Self).cast::(); + &*entry_ptr + } } - unsafe fn element_of(entry: &Entry) -> &Local { - // offset_of! macro uses unsafe, but it's unnecessary in this context. - #[allow(unused_unsafe)] - let local_ptr = (entry as *const Entry as usize - offset_of!(Local, entry)) as *const Local; + unsafe fn element_of(entry: &Entry) -> &Self { + // SAFETY: `Local` is `repr(C)` and `entry` is the first field of it. + let local_ptr = (entry as *const Entry).cast::(); &*local_ptr } diff --git a/crossbeam-epoch/src/sync/queue.rs b/crossbeam-epoch/src/sync/queue.rs index 950043881..76c326beb 100644 --- a/crossbeam-epoch/src/sync/queue.rs +++ b/crossbeam-epoch/src/sync/queue.rs @@ -132,8 +132,7 @@ impl Queue { .compare_exchange(tail, next, Release, Relaxed, guard); } guard.defer_destroy(head); - // TODO: Replace with MaybeUninit::read when api is stable - Some(n.data.as_ptr().read()) + Some(n.data.assume_init_read()) }) .map_err(|_| ()) }, @@ -165,7 +164,7 @@ impl Queue { .compare_exchange(tail, next, Release, Relaxed, guard); } guard.defer_destroy(head); - Some(n.data.as_ptr().read()) + Some(n.data.assume_init_read()) }) .map_err(|_| ()) }, diff --git a/crossbeam-queue/CHANGELOG.md b/crossbeam-queue/CHANGELOG.md index 1023c3fa9..2e1b3e5bc 100644 --- a/crossbeam-queue/CHANGELOG.md +++ b/crossbeam-queue/CHANGELOG.md @@ -1,3 +1,9 @@ +# Version 0.3.10 + +- Relax the minimum supported Rust version to 1.60. (#1056) +- Implement `UnwindSafe` and `RefUnwindSafe` for `ArrayQueue` and `SegQueue`. (#1053) +- Optimize `Drop` implementation of `ArrayQueue`. (#1057) + # Version 0.3.9 - Bump the minimum supported Rust version to 1.61. (#1037) diff --git a/crossbeam-queue/Cargo.toml b/crossbeam-queue/Cargo.toml index 3d74523ee..ad211d996 100644 --- a/crossbeam-queue/Cargo.toml +++ b/crossbeam-queue/Cargo.toml @@ -4,9 +4,9 @@ name = "crossbeam-queue" # - Update CHANGELOG.md # - Update README.md # - Create "crossbeam-queue-X.Y.Z" git tag -version = "0.3.9" -edition = "2018" -rust-version = "1.61" +version = "0.3.10" +edition = "2021" +rust-version = "1.60" license = "MIT OR Apache-2.0" repository = "https://github.com/crossbeam-rs/crossbeam" homepage = "https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-queue" @@ -37,12 +37,9 @@ alloc = [] nightly = ["crossbeam-utils/nightly"] [dependencies] -cfg-if = "1" +crossbeam-utils = { version = "0.8.18", path = "../crossbeam-utils", default-features = false } -[dependencies.crossbeam-utils] -version = "0.8.17" -path = "../crossbeam-utils" -default-features = false +cfg-if = "1" [dev-dependencies] rand = "0.8" diff --git a/crossbeam-queue/README.md b/crossbeam-queue/README.md index 6b3372ce6..902679086 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.61+](https://img.shields.io/badge/rust-1.61+-lightgray.svg)]( +[![Rust 1.60+](https://img.shields.io/badge/rust-1.60+-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.61. +version is released. Currently, the minimum supported Rust version is 1.60. ## License diff --git a/crossbeam-queue/src/array_queue.rs b/crossbeam-queue/src/array_queue.rs index e07fde8a8..3f6d19533 100644 --- a/crossbeam-queue/src/array_queue.rs +++ b/crossbeam-queue/src/array_queue.rs @@ -6,7 +6,8 @@ use alloc::boxed::Box; use core::cell::UnsafeCell; use core::fmt; -use core::mem::MaybeUninit; +use core::mem::{self, MaybeUninit}; +use core::panic::{RefUnwindSafe, UnwindSafe}; use core::sync::atomic::{self, AtomicUsize, Ordering}; use crossbeam_utils::{Backoff, CachePadded}; @@ -76,6 +77,9 @@ pub struct ArrayQueue { unsafe impl Sync for ArrayQueue {} unsafe impl Send for ArrayQueue {} +impl UnwindSafe for ArrayQueue {} +impl RefUnwindSafe for ArrayQueue {} + impl ArrayQueue { /// Creates a new bounded queue with the given capacity. /// @@ -443,37 +447,38 @@ impl ArrayQueue { impl Drop for ArrayQueue { fn drop(&mut self) { - // Get the index of the head. - let head = *self.head.get_mut(); - let tail = *self.tail.get_mut(); - - let hix = head & (self.one_lap - 1); - let tix = tail & (self.one_lap - 1); - - let len = if hix < tix { - tix - hix - } else if hix > tix { - self.cap - hix + tix - } else if tail == head { - 0 - } else { - self.cap - }; - - // Loop over all slots that hold a message and drop them. - for i in 0..len { - // Compute the index of the next slot holding a message. - let index = if hix + i < self.cap { - hix + i + if mem::needs_drop::() { + // Get the index of the head. + let head = *self.head.get_mut(); + let tail = *self.tail.get_mut(); + + let hix = head & (self.one_lap - 1); + let tix = tail & (self.one_lap - 1); + + let len = if hix < tix { + tix - hix + } else if hix > tix { + self.cap - hix + tix + } else if tail == head { + 0 } else { - hix + i - self.cap + self.cap }; - unsafe { - debug_assert!(index < self.buffer.len()); - let slot = self.buffer.get_unchecked_mut(index); - let value = &mut *slot.value.get(); - value.as_mut_ptr().drop_in_place(); + // Loop over all slots that hold a message and drop them. + for i in 0..len { + // Compute the index of the next slot holding a message. + let index = if hix + i < self.cap { + hix + i + } else { + hix + i - self.cap + }; + + unsafe { + debug_assert!(index < self.buffer.len()); + let slot = self.buffer.get_unchecked_mut(index); + (*slot.value.get()).assume_init_drop(); + } } } } diff --git a/crossbeam-queue/src/seg_queue.rs b/crossbeam-queue/src/seg_queue.rs index 2761dc07c..973a77f81 100644 --- a/crossbeam-queue/src/seg_queue.rs +++ b/crossbeam-queue/src/seg_queue.rs @@ -3,6 +3,7 @@ use core::cell::UnsafeCell; use core::fmt; use core::marker::PhantomData; use core::mem::MaybeUninit; +use core::panic::{RefUnwindSafe, UnwindSafe}; use core::ptr; use core::sync::atomic::{self, AtomicPtr, AtomicUsize, Ordering}; @@ -148,6 +149,9 @@ pub struct SegQueue { unsafe impl Send for SegQueue {} unsafe impl Sync for SegQueue {} +impl UnwindSafe for SegQueue {} +impl RefUnwindSafe for SegQueue {} + impl SegQueue { /// Creates a new unbounded queue. /// @@ -455,8 +459,7 @@ impl Drop for SegQueue { if offset < BLOCK_CAP { // Drop the value in the slot. let slot = (*block).slots.get_unchecked(offset); - let p = &mut *slot.value.get(); - p.as_mut_ptr().drop_in_place(); + (*slot.value.get()).assume_init_drop(); } else { // Deallocate the block and move to the next one. let next = *(*block).next.get_mut(); @@ -521,8 +524,7 @@ impl Iterator for IntoIter { // and this is a non-empty queue. let item = unsafe { let slot = (*block).slots.get_unchecked(offset); - let p = &mut *slot.value.get(); - p.as_mut_ptr().read() + slot.value.get().read().assume_init() }; if offset + 1 == BLOCK_CAP { // Deallocate the block and move to the next one. diff --git a/crossbeam-skiplist/Cargo.toml b/crossbeam-skiplist/Cargo.toml index 405bd2f02..1e8d86a42 100644 --- a/crossbeam-skiplist/Cargo.toml +++ b/crossbeam-skiplist/Cargo.toml @@ -5,7 +5,7 @@ name = "crossbeam-skiplist" # - Update README.md # - Create "crossbeam-skiplist-X.Y.Z" git tag version = "0.0.0" -edition = "2018" +edition = "2021" rust-version = "1.61" license = "MIT OR Apache-2.0" repository = "https://github.com/crossbeam-rs/crossbeam" @@ -28,18 +28,10 @@ std = ["alloc", "crossbeam-epoch/std", "crossbeam-utils/std"] alloc = ["crossbeam-epoch/alloc"] [dependencies] -cfg-if = "1" - -[dependencies.crossbeam-epoch] -version = "0.9.16" -path = "../crossbeam-epoch" -default-features = false -optional = true +crossbeam-epoch = { version = "0.9.17", path = "../crossbeam-epoch", default-features = false } +crossbeam-utils = { version = "0.8.18", path = "../crossbeam-utils", default-features = false } -[dependencies.crossbeam-utils] -version = "0.8.17" -path = "../crossbeam-utils" -default-features = false +cfg-if = "1" [dev-dependencies] rand = "0.8" diff --git a/crossbeam-skiplist/src/base.rs b/crossbeam-skiplist/src/base.rs index b63183650..44ee07332 100644 --- a/crossbeam-skiplist/src/base.rs +++ b/crossbeam-skiplist/src/base.rs @@ -104,11 +104,11 @@ impl Node { handle_alloc_error(layout); } - ptr::write( - &mut (*ptr).refs_and_height, - AtomicUsize::new((height - 1) | ref_count << HEIGHT_BITS), - ); - ptr::write_bytes((*ptr).tower.pointers.as_mut_ptr(), 0, height); + ptr::addr_of_mut!((*ptr).refs_and_height) + .write(AtomicUsize::new((height - 1) | ref_count << HEIGHT_BITS)); + ptr::addr_of_mut!((*ptr).tower.pointers) + .cast::>() + .write_bytes(0, height); ptr } @@ -122,14 +122,14 @@ impl Node { } /// Returns the layout of a node with the given `height`. - unsafe fn get_layout(height: usize) -> Layout { + fn get_layout(height: usize) -> Layout { assert!((1..=MAX_HEIGHT).contains(&height)); - let size_self = mem::size_of::(); - let align_self = mem::align_of::(); - let size_pointer = mem::size_of::>(); - - Layout::from_size_align_unchecked(size_self + size_pointer * height, align_self) + Layout::new::() + .extend(Layout::array::>(height).unwrap()) + .unwrap() + .0 + .pad_to_align() } /// Returns the height of this node's tower. @@ -906,8 +906,8 @@ where let n = Node::::alloc(height, 2); // Write the key and the value into the node. - ptr::write(&mut (*n).key, key); - ptr::write(&mut (*n).value, value); + ptr::addr_of_mut!((*n).key).write(key); + ptr::addr_of_mut!((*n).value).write(value); (Shared::>::from(n as *const _), &*n) }; diff --git a/crossbeam-skiplist/src/map.rs b/crossbeam-skiplist/src/map.rs index e10f3c137..3b60eec9c 100644 --- a/crossbeam-skiplist/src/map.rs +++ b/crossbeam-skiplist/src/map.rs @@ -2,7 +2,6 @@ use std::borrow::Borrow; use std::fmt; -use std::iter::FromIterator; use std::mem::ManuallyDrop; use std::ops::{Bound, RangeBounds}; use std::ptr; diff --git a/crossbeam-skiplist/src/set.rs b/crossbeam-skiplist/src/set.rs index cc4083472..6355a00da 100644 --- a/crossbeam-skiplist/src/set.rs +++ b/crossbeam-skiplist/src/set.rs @@ -2,7 +2,6 @@ use std::borrow::Borrow; use std::fmt; -use std::iter::FromIterator; use std::ops::Deref; use std::ops::{Bound, RangeBounds}; diff --git a/crossbeam-utils/CHANGELOG.md b/crossbeam-utils/CHANGELOG.md index 154169696..34c6bbda8 100644 --- a/crossbeam-utils/CHANGELOG.md +++ b/crossbeam-utils/CHANGELOG.md @@ -1,8 +1,13 @@ +# Version 0.8.18 + +- Relax the minimum supported Rust version to 1.60. (#1056) +- Improve scalability of `AtomicCell` fallback. (#1055) + # Version 0.8.17 - Bump the minimum supported Rust version to 1.61. (#1037) - Improve support for targets without atomic CAS or 64-bit atomic. (#1037) -- Always implement `{,Ref}UnwindSafe` for AtomicCell. (#1045) +- Always implement `UnwindSafe` and `RefUnwindSafe` for `AtomicCell`. (#1045) - Improve compatibility with Miri, TSan, and loom. (#995, #1003) - Improve compatibility with unstable `oom=panic`. (#1045) - Improve implementation of `CachePadded`. (#1014, #1025) diff --git a/crossbeam-utils/Cargo.toml b/crossbeam-utils/Cargo.toml index cb16c7e4e..66d8201c4 100644 --- a/crossbeam-utils/Cargo.toml +++ b/crossbeam-utils/Cargo.toml @@ -4,9 +4,9 @@ name = "crossbeam-utils" # - Update CHANGELOG.md # - Update README.md # - Create "crossbeam-utils-X.Y.Z" git tag -version = "0.8.17" -edition = "2018" -rust-version = "1.61" +version = "0.8.18" +edition = "2021" +rust-version = "1.60" license = "MIT OR Apache-2.0" repository = "https://github.com/crossbeam-rs/crossbeam" homepage = "https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-utils" diff --git a/crossbeam-utils/README.md b/crossbeam-utils/README.md index 7f87fcb1d..7d6a67948 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.61+](https://img.shields.io/badge/rust-1.61+-lightgray.svg)]( +[![Rust 1.60+](https://img.shields.io/badge/rust-1.60+-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.61. +version is released. Currently, the minimum supported Rust version is 1.60. ## License diff --git a/crossbeam-utils/src/atomic/atomic_cell.rs b/crossbeam-utils/src/atomic/atomic_cell.rs index 165faec76..06ccf2eb5 100644 --- a/crossbeam-utils/src/atomic/atomic_cell.rs +++ b/crossbeam-utils/src/atomic/atomic_cell.rs @@ -2,6 +2,7 @@ #![allow(clippy::unit_arg)] use crate::primitive::sync::atomic::{self, Ordering}; +use crate::CachePadded; use core::cell::UnsafeCell; use core::cmp; use core::fmt; @@ -998,10 +999,10 @@ fn lock(addr: usize) -> &'static SeqLock { // Now, if we have a slice of type `&[Foo]`, it is possible that field `a` in all items gets // stored at addresses that are multiples of 3. It'd be too bad if `LEN` was divisible by 3. // In order to protect from such cases, we simply choose a large prime number for `LEN`. - const LEN: usize = 97; + const LEN: usize = 67; #[allow(clippy::declare_interior_mutable_const)] - const L: SeqLock = SeqLock::new(); - static LOCKS: [SeqLock; LEN] = [L; LEN]; + const L: CachePadded = CachePadded::new(SeqLock::new()); + static LOCKS: [CachePadded; LEN] = [L; LEN]; // If the modulus is a constant number, the compiler will use crazy math to transform this into // a sequence of cheap arithmetic operations rather than using the slow modulo instruction. diff --git a/crossbeam-utils/src/sync/once_lock.rs b/crossbeam-utils/src/sync/once_lock.rs index 761851b01..e057aca7d 100644 --- a/crossbeam-utils/src/sync/once_lock.rs +++ b/crossbeam-utils/src/sync/once_lock.rs @@ -61,13 +61,11 @@ impl OnceLock { where F: FnOnce() -> T, { - let slot = self.value.get().cast::(); + let slot = self.value.get(); self.once.call_once(|| { let value = f(); - unsafe { - slot.write(value); - } + unsafe { slot.write(MaybeUninit::new(value)) } }); } @@ -84,7 +82,7 @@ impl Drop for OnceLock { fn drop(&mut self) { if self.once.is_completed() { // SAFETY: The inner value has been initialized - unsafe { self.value.get().cast::().drop_in_place() }; + unsafe { (*self.value.get()).assume_init_drop() }; } } } diff --git a/crossbeam-utils/src/thread.rs b/crossbeam-utils/src/thread.rs index f71fdea21..2d4805e12 100644 --- a/crossbeam-utils/src/thread.rs +++ b/crossbeam-utils/src/thread.rs @@ -84,7 +84,7 @@ //! tricky because argument `s` lives *inside* the invocation of `thread::scope()` and as such //! cannot be borrowed by scoped threads: //! -//! ```compile_fail,E0373,E0521 +//! ```compile_fail,E0521 //! use crossbeam_utils::thread; //! //! thread::scope(|s| {