Files
core/test/rust/performance/task/cleanup.rs
T
2026-11-03 03:32:07 +00:00

77 lines
3.5 KiB
Rust

// 只由显式检查入口运行;同步通道控制 worker 时点,不用睡眠猜测退出顺序。
use std::sync::atomic::{AtomicBool, Ordering};
struct WorkerOutput(Arc<AtomicBool>);
impl Drop for WorkerOutput {
fn drop(&mut self) {
self.0.store(true, Ordering::SeqCst);
}
}
fn check_worker_cleanup() {
assert!(matches!(native_blocking_sleep(-1), Err(NativeAsyncFailure::Sleep(message, _))
if message == "sleep duration must be nonnegative"));
let native = NativeTasks::new();
native.worker_scope(async |tasks| {
assert_eq!(native.tracked_blocking(tasks, || 42).await.unwrap(), 42);
let failure = native.tracked_blocking(tasks, || Err::<(), _>("business failure")).await;
assert_eq!(failure.unwrap(), Err("business failure"));
tasks.close();
assert!(native.tracked_blocking(tasks, || panic!("closed scope ran work")).await.is_err());
}).unwrap();
let called = Arc::new(AtomicBool::new(false));
native.worker_scope(async |tasks| {
let permits = native.workers.clone().acquire_many_owned(2).await.unwrap();
let observed = called.clone();
let queued = native.tracked_blocking(tasks, move || observed.store(true, Ordering::SeqCst));
let mut queued = Box::pin(queued);
assert!(futures_util::poll!(queued.as_mut()).is_pending());
drop(queued);
drop(permits);
}).unwrap();
assert!(!called.load(Ordering::SeqCst));
// 调用者取消、worker panic、根入口 panic 都必须排空真实工作和未领取结果。
for worker_panics in [false, true] {
for root_panics in [false, true] {
let dropped = Arc::new(AtomicBool::new(false));
let observed = dropped.clone();
let (release, blocked) = std::sync::mpsc::channel();
let (started, ready) = tokio::sync::oneshot::channel();
let worker = move || {
started.send(()).unwrap();
blocked.recv_timeout(Duration::from_secs(2)).unwrap();
let output = WorkerOutput(dropped);
if worker_panics { std::panic::panic_any(output); }
output
};
let result = native.worker_scope(async |tasks| {
let mut pending = Box::pin(native.tracked_blocking(tasks, worker));
assert!(futures_util::poll!(pending.as_mut()).is_pending());
ready.await.unwrap();
drop(pending);
assert_eq!(native.workers.available_permits(), 1);
assert!(!tasks.is_empty());
assert!(!observed.load(Ordering::SeqCst));
release.send(()).unwrap();
if root_panics { panic!("root failure after worker submission"); }
});
assert_eq!(result.is_err(), root_panics);
assert!(observed.load(Ordering::SeqCst));
assert_eq!(native.workers.available_permits(), 2);
}
}
let claimed = native.worker_scope(async |tasks| {
let result = native.tracked_blocking(tasks, || String::from("owned output")).await.unwrap();
tasks.close();
tasks.wait().await;
result
}).unwrap();
assert_eq!(claimed, "owned output");
assert_eq!(native.worker_scope(async |tasks| native.tracked_blocking(tasks, || 7).await).unwrap().unwrap(), 7);
println!("worker cleanup: success, business error, closed scope, queued cancellation, running cancellation, panic, result drop and re-entry passed");
}