From 4d58d2bcd5e08f0123d2f3ac39c6a090dfee23d6 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Fri, 14 Mar 2025 22:34:42 +0100 Subject: rtic-sync: add test validating that free queue slots are not lost on drop --- rtic-sync/src/channel.rs | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'rtic-sync/src') diff --git a/rtic-sync/src/channel.rs b/rtic-sync/src/channel.rs index e4dc835..17fd50a 100644 --- a/rtic-sync/src/channel.rs +++ b/rtic-sync/src/channel.rs @@ -559,6 +559,8 @@ impl Drop for Receiver<'_, T, N> { #[cfg(test)] mod tests { + use cassette::Cassette; + use super::*; #[test] @@ -684,4 +686,43 @@ mod tests { fn tuple_channel() { let _ = make_channel!((i32, u32), 10); } + + fn freeq(channel: &Channel, f: F) -> R + where + F: FnOnce(&mut Deque) -> R, + { + critical_section::with(|cs| f(channel.access(cs).freeq)) + } + + #[test] + fn dropping_waked_send_returns_freeq_item() { + let (mut tx, mut rx) = make_channel!(u8, 1); + + tx.try_send(0).unwrap(); + assert!(freeq(&rx.0, |q| q.is_empty())); + + // Running this in a separate thread scope to ensure that `pinned_future` is dropped fully. + // + // Calling drop explicitly gets hairy because dropping things behind a `Pin` is not easy. + std::thread::scope(|scope| { + scope.spawn(|| { + let pinned_future = core::pin::pin!(tx.send(1)); + let mut future = Cassette::new(pinned_future); + + future.poll_on(); + + assert!(freeq(&rx.0, |q| q.is_empty())); + assert!(!rx.0.wait_queue.is_empty()); + + assert_eq!(rx.try_recv(), Ok(0)); + + assert!(freeq(&rx.0, |q| q.is_empty())); + }); + }); + + assert!(!freeq(&rx.0, |q| q.is_empty())); + + // Make sure that rx & tx are alive until here for good measure. + drop((tx, rx)); + } } -- cgit v1.2.3