• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::runtime::{self, Runtime};
2 
3 use std::sync::Arc;
4 
5 #[test]
blocking_shutdown()6 fn 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()27 fn 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()48 fn 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()77 fn 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) -> Runtime97 fn mk_runtime(num_threads: usize) -> Runtime {
98     runtime::Builder::new_multi_thread()
99         .worker_threads(num_threads)
100         .build()
101         .unwrap()
102 }
103