]> git.proxmox.com Git - rustc.git/blame - vendor/rustc-rayon-core/src/spawn/test.rs
New upstream version 1.52.0~beta.3+dfsg1
[rustc.git] / vendor / rustc-rayon-core / src / spawn / test.rs
CommitLineData
6a06907d 1use crate::scope;
2c00a5a8 2use std::any::Any;
2c00a5a8 3use std::sync::mpsc::channel;
532ac7d7 4use std::sync::Mutex;
2c00a5a8 5
e74abb32 6use super::{spawn, spawn_fifo};
6a06907d 7use crate::ThreadPoolBuilder;
2c00a5a8
XL
8
9#[test]
10fn spawn_then_join_in_worker() {
11 let (tx, rx) = channel();
12 scope(move |_| {
13 spawn(move || tx.send(22).unwrap());
14 });
15 assert_eq!(22, rx.recv().unwrap());
16}
17
18#[test]
19fn spawn_then_join_outside_worker() {
20 let (tx, rx) = channel();
21 spawn(move || tx.send(22).unwrap());
22 assert_eq!(22, rx.recv().unwrap());
23}
24
25#[test]
26fn panic_fwd() {
27 let (tx, rx) = channel();
28
29 let tx = Mutex::new(tx);
e74abb32 30 let panic_handler = move |err: Box<dyn Any + Send>| {
2c00a5a8
XL
31 let tx = tx.lock().unwrap();
32 if let Some(&msg) = err.downcast_ref::<&str>() {
33 if msg == "Hello, world!" {
34 tx.send(1).unwrap();
35 } else {
36 tx.send(2).unwrap();
37 }
38 } else {
39 tx.send(3).unwrap();
40 }
41 };
42
43 let builder = ThreadPoolBuilder::new().panic_handler(panic_handler);
44
532ac7d7
XL
45 builder
46 .build()
47 .unwrap()
48 .spawn(move || panic!("Hello, world!"));
2c00a5a8
XL
49
50 assert_eq!(1, rx.recv().unwrap());
51}
52
53/// Test what happens when the thread-pool is dropped but there are
54/// still active asynchronous tasks. We expect the thread-pool to stay
55/// alive and executing until those threads are complete.
56#[test]
57fn termination_while_things_are_executing() {
58 let (tx0, rx0) = channel();
59 let (tx1, rx1) = channel();
60
61 // Create a thread-pool and spawn some code in it, but then drop
62 // our reference to it.
63 {
64 let thread_pool = ThreadPoolBuilder::new().build().unwrap();
65 thread_pool.spawn(move || {
66 let data = rx0.recv().unwrap();
67
68 // At this point, we know the "main" reference to the
69 // `ThreadPool` has been dropped, but there are still
70 // active threads. Launch one more.
71 spawn(move || {
72 tx1.send(data).unwrap();
73 });
74 });
75 }
76
77 tx0.send(22).unwrap();
78 let v = rx1.recv().unwrap();
79 assert_eq!(v, 22);
80}
81
82#[test]
83fn custom_panic_handler_and_spawn() {
84 let (tx, rx) = channel();
85
86 // Create a parallel closure that will send panics on the
87 // channel; since the closure is potentially executed in parallel
88 // with itself, we have to wrap `tx` in a mutex.
89 let tx = Mutex::new(tx);
e74abb32 90 let panic_handler = move |e: Box<dyn Any + Send>| {
2c00a5a8
XL
91 tx.lock().unwrap().send(e).unwrap();
92 };
93
94 // Execute an async that will panic.
95 let builder = ThreadPoolBuilder::new().panic_handler(panic_handler);
96 builder.build().unwrap().spawn(move || {
97 panic!("Hello, world!");
98 });
99
100 // Check that we got back the panic we expected.
101 let error = rx.recv().unwrap();
102 if let Some(&msg) = error.downcast_ref::<&str>() {
103 assert_eq!(msg, "Hello, world!");
104 } else {
105 panic!("did not receive a string from panic handler");
106 }
107}
108
109#[test]
110fn custom_panic_handler_and_nested_spawn() {
111 let (tx, rx) = channel();
112
113 // Create a parallel closure that will send panics on the
114 // channel; since the closure is potentially executed in parallel
115 // with itself, we have to wrap `tx` in a mutex.
116 let tx = Mutex::new(tx);
117 let panic_handler = move |e| {
118 tx.lock().unwrap().send(e).unwrap();
119 };
120
121 // Execute an async that will (eventually) panic.
122 const PANICS: usize = 3;
123 let builder = ThreadPoolBuilder::new().panic_handler(panic_handler);
124 builder.build().unwrap().spawn(move || {
125 // launch 3 nested spawn-asyncs; these should be in the same
126 // thread-pool and hence inherit the same panic handler
532ac7d7 127 for _ in 0..PANICS {
2c00a5a8
XL
128 spawn(move || {
129 panic!("Hello, world!");
130 });
131 }
132 });
133
134 // Check that we get back the panics we expected.
532ac7d7 135 for _ in 0..PANICS {
2c00a5a8
XL
136 let error = rx.recv().unwrap();
137 if let Some(&msg) = error.downcast_ref::<&str>() {
138 assert_eq!(msg, "Hello, world!");
139 } else {
140 panic!("did not receive a string from panic handler");
141 }
142 }
143}
e74abb32
XL
144
145macro_rules! test_order {
146 ($outer_spawn:ident, $inner_spawn:ident) => {{
147 let builder = ThreadPoolBuilder::new().num_threads(1);
148 let pool = builder.build().unwrap();
149 let (tx, rx) = channel();
150 pool.install(move || {
151 for i in 0..10 {
152 let tx = tx.clone();
153 $outer_spawn(move || {
154 for j in 0..10 {
155 let tx = tx.clone();
156 $inner_spawn(move || {
157 tx.send(i * 10 + j).unwrap();
158 });
159 }
160 });
161 }
162 });
163 rx.iter().collect::<Vec<i32>>()
164 }};
165}
166
167#[test]
168fn lifo_order() {
169 // In the absense of stealing, `spawn()` jobs on a thread will run in LIFO order.
170 let vec = test_order!(spawn, spawn);
171 let expected: Vec<i32> = (0..100).rev().collect(); // LIFO -> reversed
172 assert_eq!(vec, expected);
173}
174
175#[test]
176fn fifo_order() {
177 // In the absense of stealing, `spawn_fifo()` jobs on a thread will run in FIFO order.
178 let vec = test_order!(spawn_fifo, spawn_fifo);
179 let expected: Vec<i32> = (0..100).collect(); // FIFO -> natural order
180 assert_eq!(vec, expected);
181}
182
183#[test]
184fn lifo_fifo_order() {
185 // LIFO on the outside, FIFO on the inside
186 let vec = test_order!(spawn, spawn_fifo);
187 let expected: Vec<i32> = (0..10)
188 .rev()
189 .flat_map(|i| (0..10).map(move |j| i * 10 + j))
190 .collect();
191 assert_eq!(vec, expected);
192}
193
194#[test]
195fn fifo_lifo_order() {
196 // FIFO on the outside, LIFO on the inside
197 let vec = test_order!(spawn_fifo, spawn);
198 let expected: Vec<i32> = (0..10)
199 .flat_map(|i| (0..10).rev().map(move |j| i * 10 + j))
200 .collect();
201 assert_eq!(vec, expected);
202}
203
204macro_rules! spawn_send {
205 ($spawn:ident, $tx:ident, $i:expr) => {{
206 let tx = $tx.clone();
207 $spawn(move || tx.send($i).unwrap());
208 }};
209}
210
211/// Test mixed spawns pushing a series of numbers, interleaved such
212/// such that negative values are using the second kind of spawn.
213macro_rules! test_mixed_order {
214 ($pos_spawn:ident, $neg_spawn:ident) => {{
215 let builder = ThreadPoolBuilder::new().num_threads(1);
216 let pool = builder.build().unwrap();
217 let (tx, rx) = channel();
218 pool.install(move || {
219 spawn_send!($pos_spawn, tx, 0);
220 spawn_send!($neg_spawn, tx, -1);
221 spawn_send!($pos_spawn, tx, 1);
222 spawn_send!($neg_spawn, tx, -2);
223 spawn_send!($pos_spawn, tx, 2);
224 spawn_send!($neg_spawn, tx, -3);
225 spawn_send!($pos_spawn, tx, 3);
226 });
227 rx.iter().collect::<Vec<i32>>()
228 }};
229}
230
231#[test]
232fn mixed_lifo_fifo_order() {
233 let vec = test_mixed_order!(spawn, spawn_fifo);
234 let expected = vec![3, -1, 2, -2, 1, -3, 0];
235 assert_eq!(vec, expected);
236}
237
238#[test]
239fn mixed_fifo_lifo_order() {
240 let vec = test_mixed_order!(spawn_fifo, spawn);
241 let expected = vec![0, -3, 1, -2, 2, -1, 3];
242 assert_eq!(vec, expected);
243}