Snap for 10453938 from bc312a33af99a4ca364a29a732e04f466498e29b to mainline-odp-release

Change-Id: Ibfd8a6c2c5a2142550bdf4a9132b4a2dab0e229d
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 @@
     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 @@
     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 @@
         "//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 @@
 # - 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 @@
   }
   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://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 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 @@
         }
     };
 
-    // 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 @@
     "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 @@
     "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 @@
     "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 @@
 #[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 @@
 ///
 /// 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 @@
         }
     }
 
-    /// 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 @@
             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 @@
 
             // 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 @@
                 }
             } 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 @@
         }
     }
 
+    /// 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> 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 @@
 }
 
 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 @@
 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> 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 @@
                     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 @@
     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 @@
     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 @@
     .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 @@
     }
 }
 
-#[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 @@
 
     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 @@
 #[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 @@
     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 @@
     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 @@
     .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 @@
     }
 }
 
-#[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 @@
 
     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();