aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cargo_vcs_info.json2
-rw-r--r--Android.bp6
-rw-r--r--CHANGELOG.md18
-rw-r--r--Cargo.toml5
-rw-r--r--Cargo.toml.orig4
-rw-r--r--METADATA12
-rw-r--r--README.md4
-rw-r--r--build-common.rs13
-rw-r--r--build.rs10
-rw-r--r--no_atomic.rs13
-rw-r--r--src/array_queue.rs145
-rw-r--r--src/seg_queue.rs24
-rw-r--r--tests/array_queue.rs132
-rw-r--r--tests/seg_queue.rs19
14 files changed, 320 insertions, 87 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 1c48586..1c674b3 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,6 +1,6 @@
{
"git": {
- "sha1": "2988f873f87d2263a7fd2b9465fb9c28f43a6490"
+ "sha1": "366276a4dde8bd6b4bdab531c09e6ab1ff38c407"
},
"path_in_vcs": "crossbeam-queue"
} \ No newline at end of file
diff --git a/Android.bp b/Android.bp
index 2ac5b4a..047b21e 100644
--- a/Android.bp
+++ b/Android.bp
@@ -43,7 +43,7 @@ rust_defaults {
name: "crossbeam-queue_test_defaults",
crate_name: "crossbeam_queue",
cargo_env_compat: true,
- cargo_pkg_version: "0.3.4",
+ cargo_pkg_version: "0.3.8",
test_suites: ["general-tests"],
auto_gen_config: true,
edition: "2018",
@@ -85,7 +85,7 @@ rust_library {
host_supported: true,
crate_name: "crossbeam_queue",
cargo_env_compat: true,
- cargo_pkg_version: "0.3.4",
+ cargo_pkg_version: "0.3.8",
srcs: ["src/lib.rs"],
edition: "2018",
features: [
@@ -101,4 +101,6 @@ rust_library {
"//apex_available:platform",
"com.android.virt",
],
+ product_available: true,
+ vendor_available: true,
}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index bf79c5e..79aaacd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,21 @@
+# Version 0.3.8
+
+- Fix build script bug introduced in 0.3.7. (#932)
+
+# Version 0.3.7
+
+**Note:** This release has been yanked due to regression fixed in 0.3.8.
+
+- Improve support for custom targets. (#922)
+
+# Version 0.3.6
+
+- Bump the minimum supported Rust version to 1.38. (#877)
+
+# Version 0.3.5
+
+- Add `ArrayQueue::force_push`. (#789)
+
# Version 0.3.4
- Implement `IntoIterator` for `ArrayQueue` and `SegQueue`. (#772)
diff --git a/Cargo.toml b/Cargo.toml
index 5c1e3b3..2b775fb 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -11,11 +11,12 @@
[package]
edition = "2018"
-rust-version = "1.36"
+rust-version = "1.38"
name = "crossbeam-queue"
-version = "0.3.4"
+version = "0.3.8"
description = "Concurrent queues"
homepage = "https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-queue"
+readme = "README.md"
keywords = [
"queue",
"mpmc",
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index ac68694..27c386c 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -4,9 +4,9 @@ name = "crossbeam-queue"
# - Update CHANGELOG.md
# - Update README.md
# - Create "crossbeam-queue-X.Y.Z" git tag
-version = "0.3.4"
+version = "0.3.8"
edition = "2018"
-rust-version = "1.36"
+rust-version = "1.38"
license = "MIT OR Apache-2.0"
repository = "https://github.com/crossbeam-rs/crossbeam"
homepage = "https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-queue"
diff --git a/METADATA b/METADATA
index 6338467..4acf935 100644
--- a/METADATA
+++ b/METADATA
@@ -1,3 +1,7 @@
+# This project was upgraded with external_updater.
+# Usage: tools/external_updater/updater.sh update rust/crates/crossbeam-queue
+# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md
+
name: "crossbeam-queue"
description: "Concurrent queues"
third_party {
@@ -7,13 +11,13 @@ third_party {
}
url {
type: ARCHIVE
- value: "https://static.crates.io/crates/crossbeam-queue/crossbeam-queue-0.3.4.crate"
+ value: "https://static.crates.io/crates/crossbeam-queue/crossbeam-queue-0.3.8.crate"
}
- version: "0.3.4"
+ version: "0.3.8"
license_type: NOTICE
last_upgrade_date {
year: 2022
- month: 3
- day: 1
+ month: 12
+ day: 8
}
}
diff --git a/README.md b/README.md
index 2f30b39..85671ef 100644
--- a/README.md
+++ b/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.36+](https://img.shields.io/badge/rust-1.36+-lightgray.svg)](
+[![Rust 1.38+](https://img.shields.io/badge/rust-1.38+-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.36.
+version is released. Currently, the minimum supported Rust version is 1.38.
## License
diff --git a/build-common.rs b/build-common.rs
new file mode 100644
index 0000000..e91bb4d
--- /dev/null
+++ b/build-common.rs
@@ -0,0 +1,13 @@
+// The target triplets have the form of 'arch-vendor-system'.
+//
+// When building for Linux (e.g. the 'system' part is
+// 'linux-something'), replace the vendor with 'unknown'
+// so that mapping to rust standard targets happens correctly.
+fn convert_custom_linux_target(target: String) -> String {
+ let mut parts: Vec<&str> = target.split('-').collect();
+ let system = parts.get(2);
+ if system == Some(&"linux") {
+ parts[1] = "unknown";
+ };
+ parts.join("-")
+}
diff --git a/build.rs b/build.rs
index 587e058..6975dd8 100644
--- a/build.rs
+++ b/build.rs
@@ -15,10 +15,11 @@
use std::env;
include!("no_atomic.rs");
+include!("build-common.rs");
fn main() {
let target = match env::var("TARGET") {
- Ok(target) => target,
+ Ok(target) => convert_custom_linux_target(target),
Err(e) => {
println!(
"cargo:warning={}: unable to get TARGET environment variable: {}",
@@ -29,10 +30,9 @@ fn main() {
}
};
- // 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.
+ // Note that this is `no_`*, not `has_*`. This allows treating as the latest
+ // stable rustc is used when the build script doesn't run. This is useful
+ // for non-cargo build systems that don't run the build script.
if NO_ATOMIC_CAS.contains(&&*target) {
println!("cargo:rustc-cfg=crossbeam_no_atomic_cas");
}
diff --git a/no_atomic.rs b/no_atomic.rs
index 90ac60a..8ce0d31 100644
--- a/no_atomic.rs
+++ b/no_atomic.rs
@@ -2,13 +2,17 @@
// It is not intended for manual editing.
const NO_ATOMIC_CAS: &[&str] = &[
+ "armv4t-none-eabi",
+ "armv5te-none-eabi",
"avr-unknown-gnu-atmega328",
"bpfeb-unknown-none",
"bpfel-unknown-none",
"msp430-none-elf",
"riscv32i-unknown-none-elf",
+ "riscv32im-unknown-none-elf",
"riscv32imc-unknown-none-elf",
"thumbv4t-none-eabi",
+ "thumbv5te-none-eabi",
"thumbv6m-none-eabi",
];
@@ -17,7 +21,9 @@ const NO_ATOMIC_64: &[&str] = &[
"arm-linux-androideabi",
"armebv7r-none-eabi",
"armebv7r-none-eabihf",
+ "armv4t-none-eabi",
"armv4t-unknown-linux-gnueabi",
+ "armv5te-none-eabi",
"armv5te-unknown-linux-gnueabi",
"armv5te-unknown-linux-musleabi",
"armv5te-unknown-linux-uclibceabi",
@@ -31,6 +37,7 @@ const NO_ATOMIC_64: &[&str] = &[
"mips-unknown-linux-musl",
"mips-unknown-linux-uclibc",
"mipsel-sony-psp",
+ "mipsel-sony-psx",
"mipsel-unknown-linux-gnu",
"mipsel-unknown-linux-musl",
"mipsel-unknown-linux-uclibc",
@@ -49,10 +56,12 @@ const NO_ATOMIC_64: &[&str] = &[
"riscv32gc-unknown-linux-gnu",
"riscv32gc-unknown-linux-musl",
"riscv32i-unknown-none-elf",
+ "riscv32im-unknown-none-elf",
"riscv32imac-unknown-none-elf",
- "riscv32imc-esp-espidf",
+ "riscv32imac-unknown-xous-elf",
"riscv32imc-unknown-none-elf",
"thumbv4t-none-eabi",
+ "thumbv5te-none-eabi",
"thumbv6m-none-eabi",
"thumbv7em-none-eabi",
"thumbv7em-none-eabihf",
@@ -65,7 +74,9 @@ const NO_ATOMIC_64: &[&str] = &[
#[allow(dead_code)] // Only crossbeam-utils uses this.
const NO_ATOMIC: &[&str] = &[
"avr-unknown-gnu-atmega328",
+ "mipsel-sony-psx",
"msp430-none-elf",
"riscv32i-unknown-none-elf",
+ "riscv32im-unknown-none-elf",
"riscv32imc-unknown-none-elf",
];
diff --git a/src/array_queue.rs b/src/array_queue.rs
index 5f3061b..e07fde8 100644
--- a/src/array_queue.rs
+++ b/src/array_queue.rs
@@ -27,9 +27,11 @@ struct Slot<T> {
///
/// This queue allocates a fixed-capacity buffer on construction, which is used to store pushed
/// elements. The queue cannot hold more elements than the buffer allows. Attempting to push an
-/// element into a full queue will fail. Having a buffer allocated upfront makes this queue a bit
-/// faster than [`SegQueue`].
+/// element into a full queue will fail. Alternatively, [`force_push`] makes it possible for
+/// this queue to be used as a ring-buffer. Having a buffer allocated upfront makes this queue
+/// a bit faster than [`SegQueue`].
///
+/// [`force_push`]: ArrayQueue::force_push
/// [`SegQueue`]: super::SegQueue
///
/// # Examples
@@ -120,21 +122,10 @@ impl<T> ArrayQueue<T> {
}
}
- /// Attempts to push an element into the queue.
- ///
- /// If the queue is full, the element is returned back as an error.
- ///
- /// # Examples
- ///
- /// ```
- /// use crossbeam_queue::ArrayQueue;
- ///
- /// let q = ArrayQueue::new(1);
- ///
- /// assert_eq!(q.push(10), Ok(()));
- /// assert_eq!(q.push(20), Err(20));
- /// ```
- pub fn push(&self, value: T) -> Result<(), T> {
+ fn push_or_else<F>(&self, mut value: T, f: F) -> Result<(), T>
+ where
+ F: Fn(T, usize, usize, &Slot<T>) -> Result<T, T>,
+ {
let backoff = Backoff::new();
let mut tail = self.tail.load(Ordering::Relaxed);
@@ -143,6 +134,16 @@ impl<T> ArrayQueue<T> {
let index = tail & (self.one_lap - 1);
let lap = tail & !(self.one_lap - 1);
+ let new_tail = if index + 1 < self.cap {
+ // Same lap, incremented index.
+ // Set to `{ lap: lap, index: index + 1 }`.
+ tail + 1
+ } else {
+ // One lap forward, index wraps around to zero.
+ // Set to `{ lap: lap.wrapping_add(1), index: 0 }`.
+ lap.wrapping_add(self.one_lap)
+ };
+
// Inspect the corresponding slot.
debug_assert!(index < self.buffer.len());
let slot = unsafe { self.buffer.get_unchecked(index) };
@@ -150,16 +151,6 @@ impl<T> ArrayQueue<T> {
// If the tail and the stamp match, we may attempt to push.
if tail == stamp {
- let new_tail = if index + 1 < self.cap {
- // Same lap, incremented index.
- // Set to `{ lap: lap, index: index + 1 }`.
- tail + 1
- } else {
- // One lap forward, index wraps around to zero.
- // Set to `{ lap: lap.wrapping_add(1), index: 0 }`.
- lap.wrapping_add(self.one_lap)
- };
-
// Try moving the tail.
match self.tail.compare_exchange_weak(
tail,
@@ -182,14 +173,7 @@ impl<T> ArrayQueue<T> {
}
} else if stamp.wrapping_add(self.one_lap) == tail + 1 {
atomic::fence(Ordering::SeqCst);
- let head = self.head.load(Ordering::Relaxed);
-
- // If the head lags one lap behind the tail as well...
- if head.wrapping_add(self.one_lap) == tail {
- // ...then the queue is full.
- return Err(value);
- }
-
+ value = f(value, tail, new_tail, slot)?;
backoff.spin();
tail = self.tail.load(Ordering::Relaxed);
} else {
@@ -200,6 +184,79 @@ impl<T> ArrayQueue<T> {
}
}
+ /// Attempts to push an element into the queue.
+ ///
+ /// If the queue is full, the element is returned back as an error.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use crossbeam_queue::ArrayQueue;
+ ///
+ /// let q = ArrayQueue::new(1);
+ ///
+ /// assert_eq!(q.push(10), Ok(()));
+ /// assert_eq!(q.push(20), Err(20));
+ /// ```
+ pub fn push(&self, value: T) -> Result<(), T> {
+ self.push_or_else(value, |v, tail, _, _| {
+ let head = self.head.load(Ordering::Relaxed);
+
+ // If the head lags one lap behind the tail as well...
+ if head.wrapping_add(self.one_lap) == tail {
+ // ...then the queue is full.
+ Err(v)
+ } else {
+ Ok(v)
+ }
+ })
+ }
+
+ /// Pushes an element into the queue, replacing the oldest element if necessary.
+ ///
+ /// If the queue is full, the oldest element is replaced and returned,
+ /// otherwise `None` is returned.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use crossbeam_queue::ArrayQueue;
+ ///
+ /// let q = ArrayQueue::new(2);
+ ///
+ /// assert_eq!(q.force_push(10), None);
+ /// assert_eq!(q.force_push(20), None);
+ /// assert_eq!(q.force_push(30), Some(10));
+ /// assert_eq!(q.pop(), Some(20));
+ /// ```
+ pub fn force_push(&self, value: T) -> Option<T> {
+ self.push_or_else(value, |v, tail, new_tail, slot| {
+ let head = tail.wrapping_sub(self.one_lap);
+ let new_head = new_tail.wrapping_sub(self.one_lap);
+
+ // Try moving the head.
+ if self
+ .head
+ .compare_exchange_weak(head, new_head, Ordering::SeqCst, Ordering::Relaxed)
+ .is_ok()
+ {
+ // Move the tail.
+ self.tail.store(new_tail, Ordering::SeqCst);
+
+ // Swap the previous value.
+ let old = unsafe { slot.value.get().replace(MaybeUninit::new(v)).assume_init() };
+
+ // Update the stamp.
+ slot.stamp.store(tail + 1, Ordering::Release);
+
+ Err(old)
+ } else {
+ Ok(v)
+ }
+ })
+ .err()
+ }
+
/// Attempts to pop an element from the queue.
///
/// If the queue is empty, `None` is returned.
@@ -387,10 +444,24 @@ impl<T> ArrayQueue<T> {
impl<T> Drop for ArrayQueue<T> {
fn drop(&mut self) {
// Get the index of the head.
- let hix = self.head.load(Ordering::Relaxed) & (self.one_lap - 1);
+ 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..self.len() {
+ for i in 0..len {
// Compute the index of the next slot holding a message.
let index = if hix + i < self.cap {
hix + i
diff --git a/src/seg_queue.rs b/src/seg_queue.rs
index 1767775..2761dc0 100644
--- a/src/seg_queue.rs
+++ b/src/seg_queue.rs
@@ -35,6 +35,11 @@ struct Slot<T> {
}
impl<T> Slot<T> {
+ const UNINIT: Self = Self {
+ value: UnsafeCell::new(MaybeUninit::uninit()),
+ state: AtomicUsize::new(0),
+ };
+
/// Waits until a value is written into the slot.
fn wait_write(&self) {
let backoff = Backoff::new();
@@ -58,13 +63,10 @@ struct Block<T> {
impl<T> Block<T> {
/// Creates an empty block that starts at `start_index`.
fn new() -> Block<T> {
- // SAFETY: This is safe because:
- // [1] `Block::next` (AtomicPtr) may be safely zero initialized.
- // [2] `Block::slots` (Array) may be safely zero initialized because of [3, 4].
- // [3] `Slot::value` (UnsafeCell) may be safely zero initialized because it
- // holds a MaybeUninit.
- // [4] `Slot::state` (AtomicUsize) may be safely zero initialized.
- unsafe { MaybeUninit::zeroed().assume_init() }
+ Self {
+ next: AtomicPtr::new(ptr::null_mut()),
+ slots: [Slot::UNINIT; BLOCK_CAP],
+ }
}
/// Waits until the next pointer is set.
@@ -437,9 +439,9 @@ impl<T> SegQueue<T> {
impl<T> Drop for SegQueue<T> {
fn drop(&mut self) {
- let mut head = self.head.index.load(Ordering::Relaxed);
- let mut tail = self.tail.index.load(Ordering::Relaxed);
- let mut block = self.head.block.load(Ordering::Relaxed);
+ let mut head = *self.head.index.get_mut();
+ let mut tail = *self.tail.index.get_mut();
+ let mut block = *self.head.block.get_mut();
// Erase the lower bits.
head &= !((1 << SHIFT) - 1);
@@ -457,7 +459,7 @@ impl<T> Drop for SegQueue<T> {
p.as_mut_ptr().drop_in_place();
} else {
// Deallocate the block and move to the next one.
- let next = (*block).next.load(Ordering::Relaxed);
+ let next = *(*block).next.get_mut();
drop(Box::from_raw(block));
block = next;
}
diff --git a/tests/array_queue.rs b/tests/array_queue.rs
index a23e082..b9d4e5f 100644
--- a/tests/array_queue.rs
+++ b/tests/array_queue.rs
@@ -57,24 +57,30 @@ fn len_empty_full() {
assert!(!q.is_full());
}
-#[cfg_attr(miri, ignore)] // Miri is too slow
#[test]
fn len() {
+ #[cfg(miri)]
+ const COUNT: usize = 30;
+ #[cfg(not(miri))]
const COUNT: usize = 25_000;
+ #[cfg(miri)]
+ const CAP: usize = 40;
+ #[cfg(not(miri))]
const CAP: usize = 1000;
+ const ITERS: usize = CAP / 20;
let q = ArrayQueue::new(CAP);
assert_eq!(q.len(), 0);
for _ in 0..CAP / 10 {
- for i in 0..50 {
+ for i in 0..ITERS {
q.push(i).unwrap();
assert_eq!(q.len(), i + 1);
}
- for i in 0..50 {
+ for i in 0..ITERS {
q.pop().unwrap();
- assert_eq!(q.len(), 50 - i - 1);
+ assert_eq!(q.len(), ITERS - i - 1);
}
}
assert_eq!(q.len(), 0);
@@ -115,9 +121,11 @@ fn len() {
assert_eq!(q.len(), 0);
}
-#[cfg_attr(miri, ignore)] // Miri is too slow
#[test]
fn spsc() {
+ #[cfg(miri)]
+ const COUNT: usize = 50;
+ #[cfg(not(miri))]
const COUNT: usize = 100_000;
let q = ArrayQueue::new(3);
@@ -144,9 +152,52 @@ fn spsc() {
.unwrap();
}
-#[cfg_attr(miri, ignore)] // Miri is too slow
+#[test]
+fn spsc_ring_buffer() {
+ #[cfg(miri)]
+ const COUNT: usize = 50;
+ #[cfg(not(miri))]
+ const COUNT: usize = 100_000;
+
+ let t = AtomicUsize::new(1);
+ let q = ArrayQueue::<usize>::new(3);
+ let v = (0..COUNT).map(|_| AtomicUsize::new(0)).collect::<Vec<_>>();
+
+ scope(|scope| {
+ scope.spawn(|_| loop {
+ match t.load(Ordering::SeqCst) {
+ 0 if q.is_empty() => break,
+
+ _ => {
+ while let Some(n) = q.pop() {
+ v[n].fetch_add(1, Ordering::SeqCst);
+ }
+ }
+ }
+ });
+
+ scope.spawn(|_| {
+ for i in 0..COUNT {
+ if let Some(n) = q.force_push(i) {
+ v[n].fetch_add(1, Ordering::SeqCst);
+ }
+ }
+
+ t.fetch_sub(1, Ordering::SeqCst);
+ });
+ })
+ .unwrap();
+
+ for c in v {
+ assert_eq!(c.load(Ordering::SeqCst), 1);
+ }
+}
+
#[test]
fn mpmc() {
+ #[cfg(miri)]
+ const COUNT: usize = 50;
+ #[cfg(not(miri))]
const COUNT: usize = 25_000;
const THREADS: usize = 4;
@@ -181,10 +232,57 @@ fn mpmc() {
}
}
-#[cfg_attr(miri, ignore)] // Miri is too slow
+#[test]
+fn mpmc_ring_buffer() {
+ #[cfg(miri)]
+ const COUNT: usize = 50;
+ #[cfg(not(miri))]
+ const COUNT: usize = 25_000;
+ const THREADS: usize = 4;
+
+ let t = AtomicUsize::new(THREADS);
+ let q = ArrayQueue::<usize>::new(3);
+ let v = (0..COUNT).map(|_| AtomicUsize::new(0)).collect::<Vec<_>>();
+
+ scope(|scope| {
+ for _ in 0..THREADS {
+ scope.spawn(|_| loop {
+ match t.load(Ordering::SeqCst) {
+ 0 if q.is_empty() => break,
+
+ _ => {
+ while let Some(n) = q.pop() {
+ v[n].fetch_add(1, Ordering::SeqCst);
+ }
+ }
+ }
+ });
+ }
+
+ for _ in 0..THREADS {
+ scope.spawn(|_| {
+ for i in 0..COUNT {
+ if let Some(n) = q.force_push(i) {
+ v[n].fetch_add(1, Ordering::SeqCst);
+ }
+ }
+
+ t.fetch_sub(1, Ordering::SeqCst);
+ });
+ }
+ })
+ .unwrap();
+
+ for c in v {
+ assert_eq!(c.load(Ordering::SeqCst), THREADS);
+ }
+}
+
#[test]
fn drops() {
- const RUNS: usize = 100;
+ let runs: usize = if cfg!(miri) { 3 } else { 100 };
+ let steps: usize = if cfg!(miri) { 50 } else { 10_000 };
+ let additional: usize = if cfg!(miri) { 10 } else { 50 };
static DROPS: AtomicUsize = AtomicUsize::new(0);
@@ -199,9 +297,9 @@ fn drops() {
let mut rng = thread_rng();
- for _ in 0..RUNS {
- let steps = rng.gen_range(0..10_000);
- let additional = rng.gen_range(0..50);
+ for _ in 0..runs {
+ let steps = rng.gen_range(0..steps);
+ let additional = rng.gen_range(0..additional);
DROPS.store(0, Ordering::SeqCst);
let q = ArrayQueue::new(50);
@@ -236,7 +334,7 @@ fn drops() {
#[test]
fn linearizable() {
#[cfg(miri)]
- const COUNT: usize = 500;
+ const COUNT: usize = 100;
#[cfg(not(miri))]
const COUNT: usize = 25_000;
const THREADS: usize = 4;
@@ -244,13 +342,21 @@ fn linearizable() {
let q = ArrayQueue::new(THREADS);
scope(|scope| {
- for _ in 0..THREADS {
+ for _ in 0..THREADS / 2 {
scope.spawn(|_| {
for _ in 0..COUNT {
while q.push(0).is_err() {}
q.pop().unwrap();
}
});
+
+ scope.spawn(|_| {
+ for _ in 0..COUNT {
+ if q.force_push(0).is_none() {
+ q.pop().unwrap();
+ }
+ }
+ });
}
})
.unwrap();
diff --git a/tests/seg_queue.rs b/tests/seg_queue.rs
index f1304ed..bf5fb99 100644
--- a/tests/seg_queue.rs
+++ b/tests/seg_queue.rs
@@ -52,9 +52,11 @@ fn len() {
assert_eq!(q.len(), 0);
}
-#[cfg_attr(miri, ignore)] // Miri is too slow
#[test]
fn spsc() {
+ #[cfg(miri)]
+ const COUNT: usize = 100;
+ #[cfg(not(miri))]
const COUNT: usize = 100_000;
let q = SegQueue::new();
@@ -80,9 +82,11 @@ fn spsc() {
.unwrap();
}
-#[cfg_attr(miri, ignore)] // Miri is too slow
#[test]
fn mpmc() {
+ #[cfg(miri)]
+ const COUNT: usize = 50;
+ #[cfg(not(miri))]
const COUNT: usize = 25_000;
const THREADS: usize = 4;
@@ -117,10 +121,11 @@ fn mpmc() {
}
}
-#[cfg_attr(miri, ignore)] // Miri is too slow
#[test]
fn drops() {
- const RUNS: usize = 100;
+ let runs: usize = if cfg!(miri) { 5 } else { 100 };
+ let steps: usize = if cfg!(miri) { 50 } else { 10_000 };
+ let additional: usize = if cfg!(miri) { 100 } else { 1_000 };
static DROPS: AtomicUsize = AtomicUsize::new(0);
@@ -135,9 +140,9 @@ fn drops() {
let mut rng = thread_rng();
- for _ in 0..RUNS {
- let steps = rng.gen_range(0..10_000);
- let additional = rng.gen_range(0..1000);
+ for _ in 0..runs {
+ let steps = rng.gen_range(0..steps);
+ let additional = rng.gen_range(0..additional);
DROPS.store(0, Ordering::SeqCst);
let q = SegQueue::new();