Bug 1785002 - Update crossbeam-deque to 0.8.2. r=emilio,supply-chain-reviewers

Differential Revision: https://phabricator.services.mozilla.com/D154720
This commit is contained in:
Mike Hommey 2022-08-16 20:30:30 +00:00
Родитель e6ec815843
Коммит b6ab763ae0
11 изменённых файлов: 157 добавлений и 55 удалений

8
Cargo.lock сгенерированный
Просмотреть файл

@ -990,9 +990,9 @@ dependencies = [
[[package]]
name = "crossbeam-deque"
version = "0.8.1"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e"
checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc"
dependencies = [
"cfg-if 1.0.0",
"crossbeam-epoch 0.9.8",
@ -4347,7 +4347,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d"
dependencies = [
"autocfg",
"crossbeam-deque 0.8.1",
"crossbeam-deque 0.8.2",
"either",
"rayon-core",
]
@ -4359,7 +4359,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f"
dependencies = [
"crossbeam-channel",
"crossbeam-deque 0.8.1",
"crossbeam-deque 0.8.2",
"crossbeam-utils 0.8.8",
"num_cpus",
]

Просмотреть файл

@ -132,6 +132,11 @@ who = "Mike Hommey <mh+mozilla@glandium.org>"
criteria = "safe-to-deploy"
delta = "0.5.4 -> 0.5.6"
[[audits.crossbeam-deque]]
who = "Mike Hommey <mh+mozilla@glandium.org>"
criteria = "safe-to-deploy"
delta = "0.8.1 -> 0.8.2"
[[audits.cstr]]
who = "Emilio Cobos Álvarez <emilio@crisal.io>"
criteria = "safe-to-deploy"

Просмотреть файл

@ -1 +1 @@
{"files":{"CHANGELOG.md":"7d5f333652da0da5f068ff91ecf259599f9ff4a4448bd987dd451699b66f0f59","Cargo.toml":"a9a138b4e005ddea76f588ca7004629ebd8f1a64cd1d55474fe36cae4c57a890","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"5734ed989dfca1f625b40281ee9f4530f91b2411ec01cb748223e7eb87e201ab","README.md":"6b0a911f542186ef96eb56537cade0ecf1a5731d5d494b7094ff87f0fdeb7710","src/deque.rs":"64a2153dc566847fd9fa0e6b2b7adb3933af9984fbe3429b6f1200b058bb9850","src/lib.rs":"9f0581481691bc698176f369410726adf597d470b9d14e226a65f490d6aff8c6","tests/fifo.rs":"1d83f9ffeeba2cd6bd32f1ab136d843b8c73075d5045619be12dc3c27d8ab3ba","tests/injector.rs":"6812c97615e3f685b5612c390861f2e570ff469f3b9871ba97ddbed5c1f5266b","tests/lifo.rs":"b2ddc8154492322e734b23f35ce54040f9ec84ef878009de3a64d44d35c365a6","tests/steal.rs":"cdf588cc13eeb275ef1231eb18e3245faca7a2d054fa6527bfdba2a34bc8f7bf"},"package":"6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e"}
{"files":{"CHANGELOG.md":"ad5f2c10299e57aaed2d1b8f8a109faa2dfb16c52ce81f60ec5adb0ea9308d7f","Cargo.toml":"4802e7c0d5ab1dc35c162671483a6ee9bff5a3f1d6dd620a01863ac25068019e","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"5734ed989dfca1f625b40281ee9f4530f91b2411ec01cb748223e7eb87e201ab","README.md":"3c62aa0ee37cf714b5b3c304545d5caea4cc0a71020fccb1f146611d64202bb2","src/deque.rs":"cfb3c5b3bcea1f27ca2633d8b8576ff2080e1e9fc083236f2db7916bb77786ed","src/lib.rs":"ec0257a388627d691d652fd04d261c5c0590e1e31a35c8bf5912afac51fd5734","tests/fifo.rs":"3d98e0d4ca7cfddf10708b71642cf1ff05543d067ad837e48401d63cc31c0a18","tests/injector.rs":"fb054ef9fcac5f12e08b7b3451f370b96ab7589d32ef5c02e25958a473c45519","tests/lifo.rs":"57abdb3fc5920a422f785ba308b658bdc5400947532eeffb799f2395a2061549","tests/steal.rs":"cdf588cc13eeb275ef1231eb18e3245faca7a2d054fa6527bfdba2a34bc8f7bf"},"package":"715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc"}

18
third_party/rust/crossbeam-deque/CHANGELOG.md поставляемый
Просмотреть файл

@ -1,3 +1,7 @@
# Version 0.8.2
- Bump the minimum supported Rust version to 1.38. (#877)
# Version 0.8.1
- Fix deque steal race condition. (#726)
@ -5,26 +9,40 @@
# Version 0.8.0
**Note:** This release has been yanked. See [GHSA-pqqp-xmhj-wgcw](https://github.com/crossbeam-rs/crossbeam/security/advisories/GHSA-pqqp-xmhj-wgcw) for details.
- Bump the minimum supported Rust version to 1.36.
- Add `Worker::len()` and `Injector::len()` methods.
- Add `std` (enabled by default) feature for forward compatibility.
# Version 0.7.4
- Fix deque steal race condition.
# Version 0.7.3
**Note:** This release has been yanked. See [GHSA-pqqp-xmhj-wgcw](https://github.com/crossbeam-rs/crossbeam/security/advisories/GHSA-pqqp-xmhj-wgcw) for details.
- Stop stealing from the same deque. (#448)
- Fix unsoundness issues by adopting `MaybeUninit`. (#458)
# Version 0.7.2
**Note:** This release has been yanked. See [GHSA-pqqp-xmhj-wgcw](https://github.com/crossbeam-rs/crossbeam/security/advisories/GHSA-pqqp-xmhj-wgcw) for details.
- Bump `crossbeam-epoch` to `0.8`.
- Bump `crossbeam-utils` to `0.7`.
# Version 0.7.1
**Note:** This release has been yanked. See [GHSA-pqqp-xmhj-wgcw](https://github.com/crossbeam-rs/crossbeam/security/advisories/GHSA-pqqp-xmhj-wgcw) for details.
- Bump the minimum required version of `crossbeam-utils`.
# Version 0.7.0
**Note:** This release has been yanked. See [GHSA-pqqp-xmhj-wgcw](https://github.com/crossbeam-rs/crossbeam/security/advisories/GHSA-pqqp-xmhj-wgcw) for details.
- Make `Worker::pop()` faster in the FIFO case.
- Replace `fifo()` nad `lifo()` with `Worker::new_fifo()` and `Worker::new_lifo()`.
- Add more batched steal methods.

26
third_party/rust/crossbeam-deque/Cargo.toml поставляемый
Просмотреть файл

@ -11,16 +11,26 @@
[package]
edition = "2018"
rust-version = "1.38"
name = "crossbeam-deque"
version = "0.8.1"
authors = ["The Crossbeam Project Developers"]
version = "0.8.2"
description = "Concurrent work-stealing deque"
homepage = "https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-deque"
documentation = "https://docs.rs/crossbeam-deque"
keywords = ["chase-lev", "lock-free", "scheduler", "scheduling"]
categories = ["algorithms", "concurrency", "data-structures"]
readme = "README.md"
keywords = [
"chase-lev",
"lock-free",
"scheduler",
"scheduling",
]
categories = [
"algorithms",
"concurrency",
"data-structures",
]
license = "MIT OR Apache-2.0"
repository = "https://github.com/crossbeam-rs/crossbeam"
[dependencies.cfg-if]
version = "1"
@ -33,9 +43,13 @@ default-features = false
version = "0.8"
optional = true
default-features = false
[dev-dependencies.rand]
version = "0.8"
[features]
default = ["std"]
std = ["crossbeam-epoch/std", "crossbeam-utils/std"]
std = [
"crossbeam-epoch/std",
"crossbeam-utils/std",
]

4
third_party/rust/crossbeam-deque/README.md поставляемый
Просмотреть файл

@ -8,7 +8,7 @@ https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-deque#license)
https://crates.io/crates/crossbeam-deque)
[![Documentation](https://docs.rs/crossbeam-deque/badge.svg)](
https://docs.rs/crossbeam-deque)
[![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)
@ -28,7 +28,7 @@ crossbeam-deque = "0.8"
Crossbeam Deque 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

76
third_party/rust/crossbeam-deque/src/deque.rs поставляемый
Просмотреть файл

@ -3,7 +3,7 @@ use std::cmp;
use std::fmt;
use std::iter::FromIterator;
use std::marker::PhantomData;
use std::mem::{self, MaybeUninit};
use std::mem::{self, ManuallyDrop, MaybeUninit};
use std::ptr;
use std::sync::atomic::{self, AtomicIsize, AtomicPtr, AtomicUsize, Ordering};
use std::sync::Arc;
@ -38,9 +38,8 @@ impl<T> Buffer<T> {
fn alloc(cap: usize) -> Buffer<T> {
debug_assert_eq!(cap, cap.next_power_of_two());
let mut v = Vec::with_capacity(cap);
let mut v = ManuallyDrop::new(Vec::with_capacity(cap));
let ptr = v.as_mut_ptr();
mem::forget(v);
Buffer { ptr, cap }
}
@ -53,6 +52,8 @@ impl<T> Buffer<T> {
/// Returns a pointer to the task at the specified `index`.
unsafe fn at(&self, index: isize) -> *mut T {
// `self.cap` is always a power of two.
// We do all the loads at `MaybeUninit` because we might realize, after loading, that we
// don't actually have the right to access this memory.
self.ptr.offset(index & (self.cap - 1) as isize)
}
@ -62,8 +63,8 @@ impl<T> Buffer<T> {
/// technically speaking a data race and therefore UB. We should use an atomic store here, but
/// that would be more expensive and difficult to implement generically for all types `T`.
/// Hence, as a hack, we use a volatile write instead.
unsafe fn write(&self, index: isize, task: T) {
ptr::write_volatile(self.at(index), task)
unsafe fn write(&self, index: isize, task: MaybeUninit<T>) {
ptr::write_volatile(self.at(index).cast::<MaybeUninit<T>>(), task)
}
/// Reads a task from the specified `index`.
@ -71,9 +72,9 @@ impl<T> Buffer<T> {
/// This method might be concurrently called with another `write` at the same index, which is
/// technically speaking a data race and therefore UB. We should use an atomic load here, but
/// that would be more expensive and difficult to implement generically for all types `T`.
/// Hence, as a hack, we use a volatile write instead.
unsafe fn read(&self, index: isize) -> T {
ptr::read_volatile(self.at(index))
/// Hence, as a hack, we use a volatile load instead.
unsafe fn read(&self, index: isize) -> MaybeUninit<T> {
ptr::read_volatile(self.at(index).cast::<MaybeUninit<T>>())
}
}
@ -115,8 +116,8 @@ struct Inner<T> {
impl<T> Drop for Inner<T> {
fn drop(&mut self) {
// Load the back index, front index, and buffer.
let b = self.back.load(Ordering::Relaxed);
let f = self.front.load(Ordering::Relaxed);
let b = *self.back.get_mut();
let f = *self.front.get_mut();
unsafe {
let buffer = self.buffer.load(Ordering::Relaxed, epoch::unprotected());
@ -406,7 +407,7 @@ impl<T> Worker<T> {
// Write `task` into the slot.
unsafe {
buffer.write(b, task);
buffer.write(b, MaybeUninit::new(task));
}
atomic::fence(Ordering::Release);
@ -461,7 +462,7 @@ impl<T> Worker<T> {
unsafe {
// Read the popped task.
let buffer = self.buffer.get();
let task = buffer.read(f);
let task = buffer.read(f).assume_init();
// Shrink the buffer if `len - 1` is less than one fourth of the capacity.
if buffer.cap > MIN_CAP && len <= buffer.cap as isize / 4 {
@ -509,8 +510,8 @@ impl<T> Worker<T> {
)
.is_err()
{
// Failed. We didn't pop anything.
mem::forget(task.take());
// Failed. We didn't pop anything. Reset to `None`.
task.take();
}
// Restore the back index to the original task.
@ -524,7 +525,7 @@ impl<T> Worker<T> {
}
}
task
task.map(|t| unsafe { t.assume_init() })
}
}
}
@ -661,12 +662,11 @@ impl<T> Stealer<T> {
.is_err()
{
// We didn't steal this task, forget it.
mem::forget(task);
return Steal::Retry;
}
// Return the stolen task.
Steal::Success(task)
Steal::Success(unsafe { task.assume_init() })
}
/// Steals a batch of tasks and pushes them into another worker.
@ -821,7 +821,6 @@ impl<T> Stealer<T> {
.is_err()
{
// We didn't steal this task, forget it and break from the loop.
mem::forget(task);
batch_size = i;
break;
}
@ -975,7 +974,6 @@ impl<T> Stealer<T> {
.is_err()
{
// We didn't steal this task, forget it.
mem::forget(task);
return Steal::Retry;
}
@ -992,7 +990,6 @@ impl<T> Stealer<T> {
.is_err()
{
// We didn't steal this task, forget it.
mem::forget(task);
return Steal::Retry;
}
@ -1037,7 +1034,6 @@ impl<T> Stealer<T> {
.is_err()
{
// We didn't steal this task, forget it and break from the loop.
mem::forget(tmp);
batch_size = i;
break;
}
@ -1077,7 +1073,7 @@ impl<T> Stealer<T> {
dest.inner.back.store(dest_b, Ordering::Release);
// Return with success.
Steal::Success(task)
Steal::Success(unsafe { task.assume_init() })
}
}
@ -1123,6 +1119,11 @@ struct Slot<T> {
}
impl<T> Slot<T> {
const UNINIT: Self = Self {
task: UnsafeCell::new(MaybeUninit::uninit()),
state: AtomicUsize::new(0),
};
/// Waits until a task is written into the slot.
fn wait_write(&self) {
let backoff = Backoff::new();
@ -1146,13 +1147,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::task` (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.
@ -1535,7 +1533,7 @@ impl<T> Injector<T> {
// Read the task.
let slot = (*block).slots.get_unchecked(offset + i);
slot.wait_write();
let task = slot.task.get().read().assume_init();
let task = slot.task.get().read();
// Write it into the destination queue.
dest_buffer.write(dest_b.wrapping_add(i as isize), task);
@ -1547,7 +1545,7 @@ impl<T> Injector<T> {
// Read the task.
let slot = (*block).slots.get_unchecked(offset + i);
slot.wait_write();
let task = slot.task.get().read().assume_init();
let task = slot.task.get().read();
// Write it into the destination queue.
dest_buffer.write(dest_b.wrapping_add((batch_size - 1 - i) as isize), task);
@ -1689,7 +1687,7 @@ impl<T> Injector<T> {
// Read the task.
let slot = (*block).slots.get_unchecked(offset);
slot.wait_write();
let task = slot.task.get().read().assume_init();
let task = slot.task.get().read();
match dest.flavor {
Flavor::Fifo => {
@ -1698,7 +1696,7 @@ impl<T> Injector<T> {
// Read the task.
let slot = (*block).slots.get_unchecked(offset + i + 1);
slot.wait_write();
let task = slot.task.get().read().assume_init();
let task = slot.task.get().read();
// Write it into the destination queue.
dest_buffer.write(dest_b.wrapping_add(i as isize), task);
@ -1711,7 +1709,7 @@ impl<T> Injector<T> {
// Read the task.
let slot = (*block).slots.get_unchecked(offset + i + 1);
slot.wait_write();
let task = slot.task.get().read().assume_init();
let task = slot.task.get().read();
// Write it into the destination queue.
dest_buffer.write(dest_b.wrapping_add((batch_size - 1 - i) as isize), task);
@ -1744,7 +1742,7 @@ impl<T> Injector<T> {
}
}
Steal::Success(task)
Steal::Success(task.assume_init())
}
}
@ -1820,9 +1818,9 @@ impl<T> Injector<T> {
impl<T> Drop for Injector<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);
@ -1840,7 +1838,7 @@ impl<T> Drop for Injector<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;
}

1
third_party/rust/crossbeam-deque/src/lib.rs поставляемый
Просмотреть файл

@ -95,6 +95,7 @@
rust_2018_idioms,
unreachable_pub
)]
#![allow(clippy::question_mark)] // https://github.com/rust-lang/rust-clippy/issues/8281
#![cfg_attr(not(feature = "std"), no_std)]
use cfg_if::cfg_if;

Просмотреть файл

@ -71,6 +71,9 @@ fn is_empty() {
#[test]
fn spsc() {
#[cfg(miri)]
const STEPS: usize = 500;
#[cfg(not(miri))]
const STEPS: usize = 50_000;
let w = Worker::new_fifo();
@ -100,6 +103,9 @@ fn spsc() {
#[test]
fn stampede() {
const THREADS: usize = 8;
#[cfg(miri)]
const COUNT: usize = 500;
#[cfg(not(miri))]
const COUNT: usize = 50_000;
let w = Worker::new_fifo();
@ -141,6 +147,9 @@ fn stampede() {
#[test]
fn stress() {
const THREADS: usize = 8;
#[cfg(miri)]
const COUNT: usize = 500;
#[cfg(not(miri))]
const COUNT: usize = 50_000;
let w = Worker::new_fifo();
@ -197,6 +206,7 @@ fn stress() {
.unwrap();
}
#[cfg_attr(miri, ignore)] // Miri is too slow
#[test]
fn no_starvation() {
const THREADS: usize = 8;
@ -258,8 +268,17 @@ fn no_starvation() {
#[test]
fn destructors() {
#[cfg(miri)]
const THREADS: usize = 2;
#[cfg(not(miri))]
const THREADS: usize = 8;
#[cfg(miri)]
const COUNT: usize = 500;
#[cfg(not(miri))]
const COUNT: usize = 50_000;
#[cfg(miri)]
const STEPS: usize = 100;
#[cfg(not(miri))]
const STEPS: usize = 1000;
struct Elem(usize, Arc<Mutex<Vec<usize>>>);
@ -330,7 +349,7 @@ fn destructors() {
{
let mut v = dropped.lock().unwrap();
assert_eq!(v.len(), rem);
v.sort();
v.sort_unstable();
for pair in v.windows(2) {
assert_eq!(pair[0] + 1, pair[1]);
}

Просмотреть файл

@ -46,6 +46,9 @@ fn is_empty() {
#[test]
fn spsc() {
#[cfg(miri)]
const COUNT: usize = 500;
#[cfg(not(miri))]
const COUNT: usize = 100_000;
let q = Injector::new();
@ -58,6 +61,8 @@ fn spsc() {
assert_eq!(i, v);
break;
}
#[cfg(miri)]
std::hint::spin_loop();
}
}
@ -73,6 +78,9 @@ fn spsc() {
#[test]
fn mpmc() {
#[cfg(miri)]
const COUNT: usize = 500;
#[cfg(not(miri))]
const COUNT: usize = 25_000;
const THREADS: usize = 4;
@ -96,6 +104,8 @@ fn mpmc() {
v[n].fetch_add(1, SeqCst);
break;
}
#[cfg(miri)]
std::hint::spin_loop();
}
}
});
@ -111,6 +121,9 @@ fn mpmc() {
#[test]
fn stampede() {
const THREADS: usize = 8;
#[cfg(miri)]
const COUNT: usize = 500;
#[cfg(not(miri))]
const COUNT: usize = 50_000;
let q = Injector::new();
@ -152,6 +165,9 @@ fn stampede() {
#[test]
fn stress() {
const THREADS: usize = 8;
#[cfg(miri)]
const COUNT: usize = 500;
#[cfg(not(miri))]
const COUNT: usize = 50_000;
let q = Injector::new();
@ -208,6 +224,7 @@ fn stress() {
.unwrap();
}
#[cfg_attr(miri, ignore)] // Miri is too slow
#[test]
fn no_starvation() {
const THREADS: usize = 8;
@ -269,8 +286,17 @@ fn no_starvation() {
#[test]
fn destructors() {
#[cfg(miri)]
const THREADS: usize = 2;
#[cfg(not(miri))]
const THREADS: usize = 8;
#[cfg(miri)]
const COUNT: usize = 500;
#[cfg(not(miri))]
const COUNT: usize = 50_000;
#[cfg(miri)]
const STEPS: usize = 100;
#[cfg(not(miri))]
const STEPS: usize = 1000;
struct Elem(usize, Arc<Mutex<Vec<usize>>>);
@ -341,7 +367,7 @@ fn destructors() {
{
let mut v = dropped.lock().unwrap();
assert_eq!(v.len(), rem);
v.sort();
v.sort_unstable();
for pair in v.windows(2) {
assert_eq!(pair[0] + 1, pair[1]);
}

Просмотреть файл

@ -71,6 +71,9 @@ fn is_empty() {
#[test]
fn spsc() {
#[cfg(miri)]
const STEPS: usize = 500;
#[cfg(not(miri))]
const STEPS: usize = 50_000;
let w = Worker::new_lifo();
@ -84,6 +87,8 @@ fn spsc() {
assert_eq!(i, v);
break;
}
#[cfg(miri)]
std::hint::spin_loop();
}
}
@ -100,6 +105,9 @@ fn spsc() {
#[test]
fn stampede() {
const THREADS: usize = 8;
#[cfg(miri)]
const COUNT: usize = 500;
#[cfg(not(miri))]
const COUNT: usize = 50_000;
let w = Worker::new_lifo();
@ -141,6 +149,9 @@ fn stampede() {
#[test]
fn stress() {
const THREADS: usize = 8;
#[cfg(miri)]
const COUNT: usize = 500;
#[cfg(not(miri))]
const COUNT: usize = 50_000;
let w = Worker::new_lifo();
@ -197,6 +208,7 @@ fn stress() {
.unwrap();
}
#[cfg_attr(miri, ignore)] // Miri is too slow
#[test]
fn no_starvation() {
const THREADS: usize = 8;
@ -258,8 +270,17 @@ fn no_starvation() {
#[test]
fn destructors() {
#[cfg(miri)]
const THREADS: usize = 2;
#[cfg(not(miri))]
const THREADS: usize = 8;
#[cfg(miri)]
const COUNT: usize = 500;
#[cfg(not(miri))]
const COUNT: usize = 50_000;
#[cfg(miri)]
const STEPS: usize = 100;
#[cfg(not(miri))]
const STEPS: usize = 1000;
struct Elem(usize, Arc<Mutex<Vec<usize>>>);
@ -330,7 +351,7 @@ fn destructors() {
{
let mut v = dropped.lock().unwrap();
assert_eq!(v.len(), rem);
v.sort();
v.sort_unstable();
for pair in v.windows(2) {
assert_eq!(pair[0] + 1, pair[1]);
}