#![cfg(feature = "rt")]
#![cfg(test)]
mod panic_support;
mod support;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, mpsc};
use panic_support::runtime;
use support::JoinHandleExt as _;
use testing_aids::TEST_TIMEOUT;
use thread_aware::Unaware;
testing_aids::init_tracing!();
struct ResultDropPanic {
drops: Arc<AtomicUsize>,
dropped: mpsc::Sender<()>,
}
impl Drop for ResultDropPanic {
fn drop(&mut self) {
self.drops.fetch_add(1, Ordering::SeqCst);
self.dropped.send(()).unwrap();
panic!("unreceived result destructor");
}
}
#[test]
fn abandoned_remote_result_drop_is_contained() {
let runtime = runtime();
let (release, gate) = events_once::Event::boxed();
let (dropped, received) = mpsc::channel();
let drops = Arc::new(AtomicUsize::new(0));
let captured = Arc::clone(&drops);
let task = runtime.scheduler().spawn_anywhere(
Unaware((gate, captured, dropped)),
|_, Unaware((gate, drops, dropped))| async move {
gate.await.unwrap();
Unaware(ResultDropPanic { drops, dropped })
},
);
drop(task);
release.send(());
received.recv_timeout(TEST_TIMEOUT).unwrap();
assert_eq!(runtime.scheduler().spawn_anywhere((), |_, ()| async { 7 }).join().unwrap(), 7);
assert_eq!(drops.load(Ordering::SeqCst), 1);
runtime.stop().unwrap();
}
#[test]
fn abandoned_blocking_result_drop_is_contained() {
let runtime = runtime();
let (started, ready) = mpsc::channel();
let (release, gate) = mpsc::channel();
let (dropped, received) = mpsc::channel();
let drops = Arc::new(AtomicUsize::new(0));
let captured = Arc::clone(&drops);
let task = runtime.scheduler().spawn_blocking(move || {
started.send(()).unwrap();
gate.recv_timeout(TEST_TIMEOUT).unwrap();
ResultDropPanic { drops: captured, dropped }
});
ready.recv_timeout(TEST_TIMEOUT).unwrap();
drop(task);
release.send(()).unwrap();
received.recv_timeout(TEST_TIMEOUT).unwrap();
assert_eq!(runtime.scheduler().spawn_blocking(|| 7).join().unwrap(), 7);
assert_eq!(drops.load(Ordering::SeqCst), 1);
runtime.stop().unwrap();
}