# HG changeset patch # User Mike Hommey # Date 1648102107 0 # Node ID 5075188978be1edb7403ada9fef6746db1d16da8 # Parent 1aa0ad6cf4a939651c75e0249785c6d57331db36 Bug 1757571 - Upgrade crossbeam-channel to 0.5.4. r=emilio Differential Revision: https://phabricator.services.mozilla.com/D141563 diff --git a/Cargo.lock b/Cargo.lock --- a/Cargo.lock +++ b/Cargo.lock @@ -968,19 +968,19 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "738c290dfaea84fc1ca15ad9c168d083b05a714e1efddd8edaab678dc28d2836" dependencies = [ "cfg-if 1.0.0", ] [[package]] name = "crossbeam-channel" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e54ea8bc3fb1ee042f5aace6e3c6e025d3874866da222930f70ce62aceba0bfa" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53" dependencies = [ "cfg-if 1.0.0", "crossbeam-utils 0.8.6", ] [[package]] name = "crossbeam-deque" version = "0.7.4" diff --git a/third_party/rust/crossbeam-channel/.cargo-checksum.json b/third_party/rust/crossbeam-channel/.cargo-checksum.json --- a/third_party/rust/crossbeam-channel/.cargo-checksum.json +++ b/third_party/rust/crossbeam-channel/.cargo-checksum.json @@ -1,1 +1,1 @@ -{"files":{"CHANGELOG.md":"e70d1a5fa6697a8b24e193e3934975317df12279c167b90fcb9616291792197c","Cargo.lock":"0f4e59f28bdd52c4781d102fc7d1f16d1ea417aaec0a4846432444a4019b2537","Cargo.toml":"c8334f658b699a1a0e25d997d752a9493a627f9ddcb7aab739c7319ea583882f","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"5734ed989dfca1f625b40281ee9f4530f91b2411ec01cb748223e7eb87e201ab","LICENSE-THIRD-PARTY":"b16db96b93b1d7cf7bea533f572091ec6bca3234fbe0a83038be772ff391a44c","README.md":"415a71d4978cfd338a6ae1f1b41284652eccd277a815542c304647dc437a8274","benches/crossbeam.rs":"96cb1abd23cac3ef8a7174a802e94609926b555bb02c9658c78723d433f1dd92","examples/fibonacci.rs":"4e88fa40048cdc31e9c7bb60347d46f92543d7ddf39cab3b52bfe44affdb6a02","examples/matching.rs":"63c250e164607a7a9f643d46f107bb5da846d49e89cf9069909562d20e530f71","examples/stopwatch.rs":"d02121258f08d56f1eb7997e19bcb9bacb6836cfa0abbba90a9e59d8a50ae5cf","src/channel.rs":"a9baaad2f414c38cd324a60ac9375ca58462ce6662217683648e9b66cec43a8c","src/context.rs":"ff4d39639ddf16aaab582d4a5f3d10ef2c71afe1abbf4e60f3d9d2ddbd72c230","src/counter.rs":"c49a9f44587888850edeb62f7c8ecd1acecb39c836834254ff3ac934c478440a","src/err.rs":"fdbde7279a1e74973e5c7d3e835a97836229a357fe465c0ba1a37f2a012d1bef","src/flavors/array.rs":"853c2ad068f912cfb49877bcd41e241f34b25026b709bf0629523f19952e3adc","src/flavors/at.rs":"65bf870b3ddb14738256706b0276f2656ad1fe9cd8eb91737489868edd088e92","src/flavors/list.rs":"50dbe59616c39b5aa184470023ce0cfb1cb0dbd92e1577375d299446981527c0","src/flavors/mod.rs":"3d9d43bc38b0adb18c96c995c2bd3421d8e33ab6c30b20c3c467d21d48e485dc","src/flavors/never.rs":"0e7921922d00c711552fb063c63c78192fa6ddc0762fb81c1713b847495ec39a","src/flavors/tick.rs":"38a479b9f4a72a5ccb9c407a1e7b44d36b6ad0f4e214e39266b12b9564c803dc","src/flavors/zero.rs":"012a53f56b86df22ce49866da95e5f457fb99a18a098f0f64779c6d1cdd7092f","src/lib.rs":"3a65706d4124844ffc4c8cb1f8cc779631ec94f449f85cbb68364ad3619404f1","src/select.rs":"66eb10a6cbdf8dd0869f2a7cac9992fdaee36c9e2a01d708d39d7c794572935b","src/select_macro.rs":"96bc9acb9a22588a4e733b0ab0761ad2be9a6b3e03744e8fc9c6de9ae433b696","src/utils.rs":"746fe315d6cfc832e3dda35e5055c0fd5c99907f1303b2ea7eacc4e37c8527e1","src/waker.rs":"591ee70bf62ccad5aa2fac7b92d444183b02790a79c024f016c78de2396d08a3","tests/after.rs":"0154a8e152880db17a20514ecdd49dabc361d3629858d119b9746b5e932c780c","tests/array.rs":"e5f25e8991863a9a86d61a66be646d04feae527f35b1697fd215b97af4383736","tests/golang.rs":"dc85669c9c4e902b1bb263d00f5cb6f9ecb6d42b19fe53425b55ce97c887da49","tests/iter.rs":"25dc02135bbae9d47a30f9047661648e66bdc134e40ba78bc2fbacbb8b3819bc","tests/list.rs":"de865ef097f3bcb35c1c814554e6108fed43b3dbb1533c8bbcf8688cceb6b6ab","tests/mpsc.rs":"401aa3c6923815058881ddce98070df68ebab283913c89c007436bb8af7ca0ea","tests/never.rs":"ee40c4fc4dd5af4983fae8de6927f52b81174d222c162f745b26c4a6c7108e4f","tests/ready.rs":"d349702f123925a0781b48d677e6dcf64fc5d1fc788a7bf1e151a3d57e81871c","tests/same_channel.rs":"2bab761443671e841e1b2476bd8082d75533a2f6be7946f5dbcee67cdc82dccb","tests/select.rs":"d20259a45f387cbce80c2c876ae81ea3883f36ea01c5151c159d58c362f6ba07","tests/select_macro.rs":"d3af2dc98e0dd03dc4ffab464b8ccb2f8b7504e8bb830948a04c015b92f0b296","tests/thread_locals.rs":"a1ce59e2aff69161621c0cb215eb6ea238088c06a31a8507a74cf179fd5a4299","tests/tick.rs":"5f697bd14c48505d932e82065b5302ef668e1cc19cac18e8ac22e0c83c221c1d","tests/zero.rs":"afbd838001d4196daddf17133e60ccea31529cc48ee01e245ac0d6366d1e30b9"},"package":"e54ea8bc3fb1ee042f5aace6e3c6e025d3874866da222930f70ce62aceba0bfa"} \ No newline at end of file +{"files":{"CHANGELOG.md":"0f549e63930d1e576f117ee9249c84276eadbe6fb95818680c042c6c0af8a807","Cargo.lock":"834da9468c17c8e1b7fe457764257f4dfdaa24bc98cbdfedf3af4f3d4f5c1e6a","Cargo.toml":"1296a016c4c23d38a35b3d737ee8285fcaaf7d23b7bbb5a3484cefe56b7ca32a","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"5734ed989dfca1f625b40281ee9f4530f91b2411ec01cb748223e7eb87e201ab","LICENSE-THIRD-PARTY":"b16db96b93b1d7cf7bea533f572091ec6bca3234fbe0a83038be772ff391a44c","README.md":"415a71d4978cfd338a6ae1f1b41284652eccd277a815542c304647dc437a8274","benches/crossbeam.rs":"96cb1abd23cac3ef8a7174a802e94609926b555bb02c9658c78723d433f1dd92","examples/fibonacci.rs":"4e88fa40048cdc31e9c7bb60347d46f92543d7ddf39cab3b52bfe44affdb6a02","examples/matching.rs":"63c250e164607a7a9f643d46f107bb5da846d49e89cf9069909562d20e530f71","examples/stopwatch.rs":"d02121258f08d56f1eb7997e19bcb9bacb6836cfa0abbba90a9e59d8a50ae5cf","src/channel.rs":"3bbf69df6c3f0071a44bab0139a749447604f5ffa5e45acc2998803dee066522","src/context.rs":"ff4d39639ddf16aaab582d4a5f3d10ef2c71afe1abbf4e60f3d9d2ddbd72c230","src/counter.rs":"c49a9f44587888850edeb62f7c8ecd1acecb39c836834254ff3ac934c478440a","src/err.rs":"44cb2024ee6b0cd6fd24996430e53720769f64b4ac35016bc3e05cb9db48681d","src/flavors/array.rs":"0743fb71a8adc8d95143b1cdae996823dddb7ab7fb7139eb6e0cdf733ff231ee","src/flavors/at.rs":"1db64919593b7c14f838c16a22732515f1e716d2d5f6cc639f42631380e545cd","src/flavors/list.rs":"017b66a84ada393d11d1730297426338244b115944a4d631573447641a66bed6","src/flavors/mod.rs":"3d9d43bc38b0adb18c96c995c2bd3421d8e33ab6c30b20c3c467d21d48e485dc","src/flavors/never.rs":"747da857aa1a7601641f23f4930e6ad00ebaf50456d9be5c7aa270e2ecc24dcb","src/flavors/tick.rs":"69b2dfe0186bc8b9fd7a73e32da59d2656d8150da1e00fba92a412e0907568a3","src/flavors/zero.rs":"1edd8e5114daa5b82ec9f4a715c0389a9de02cce64de0f71b4225868dad99a99","src/lib.rs":"3a65706d4124844ffc4c8cb1f8cc779631ec94f449f85cbb68364ad3619404f1","src/select.rs":"63dbfde7098dac1424f1cc884f6b8364f3bf3e06527691dde628ff6c416a7f35","src/select_macro.rs":"582a033cc0a51917fd5197dfb66677e9d7982c013414e75ae78b4a740189a56d","src/utils.rs":"b4d38e39a7d7774729458b1b39253377a55657d377c483d30b32e42a0a0092e3","src/waker.rs":"2114bd84f35b2c654d1914127e0380e17a5c20d8ec1e20449af3d653cad27c64","tests/after.rs":"0154a8e152880db17a20514ecdd49dabc361d3629858d119b9746b5e932c780c","tests/array.rs":"e0f3814328c79727a85df3aee0409701849dabfeaaa2f70721e14396fbaba1cd","tests/golang.rs":"dc85669c9c4e902b1bb263d00f5cb6f9ecb6d42b19fe53425b55ce97c887da49","tests/iter.rs":"25dc02135bbae9d47a30f9047661648e66bdc134e40ba78bc2fbacbb8b3819bc","tests/list.rs":"de865ef097f3bcb35c1c814554e6108fed43b3dbb1533c8bbcf8688cceb6b6ab","tests/mpsc.rs":"401aa3c6923815058881ddce98070df68ebab283913c89c007436bb8af7ca0ea","tests/never.rs":"ee40c4fc4dd5af4983fae8de6927f52b81174d222c162f745b26c4a6c7108e4f","tests/ready.rs":"d349702f123925a0781b48d677e6dcf64fc5d1fc788a7bf1e151a3d57e81871c","tests/same_channel.rs":"2bab761443671e841e1b2476bd8082d75533a2f6be7946f5dbcee67cdc82dccb","tests/select.rs":"d20259a45f387cbce80c2c876ae81ea3883f36ea01c5151c159d58c362f6ba07","tests/select_macro.rs":"948eb21f72a9317c0de98a9bd21f6f8ff2b09b73b45c171c45b04c051a2fd0c4","tests/thread_locals.rs":"a1ce59e2aff69161621c0cb215eb6ea238088c06a31a8507a74cf179fd5a4299","tests/tick.rs":"5f697bd14c48505d932e82065b5302ef668e1cc19cac18e8ac22e0c83c221c1d","tests/zero.rs":"afbd838001d4196daddf17133e60ccea31529cc48ee01e245ac0d6366d1e30b9"},"package":"5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53"} \ No newline at end of file diff --git a/third_party/rust/crossbeam-channel/CHANGELOG.md b/third_party/rust/crossbeam-channel/CHANGELOG.md --- a/third_party/rust/crossbeam-channel/CHANGELOG.md +++ b/third_party/rust/crossbeam-channel/CHANGELOG.md @@ -1,11 +1,19 @@ +# Version 0.5.4 + +- Workaround a bug in upstream related to TLS access on AArch64 Linux. (#802) + +# Version 0.5.3 + +- Fix panic on very large timeout. (#798) + # Version 0.5.2 -- Fix stacked borrows violations. (#763, #764) +- Fix stacked borrows violations when `-Zmiri-tag-raw-pointers` is enabled. (#763, #764) # Version 0.5.1 - Fix memory leak in unbounded channel. (#669) # Version 0.5.0 - Bump the minimum supported Rust version to 1.36. @@ -17,16 +25,18 @@ # Version 0.4.4 - Fix bug in release (yanking 0.4.3) - Fix UB and breaking change introduced in 0.4.3 # Version 0.4.3 +**Note**: This release has been yanked. See [CVE-2020-15254](https://github.com/crossbeam-rs/crossbeam/security/advisories/GHSA-v5m7-53cv-f3hx) for details. + - Change license to "MIT OR Apache-2.0". # Version 0.4.2 - Fix bug in release (yanking 0.4.1) # Version 0.4.1 diff --git a/third_party/rust/crossbeam-channel/Cargo.lock b/third_party/rust/crossbeam-channel/Cargo.lock --- a/third_party/rust/crossbeam-channel/Cargo.lock +++ b/third_party/rust/crossbeam-channel/Cargo.lock @@ -5,40 +5,40 @@ version = 3 [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "crossbeam-channel" -version = "0.5.2" +version = "0.5.4" dependencies = [ "cfg-if", "crossbeam-utils", "num_cpus", "rand", "signal-hook", ] [[package]] name = "crossbeam-utils" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcae03edb34f947e64acdb1c33ec169824e20657e9ecb61cef6c8c74dcb8120" +checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" dependencies = [ "cfg-if", "lazy_static", ] [[package]] name = "getrandom" -version = "0.2.3" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77" dependencies = [ "cfg-if", "libc", "wasi", ] [[package]] name = "hermit-abi" @@ -52,19 +52,19 @@ dependencies = [ [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.112" +version = "0.2.120" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" +checksum = "ad5c14e80759d0939d013e6ca49930e59fc53dd8e5009132f76240c179380c09" [[package]] name = "num_cpus" version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" dependencies = [ "hermit-abi", @@ -74,24 +74,23 @@ dependencies = [ [[package]] name = "ppv-lite86" version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" [[package]] name = "rand" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", "rand_core", - "rand_hc", ] [[package]] name = "rand_chacha" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ @@ -104,25 +103,16 @@ name = "rand_core" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" dependencies = [ "getrandom", ] [[package]] -name = "rand_hc" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" -dependencies = [ - "rand_core", -] - -[[package]] name = "signal-hook" version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "647c97df271007dcea485bb74ffdb57f2e683f1306c854f468a0c244badabf2d" dependencies = [ "libc", "signal-hook-registry", ] diff --git a/third_party/rust/crossbeam-channel/Cargo.toml b/third_party/rust/crossbeam-channel/Cargo.toml --- a/third_party/rust/crossbeam-channel/Cargo.toml +++ b/third_party/rust/crossbeam-channel/Cargo.toml @@ -8,30 +8,42 @@ # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" rust-version = "1.36" name = "crossbeam-channel" -version = "0.5.2" +version = "0.5.4" description = "Multi-producer multi-consumer channels for message passing" homepage = "https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-channel" -keywords = ["channel", "mpmc", "select", "golang", "message"] -categories = ["algorithms", "concurrency", "data-structures"] +keywords = [ + "channel", + "mpmc", + "select", + "golang", + "message", +] +categories = [ + "algorithms", + "concurrency", + "data-structures", +] license = "MIT OR Apache-2.0" repository = "https://github.com/crossbeam-rs/crossbeam" + [dependencies.cfg-if] version = "1" [dependencies.crossbeam-utils] version = "0.8" optional = true default-features = false + [dev-dependencies.num_cpus] version = "1.13.0" [dev-dependencies.rand] version = "0.8" [dev-dependencies.signal-hook] version = "0.3" diff --git a/third_party/rust/crossbeam-channel/src/channel.rs b/third_party/rust/crossbeam-channel/src/channel.rs --- a/third_party/rust/crossbeam-channel/src/channel.rs +++ b/third_party/rust/crossbeam-channel/src/channel.rs @@ -9,16 +9,17 @@ use std::time::{Duration, Instant}; use crate::context::Context; use crate::counter; use crate::err::{ RecvError, RecvTimeoutError, SendError, SendTimeoutError, TryRecvError, TrySendError, }; use crate::flavors; use crate::select::{Operation, SelectHandle, Token}; +use crate::utils; /// Creates a channel of unbounded capacity. /// /// This channel has a growable buffer that can hold any number of messages at a time. /// /// # Examples /// /// ``` @@ -466,17 +467,17 @@ impl Sender { /// Ok(()), /// ); /// assert_eq!( /// s.send_timeout(3, Duration::from_millis(500)), /// Err(SendTimeoutError::Disconnected(3)), /// ); /// ``` pub fn send_timeout(&self, msg: T, timeout: Duration) -> Result<(), SendTimeoutError> { - self.send_deadline(msg, Instant::now() + timeout) + self.send_deadline(msg, utils::convert_timeout_to_deadline(timeout)) } /// Waits for a message to be sent into the channel, but only until a given deadline. /// /// If the channel is full and not disconnected, this call will block until the send operation /// can proceed or the operation times out. If the channel becomes disconnected, this call will /// wake up and return an error. The returned error contains the original message. /// @@ -856,17 +857,17 @@ impl Receiver { /// Ok(5), /// ); /// assert_eq!( /// r.recv_timeout(Duration::from_secs(1)), /// Err(RecvTimeoutError::Disconnected), /// ); /// ``` pub fn recv_timeout(&self, timeout: Duration) -> Result { - self.recv_deadline(Instant::now() + timeout) + self.recv_deadline(utils::convert_timeout_to_deadline(timeout)) } /// Waits for a message to be received from the channel, but only before a given deadline. /// /// If the channel is empty and not disconnected, this call will block until the receive /// operation can proceed or the operation times out. If the channel is empty and becomes /// disconnected, this call will wake up and return an error. /// diff --git a/third_party/rust/crossbeam-channel/src/err.rs b/third_party/rust/crossbeam-channel/src/err.rs --- a/third_party/rust/crossbeam-channel/src/err.rs +++ b/third_party/rust/crossbeam-channel/src/err.rs @@ -303,26 +303,24 @@ impl From for TryRecvError { match err { RecvError => TryRecvError::Disconnected, } } } impl TryRecvError { /// Returns `true` if the receive operation failed because the channel is empty. - #[allow(clippy::trivially_copy_pass_by_ref)] pub fn is_empty(&self) -> bool { match self { TryRecvError::Empty => true, _ => false, } } /// Returns `true` if the receive operation failed because the channel is disconnected. - #[allow(clippy::trivially_copy_pass_by_ref)] pub fn is_disconnected(&self) -> bool { match self { TryRecvError::Disconnected => true, _ => false, } } } @@ -342,26 +340,24 @@ impl From for RecvTimeoutErro match err { RecvError => RecvTimeoutError::Disconnected, } } } impl RecvTimeoutError { /// Returns `true` if the receive operation timed out. - #[allow(clippy::trivially_copy_pass_by_ref)] pub fn is_timeout(&self) -> bool { match self { RecvTimeoutError::Timeout => true, _ => false, } } /// Returns `true` if the receive operation failed because the channel is disconnected. - #[allow(clippy::trivially_copy_pass_by_ref)] pub fn is_disconnected(&self) -> bool { match self { RecvTimeoutError::Disconnected => true, _ => false, } } } diff --git a/third_party/rust/crossbeam-channel/src/flavors/array.rs b/third_party/rust/crossbeam-channel/src/flavors/array.rs --- a/third_party/rust/crossbeam-channel/src/flavors/array.rs +++ b/third_party/rust/crossbeam-channel/src/flavors/array.rs @@ -4,17 +4,16 @@ //! //! The implementation is based on Dmitry Vyukov's bounded MPMC queue. //! //! Source: //! - //! - use std::cell::UnsafeCell; -use std::marker::PhantomData; use std::mem::MaybeUninit; use std::ptr; use std::sync::atomic::{self, AtomicUsize, Ordering}; use std::time::Instant; use crossbeam_utils::{Backoff, CachePadded}; use crate::context::Context; @@ -28,17 +27,17 @@ struct Slot { stamp: AtomicUsize, /// The message in this slot. msg: UnsafeCell>, } /// The token type for the array flavor. #[derive(Debug)] -pub struct ArrayToken { +pub(crate) struct ArrayToken { /// Slot to read from or write to. slot: *const u8, /// Stamp to store into the slot after reading or writing. stamp: usize, } impl Default for ArrayToken { @@ -67,35 +66,32 @@ pub(crate) struct Channel { /// This value is a "stamp" consisting of an index into the buffer, a mark bit, and a lap, but /// packed into a single `usize`. The lower bits represent the index, while the upper bits /// represent the lap. The mark bit indicates that the channel is disconnected. /// /// Messages are pushed into the tail of the channel. tail: CachePadded, /// The buffer holding slots. - buffer: *mut Slot, + buffer: Box<[Slot]>, /// The channel capacity. cap: usize, /// A stamp with the value of `{ lap: 1, mark: 0, index: 0 }`. one_lap: usize, /// If this bit is set in the tail, that means the channel is disconnected. mark_bit: usize, /// Senders waiting while the channel is full. senders: SyncWaker, /// Receivers waiting while the channel is empty and not disconnected. receivers: SyncWaker, - - /// Indicates that dropping a `Channel` may drop values of type `T`. - _marker: PhantomData, } impl Channel { /// Creates a bounded channel of capacity `cap`. pub(crate) fn with_capacity(cap: usize) -> Self { assert!(cap > 0, "capacity must be positive"); // Compute constants `mark_bit` and `one_lap`. @@ -104,39 +100,35 @@ impl Channel { // Head is initialized to `{ lap: 0, mark: 0, index: 0 }`. let head = 0; // Tail is initialized to `{ lap: 0, mark: 0, index: 0 }`. let tail = 0; // Allocate a buffer of `cap` slots initialized // with stamps. - let buffer = { - let boxed: Box<[Slot]> = (0..cap) - .map(|i| { - // Set the stamp to `{ lap: 0, mark: 0, index: i }`. - Slot { - stamp: AtomicUsize::new(i), - msg: UnsafeCell::new(MaybeUninit::uninit()), - } - }) - .collect(); - Box::into_raw(boxed) as *mut Slot - }; + let buffer: Box<[Slot]> = (0..cap) + .map(|i| { + // Set the stamp to `{ lap: 0, mark: 0, index: i }`. + Slot { + stamp: AtomicUsize::new(i), + msg: UnsafeCell::new(MaybeUninit::uninit()), + } + }) + .collect(); Channel { buffer, cap, one_lap, mark_bit, head: CachePadded::new(AtomicUsize::new(head)), tail: CachePadded::new(AtomicUsize::new(tail)), senders: SyncWaker::new(), receivers: SyncWaker::new(), - _marker: PhantomData, } } /// Returns a receiver handle to the channel. pub(crate) fn receiver(&self) -> Receiver<'_, T> { Receiver(self) } @@ -158,17 +150,18 @@ impl Channel { return true; } // Deconstruct the tail. let index = tail & (self.mark_bit - 1); let lap = tail & !(self.one_lap - 1); // Inspect the corresponding slot. - let slot = unsafe { &*self.buffer.add(index) }; + debug_assert!(index < self.buffer.len()); + let slot = unsafe { self.buffer.get_unchecked(index) }; let stamp = slot.stamp.load(Ordering::Acquire); // 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, mark: 0, index: index + 1 }`. tail + 1 @@ -240,17 +233,18 @@ impl Channel { let mut head = self.head.load(Ordering::Relaxed); loop { // Deconstruct the head. let index = head & (self.mark_bit - 1); let lap = head & !(self.one_lap - 1); // Inspect the corresponding slot. - let slot = unsafe { &*self.buffer.add(index) }; + debug_assert!(index < self.buffer.len()); + let slot = unsafe { self.buffer.get_unchecked(index) }; let stamp = slot.stamp.load(Ordering::Acquire); // If the the stamp is ahead of the head by 1, we may attempt to pop. if head + 1 == stamp { let new = if index + 1 < self.cap { // Same lap, incremented index. // Set to `{ lap: lap, mark: 0, index: index + 1 }`. head + 1 @@ -470,17 +464,16 @@ impl Channel { } else { self.cap }; } } } /// Returns the capacity of the channel. - #[allow(clippy::unnecessary_wraps)] // This is intentional. pub(crate) fn capacity(&self) -> Option { Some(self.cap) } /// Disconnects the channel and wakes up all blocked senders and receivers. /// /// Returns `true` if this call disconnected the channel. pub(crate) fn disconnect(&self) -> bool { @@ -535,33 +528,22 @@ impl Drop for Channel { // 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 { - let p = { - let slot = &mut *self.buffer.add(index); - let msg = &mut *slot.msg.get(); - msg.as_mut_ptr() - }; - p.drop_in_place(); + 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(); } } - - // Finally, deallocate the buffer, but don't run any destructors. - unsafe { - // Create a slice from the buffer to make - // a fat pointer. Then, use Box::from_raw - // to deallocate it. - let ptr = std::slice::from_raw_parts_mut(self.buffer, self.cap) as *mut [Slot]; - Box::from_raw(ptr); - } } } /// Receiver handle to a channel. pub(crate) struct Receiver<'a, T>(&'a Channel); /// Sender handle to a channel. pub(crate) struct Sender<'a, T>(&'a Channel); diff --git a/third_party/rust/crossbeam-channel/src/flavors/at.rs b/third_party/rust/crossbeam-channel/src/flavors/at.rs --- a/third_party/rust/crossbeam-channel/src/flavors/at.rs +++ b/third_party/rust/crossbeam-channel/src/flavors/at.rs @@ -30,17 +30,17 @@ impl Channel { Channel { delivery_time: when, received: AtomicBool::new(false), } } /// Creates a channel that delivers a message after a certain duration of time. #[inline] pub(crate) fn new_timeout(dur: Duration) -> Self { - Self::new_deadline(Instant::now() + dur) + Self::new_deadline(utils::convert_timeout_to_deadline(dur)) } /// Attempts to receive a message without blocking. #[inline] pub(crate) fn try_recv(&self) -> Result { // We use relaxed ordering because this is just an optional optimistic check. if self.received.load(Ordering::Relaxed) { // The message has already been received. @@ -137,17 +137,16 @@ impl Channel { if self.is_empty() { 0 } else { 1 } } /// Returns the capacity of the channel. - #[allow(clippy::unnecessary_wraps)] // This is intentional. #[inline] pub(crate) fn capacity(&self) -> Option { Some(1) } } impl SelectHandle for Channel { #[inline] diff --git a/third_party/rust/crossbeam-channel/src/flavors/list.rs b/third_party/rust/crossbeam-channel/src/flavors/list.rs --- a/third_party/rust/crossbeam-channel/src/flavors/list.rs +++ b/third_party/rust/crossbeam-channel/src/flavors/list.rs @@ -121,17 +121,17 @@ struct Position { index: AtomicUsize, /// The block in the linked list. block: AtomicPtr>, } /// The token type for the list flavor. #[derive(Debug)] -pub struct ListToken { +pub(crate) struct ListToken { /// The block of slots. block: *const u8, /// The offset into the block. offset: usize, } impl Default for ListToken { diff --git a/third_party/rust/crossbeam-channel/src/flavors/never.rs b/third_party/rust/crossbeam-channel/src/flavors/never.rs --- a/third_party/rust/crossbeam-channel/src/flavors/never.rs +++ b/third_party/rust/crossbeam-channel/src/flavors/never.rs @@ -60,17 +60,16 @@ impl Channel { /// Returns the number of messages in the channel. #[inline] pub(crate) fn len(&self) -> usize { 0 } /// Returns the capacity of the channel. - #[allow(clippy::unnecessary_wraps)] // This is intentional. #[inline] pub(crate) fn capacity(&self) -> Option { Some(0) } } impl SelectHandle for Channel { #[inline] diff --git a/third_party/rust/crossbeam-channel/src/flavors/tick.rs b/third_party/rust/crossbeam-channel/src/flavors/tick.rs --- a/third_party/rust/crossbeam-channel/src/flavors/tick.rs +++ b/third_party/rust/crossbeam-channel/src/flavors/tick.rs @@ -5,16 +5,17 @@ use std::thread; use std::time::{Duration, Instant}; use crossbeam_utils::atomic::AtomicCell; use crate::context::Context; use crate::err::{RecvTimeoutError, TryRecvError}; use crate::select::{Operation, SelectHandle, Token}; +use crate::utils; /// Result of a receive operation. pub(crate) type TickToken = Option; /// Channel that delivers messages periodically. pub(crate) struct Channel { /// The instant at which the next message will be delivered. delivery_time: AtomicCell, @@ -23,17 +24,17 @@ pub(crate) struct Channel { duration: Duration, } impl Channel { /// Creates a channel that delivers messages periodically. #[inline] pub(crate) fn new(dur: Duration) -> Self { Channel { - delivery_time: AtomicCell::new(Instant::now() + dur), + delivery_time: AtomicCell::new(utils::convert_timeout_to_deadline(dur)), duration: dur, } } /// Attempts to receive a message without blocking. #[inline] pub(crate) fn try_recv(&self) -> Result { loop { @@ -107,17 +108,16 @@ impl Channel { if self.is_empty() { 0 } else { 1 } } /// Returns the capacity of the channel. - #[allow(clippy::unnecessary_wraps)] // This is intentional. #[inline] pub(crate) fn capacity(&self) -> Option { Some(1) } } impl SelectHandle for Channel { #[inline] diff --git a/third_party/rust/crossbeam-channel/src/flavors/zero.rs b/third_party/rust/crossbeam-channel/src/flavors/zero.rs --- a/third_party/rust/crossbeam-channel/src/flavors/zero.rs +++ b/third_party/rust/crossbeam-channel/src/flavors/zero.rs @@ -12,17 +12,17 @@ use crossbeam_utils::Backoff; use crate::context::Context; use crate::err::{RecvTimeoutError, SendTimeoutError, TryRecvError, TrySendError}; use crate::select::{Operation, SelectHandle, Selected, Token}; use crate::utils::Spinlock; use crate::waker::Waker; /// A pointer to a packet. -pub struct ZeroToken(*mut ()); +pub(crate) struct ZeroToken(*mut ()); impl Default for ZeroToken { fn default() -> Self { Self(ptr::null_mut()) } } impl fmt::Debug for ZeroToken { @@ -358,17 +358,16 @@ impl Channel { } /// Returns the current number of messages inside the channel. pub(crate) fn len(&self) -> usize { 0 } /// Returns the capacity of the channel. - #[allow(clippy::unnecessary_wraps)] // This is intentional. pub(crate) fn capacity(&self) -> Option { Some(0) } /// Returns `true` if the channel is empty. pub(crate) fn is_empty(&self) -> bool { true } diff --git a/third_party/rust/crossbeam-channel/src/select.rs b/third_party/rust/crossbeam-channel/src/select.rs --- a/third_party/rust/crossbeam-channel/src/select.rs +++ b/third_party/rust/crossbeam-channel/src/select.rs @@ -17,22 +17,23 @@ use crate::utils; /// Temporary data that gets initialized during select or a blocking operation, and is consumed by /// `read` or `write`. /// /// Each field contains data associated with a specific channel flavor. // This is a private API that is used by the select macro. #[derive(Debug, Default)] pub struct Token { - pub at: flavors::at::AtToken, - pub array: flavors::array::ArrayToken, - pub list: flavors::list::ListToken, - pub never: flavors::never::NeverToken, - pub tick: flavors::tick::TickToken, - pub zero: flavors::zero::ZeroToken, + pub(crate) at: flavors::at::AtToken, + pub(crate) array: flavors::array::ArrayToken, + pub(crate) list: flavors::list::ListToken, + #[allow(dead_code)] + pub(crate) never: flavors::never::NeverToken, + pub(crate) tick: flavors::tick::TickToken, + pub(crate) zero: flavors::zero::ZeroToken, } /// Identifier associated with an operation by a specific thread on a specific channel. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct Operation(usize); impl Operation { /// Creates an operation identifier from a mutable reference. @@ -481,17 +482,17 @@ pub fn select<'a>( /// Blocks for a limited time until one of the operations becomes ready and selects it. // This is a private API (exposed inside crossbeam_channel::internal module) that is used by the select macro. #[inline] pub fn select_timeout<'a>( handles: &mut [(&'a dyn SelectHandle, usize, *const u8)], timeout: Duration, ) -> Result, SelectTimeoutError> { - select_deadline(handles, Instant::now() + timeout) + select_deadline(handles, utils::convert_timeout_to_deadline(timeout)) } /// Blocks until a given deadline, or until one of the operations becomes ready and selects it. #[inline] pub(crate) fn select_deadline<'a>( handles: &mut [(&'a dyn SelectHandle, usize, *const u8)], deadline: Instant, ) -> Result, SelectTimeoutError> { @@ -1037,17 +1038,17 @@ impl<'a> Select<'a> { /// match sel.ready_timeout(Duration::from_millis(500)) { /// Err(_) => panic!("should not have timed out"), /// Ok(i) if i == oper1 => assert_eq!(r1.try_recv(), Ok(10)), /// Ok(i) if i == oper2 => assert_eq!(r2.try_recv(), Ok(20)), /// Ok(_) => unreachable!(), /// } /// ``` pub fn ready_timeout(&mut self, timeout: Duration) -> Result { - self.ready_deadline(Instant::now() + timeout) + self.ready_deadline(utils::convert_timeout_to_deadline(timeout)) } /// Blocks until a given deadline, or until one of the operations becomes ready. /// /// If an operation becomes ready, its index is returned. If multiple operations are ready at /// the same time, a random one among them is chosen. If none of the operations become ready /// before the deadline, an error is returned. /// diff --git a/third_party/rust/crossbeam-channel/src/select_macro.rs b/third_party/rust/crossbeam-channel/src/select_macro.rs --- a/third_party/rust/crossbeam-channel/src/select_macro.rs +++ b/third_party/rust/crossbeam-channel/src/select_macro.rs @@ -116,28 +116,17 @@ macro_rules! crossbeam_channel_internal $crate::crossbeam_channel_internal!( @list ($($tail)*) ($($head)* $case ($($args)*) $(-> $res)* => { $body },) ) }; // Only one case remains. (@list - ($case:ident ($($args:tt)*) $(-> $res:pat)* => $body:expr) - ($($head:tt)*) - ) => { - $crate::crossbeam_channel_internal!( - @list - () - ($($head)* $case ($($args)*) $(-> $res)* => { $body },) - ) - }; - // Accept a trailing comma at the end of the list. - (@list - ($case:ident ($($args:tt)*) $(-> $res:pat)* => $body:expr,) + ($case:ident ($($args:tt)*) $(-> $res:pat)* => $body:expr $(,)?) ($($head:tt)*) ) => { $crate::crossbeam_channel_internal!( @list () ($($head)* $case ($($args)*) $(-> $res)* => { $body },) ) }; @@ -368,30 +357,17 @@ macro_rules! crossbeam_channel_internal @init $cases $default ) }; // Check the format of a recv case. (@case - (recv($r:expr) -> $res:pat => $body:tt, $($tail:tt)*) - ($($cases:tt)*) - $default:tt - ) => { - $crate::crossbeam_channel_internal!( - @case - ($($tail)*) - ($($cases)* recv($r) -> $res => $body,) - $default - ) - }; - // Allow trailing comma... - (@case - (recv($r:expr,) -> $res:pat => $body:tt, $($tail:tt)*) + (recv($r:expr $(,)?) -> $res:pat => $body:tt, $($tail:tt)*) ($($cases:tt)*) $default:tt ) => { $crate::crossbeam_channel_internal!( @case ($($tail)*) ($($cases)* recv($r) -> $res => $body,) $default @@ -423,30 +399,17 @@ macro_rules! crossbeam_channel_internal stringify!($t), "`", ) ) }; // Check the format of a send case. (@case - (send($s:expr, $m:expr) -> $res:pat => $body:tt, $($tail:tt)*) - ($($cases:tt)*) - $default:tt - ) => { - $crate::crossbeam_channel_internal!( - @case - ($($tail)*) - ($($cases)* send($s, $m) -> $res => $body,) - $default - ) - }; - // Allow trailing comma... - (@case - (send($s:expr, $m:expr,) -> $res:pat => $body:tt, $($tail:tt)*) + (send($s:expr, $m:expr $(,)?) -> $res:pat => $body:tt, $($tail:tt)*) ($($cases:tt)*) $default:tt ) => { $crate::crossbeam_channel_internal!( @case ($($tail)*) ($($cases)* send($s, $m) -> $res => $body,) $default @@ -491,30 +454,17 @@ macro_rules! crossbeam_channel_internal @case ($($tail)*) $cases (default() => $body,) ) }; // Check the format of a default case with timeout. (@case - (default($timeout:expr) => $body:tt, $($tail:tt)*) - $cases:tt - () - ) => { - $crate::crossbeam_channel_internal!( - @case - ($($tail)*) - $cases - (default($timeout) => $body,) - ) - }; - // Allow trailing comma... - (@case - (default($timeout:expr,) => $body:tt, $($tail:tt)*) + (default($timeout:expr $(,)?) => $body:tt, $($tail:tt)*) $cases:tt () ) => { $crate::crossbeam_channel_internal!( @case ($($tail)*) $cases (default($timeout) => $body,) diff --git a/third_party/rust/crossbeam-channel/src/utils.rs b/third_party/rust/crossbeam-channel/src/utils.rs --- a/third_party/rust/crossbeam-channel/src/utils.rs +++ b/third_party/rust/crossbeam-channel/src/utils.rs @@ -56,16 +56,24 @@ pub(crate) fn sleep_until(deadline: Opti break; } thread::sleep(d - now); } } } } +// https://github.com/crossbeam-rs/crossbeam/issues/795 +pub(crate) fn convert_timeout_to_deadline(timeout: Duration) -> Instant { + match Instant::now().checked_add(timeout) { + Some(deadline) => deadline, + None => Instant::now() + Duration::from_secs(86400 * 365 * 30), + } +} + /// A simple spinlock. pub(crate) struct Spinlock { flag: AtomicBool, value: UnsafeCell, } impl Spinlock { /// Returns a new spinlock initialized with `value`. diff --git a/third_party/rust/crossbeam-channel/src/waker.rs b/third_party/rust/crossbeam-channel/src/waker.rs --- a/third_party/rust/crossbeam-channel/src/waker.rs +++ b/third_party/rust/crossbeam-channel/src/waker.rs @@ -72,36 +72,42 @@ impl Waker { } else { None } } /// Attempts to find another thread's entry, select the operation, and wake it up. #[inline] pub(crate) fn try_select(&mut self) -> Option { - self.selectors - .iter() - .position(|selector| { - // Does the entry belong to a different thread? - selector.cx.thread_id() != current_thread_id() - && selector // Try selecting this operation. - .cx - .try_select(Selected::Operation(selector.oper)) - .is_ok() - && { - // Provide the packet. - selector.cx.store_packet(selector.packet); - // Wake the thread up. - selector.cx.unpark(); - true - } - }) - // Remove the entry from the queue to keep it clean and improve - // performance. - .map(|pos| self.selectors.remove(pos)) + if self.selectors.is_empty() { + None + } else { + let thread_id = current_thread_id(); + + self.selectors + .iter() + .position(|selector| { + // Does the entry belong to a different thread? + selector.cx.thread_id() != thread_id + && selector // Try selecting this operation. + .cx + .try_select(Selected::Operation(selector.oper)) + .is_ok() + && { + // Provide the packet. + selector.cx.store_packet(selector.packet); + // Wake the thread up. + selector.cx.unpark(); + true + } + }) + // Remove the entry from the queue to keep it clean and improve + // performance. + .map(|pos| self.selectors.remove(pos)) + } } /// Returns `true` if there is an entry which can be selected by the current thread. #[inline] pub(crate) fn can_select(&self) -> bool { if self.selectors.is_empty() { false } else { diff --git a/third_party/rust/crossbeam-channel/tests/array.rs b/third_party/rust/crossbeam-channel/tests/array.rs --- a/third_party/rust/crossbeam-channel/tests/array.rs +++ b/third_party/rust/crossbeam-channel/tests/array.rs @@ -1,12 +1,10 @@ //! Tests for the array channel flavor. -#![cfg(not(miri))] // TODO: many assertions failed due to Miri is slow - use std::any::Any; use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering; use std::thread; use std::time::Duration; use crossbeam_channel::{bounded, select, Receiver}; use crossbeam_channel::{RecvError, RecvTimeoutError, TryRecvError}; @@ -249,17 +247,23 @@ fn recv_after_disconnect() { assert_eq!(r.recv(), Ok(1)); assert_eq!(r.recv(), Ok(2)); assert_eq!(r.recv(), Ok(3)); assert_eq!(r.recv(), Err(RecvError)); } #[test] fn len() { + #[cfg(miri)] + const COUNT: usize = 250; + #[cfg(not(miri))] const COUNT: usize = 25_000; + #[cfg(miri)] + const CAP: usize = 100; + #[cfg(not(miri))] const CAP: usize = 1000; let (s, r) = bounded(CAP); assert_eq!(s.len(), 0); assert_eq!(r.len(), 0); for _ in 0..CAP / 10 { @@ -342,16 +346,19 @@ fn disconnect_wakes_receiver() { drop(s); }); }) .unwrap(); } #[test] fn spsc() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 100_000; let (s, r) = bounded(3); scope(|scope| { scope.spawn(move |_| { for i in 0..COUNT { assert_eq!(r.recv(), Ok(i)); @@ -364,16 +371,19 @@ fn spsc() { } }); }) .unwrap(); } #[test] fn mpmc() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 25_000; const THREADS: usize = 4; let (s, r) = bounded::(3); let v = (0..COUNT).map(|_| AtomicUsize::new(0)).collect::>(); scope(|scope| { for _ in 0..THREADS { @@ -396,31 +406,37 @@ fn mpmc() { for c in v { assert_eq!(c.load(Ordering::SeqCst), THREADS); } } #[test] fn stress_oneshot() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 10_000; for _ in 0..COUNT { let (s, r) = bounded(1); scope(|scope| { scope.spawn(|_| r.recv().unwrap()); scope.spawn(|_| s.send(0).unwrap()); }) .unwrap(); } } #[test] fn stress_iter() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 100_000; let (request_s, request_r) = bounded(1); let (response_s, response_r) = bounded(1); scope(|scope| { scope.spawn(move |_| { let mut count = 0; @@ -476,16 +492,17 @@ fn stress_timeout_two_threads() { } } } }); }) .unwrap(); } +#[cfg_attr(miri, ignore)] // Miri is too slow #[test] fn drops() { const RUNS: usize = 100; static DROPS: AtomicUsize = AtomicUsize::new(0); #[derive(Debug, PartialEq)] struct DropCounter; @@ -528,16 +545,19 @@ fn drops() { drop(s); drop(r); assert_eq!(DROPS.load(Ordering::SeqCst), steps + additional); } } #[test] fn linearizable() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 25_000; const THREADS: usize = 4; let (s, r) = bounded(THREADS); scope(|scope| { for _ in 0..THREADS { scope.spawn(|_| { @@ -548,16 +568,19 @@ fn linearizable() { }); } }) .unwrap(); } #[test] fn fairness() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 10_000; let (s1, r1) = bounded::<()>(COUNT); let (s2, r2) = bounded::<()>(COUNT); for _ in 0..COUNT { s1.send(()).unwrap(); s2.send(()).unwrap(); @@ -570,16 +593,19 @@ fn fairness() { recv(r2) -> _ => hits[1] += 1, } } assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); } #[test] fn fairness_duplicates() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 10_000; let (s, r) = bounded::<()>(COUNT); for _ in 0..COUNT { s.send(()).unwrap(); } @@ -614,16 +640,19 @@ fn recv_in_send() { select! { send(s, assert_eq!(r.recv(), Ok(()))) -> _ => {} } } #[test] fn channel_through_channel() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 1000; type T = Box; let (s, r) = bounded::(1); scope(|scope| { scope.spawn(move |_| { @@ -649,8 +678,61 @@ fn channel_through_channel() { .unwrap() .take() .unwrap() } }); }) .unwrap(); } + +#[test] +fn panic_on_drop() { + struct Msg1<'a>(&'a mut bool); + impl Drop for Msg1<'_> { + fn drop(&mut self) { + if *self.0 && !std::thread::panicking() { + panic!("double drop"); + } else { + *self.0 = true; + } + } + } + + struct Msg2<'a>(&'a mut bool); + impl Drop for Msg2<'_> { + fn drop(&mut self) { + if *self.0 { + panic!("double drop"); + } else { + *self.0 = true; + panic!("first drop"); + } + } + } + + // normal + let (s, r) = bounded(2); + let (mut a, mut b) = (false, false); + s.send(Msg1(&mut a)).unwrap(); + s.send(Msg1(&mut b)).unwrap(); + drop(s); + drop(r); + assert!(a); + assert!(b); + + // panic on drop + let (s, r) = bounded(2); + let (mut a, mut b) = (false, false); + s.send(Msg2(&mut a)).unwrap(); + s.send(Msg2(&mut b)).unwrap(); + drop(s); + let res = std::panic::catch_unwind(move || { + drop(r); + }); + assert_eq!( + *res.unwrap_err().downcast_ref::<&str>().unwrap(), + "first drop" + ); + assert!(a); + // Elements after the panicked element will leak. + assert!(!b); +} diff --git a/third_party/rust/crossbeam-channel/tests/select_macro.rs b/third_party/rust/crossbeam-channel/tests/select_macro.rs --- a/third_party/rust/crossbeam-channel/tests/select_macro.rs +++ b/third_party/rust/crossbeam-channel/tests/select_macro.rs @@ -1463,8 +1463,19 @@ fn disconnect_wakes_receiver() { }); scope.spawn(move |_| { thread::sleep(ms(1000)); drop(s); }); }) .unwrap(); } + +#[test] +fn trailing_comma() { + let (s, r) = unbounded::(); + + select! { + send(s, 1,) -> _ => {}, + recv(r,) -> _ => {}, + default(ms(1000),) => {}, + } +}