// 只由显式检查入口运行;同步通道控制 worker 时点,不用睡眠猜测退出顺序。 use std::sync::atomic::{AtomicBool, Ordering}; struct WorkerOutput(Arc); 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"); }