1 use crate::runtime::{self, Runtime}; 2 3 use std::sync::Arc; 4 5 #[test] blocking_shutdown()6fn blocking_shutdown() { 7 loom::model(|| { 8 let v = Arc::new(()); 9 10 let rt = mk_runtime(1); 11 { 12 let _enter = rt.enter(); 13 for _ in 0..2 { 14 let v = v.clone(); 15 crate::task::spawn_blocking(move || { 16 assert!(1 < Arc::strong_count(&v)); 17 }); 18 } 19 } 20 21 drop(rt); 22 assert_eq!(1, Arc::strong_count(&v)); 23 }); 24 } 25 26 #[test] spawn_mandatory_blocking_should_always_run()27fn spawn_mandatory_blocking_should_always_run() { 28 use crate::runtime::tests::loom_oneshot; 29 loom::model(|| { 30 let rt = runtime::Builder::new_current_thread().build().unwrap(); 31 32 let (tx, rx) = loom_oneshot::channel(); 33 let _enter = rt.enter(); 34 runtime::spawn_blocking(|| {}); 35 runtime::spawn_mandatory_blocking(move || { 36 let _ = tx.send(()); 37 }) 38 .unwrap(); 39 40 drop(rt); 41 42 // This call will deadlock if `spawn_mandatory_blocking` doesn't run. 43 let () = rx.recv(); 44 }); 45 } 46 47 #[test] spawn_mandatory_blocking_should_run_even_when_shutting_down_from_other_thread()48fn spawn_mandatory_blocking_should_run_even_when_shutting_down_from_other_thread() { 49 use crate::runtime::tests::loom_oneshot; 50 loom::model(|| { 51 let rt = runtime::Builder::new_current_thread().build().unwrap(); 52 let handle = rt.handle().clone(); 53 54 // Drop the runtime in a different thread 55 { 56 loom::thread::spawn(move || { 57 drop(rt); 58 }); 59 } 60 61 let _enter = handle.enter(); 62 let (tx, rx) = loom_oneshot::channel(); 63 let handle = runtime::spawn_mandatory_blocking(move || { 64 let _ = tx.send(()); 65 }); 66 67 // handle.is_some() means that `spawn_mandatory_blocking` 68 // promised us to run the blocking task 69 if handle.is_some() { 70 // This call will deadlock if `spawn_mandatory_blocking` doesn't run. 71 let () = rx.recv(); 72 } 73 }); 74 } 75 76 #[test] spawn_blocking_when_paused()77fn spawn_blocking_when_paused() { 78 use std::time::Duration; 79 loom::model(|| { 80 let rt = crate::runtime::Builder::new_current_thread() 81 .enable_time() 82 .start_paused(true) 83 .build() 84 .unwrap(); 85 let handle = rt.handle(); 86 let _enter = handle.enter(); 87 let a = crate::task::spawn_blocking(|| {}); 88 let b = crate::task::spawn_blocking(|| {}); 89 rt.block_on(crate::time::timeout(Duration::from_millis(1), async move { 90 a.await.expect("blocking task should finish"); 91 b.await.expect("blocking task should finish"); 92 })) 93 .expect("timeout should not trigger"); 94 }); 95 } 96 mk_runtime(num_threads: usize) -> Runtime97fn mk_runtime(num_threads: usize) -> Runtime { 98 runtime::Builder::new_multi_thread() 99 .worker_threads(num_threads) 100 .build() 101 .unwrap() 102 } 103