• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use std::any::Any;
2 use std::sync::atomic::{AtomicUsize, Ordering};
3 use std::thread::sleep;
4 use std::time::Duration;
5 
6 use crossbeam_utils::thread;
7 
8 const THREADS: usize = 10;
9 const SMALL_STACK_SIZE: usize = 20;
10 
11 #[test]
12 // Android aborts on panic and this test relies on stack unwinding.
13 #[cfg(not(target_os = "android"))]
join()14 fn join() {
15     let counter = AtomicUsize::new(0);
16     thread::scope(|scope| {
17         let handle = scope.spawn(|_| {
18             counter.store(1, Ordering::Relaxed);
19         });
20         assert!(handle.join().is_ok());
21 
22         let panic_handle = scope.spawn(|_| {
23             panic!("\"My honey is running out!\", said Pooh.");
24         });
25         assert!(panic_handle.join().is_err());
26     })
27     .unwrap();
28 
29     // There should be sufficient synchronization.
30     assert_eq!(1, counter.load(Ordering::Relaxed));
31 }
32 
33 #[test]
counter()34 fn counter() {
35     let counter = AtomicUsize::new(0);
36     thread::scope(|scope| {
37         for _ in 0..THREADS {
38             scope.spawn(|_| {
39                 counter.fetch_add(1, Ordering::Relaxed);
40             });
41         }
42     })
43     .unwrap();
44 
45     assert_eq!(THREADS, counter.load(Ordering::Relaxed));
46 }
47 
48 #[test]
counter_builder()49 fn counter_builder() {
50     let counter = AtomicUsize::new(0);
51     thread::scope(|scope| {
52         for i in 0..THREADS {
53             scope
54                 .builder()
55                 .name(format!("child-{}", i))
56                 .stack_size(SMALL_STACK_SIZE)
57                 .spawn(|_| {
58                     counter.fetch_add(1, Ordering::Relaxed);
59                 })
60                 .unwrap();
61         }
62     })
63     .unwrap();
64 
65     assert_eq!(THREADS, counter.load(Ordering::Relaxed));
66 }
67 
68 #[test]
69 // Android aborts on panic and this test relies on stack unwinding.
70 #[cfg(not(target_os = "android"))]
counter_panic()71 fn counter_panic() {
72     let counter = AtomicUsize::new(0);
73     let result = thread::scope(|scope| {
74         scope.spawn(|_| {
75             panic!("\"My honey is running out!\", said Pooh.");
76         });
77         sleep(Duration::from_millis(100));
78 
79         for _ in 0..THREADS {
80             scope.spawn(|_| {
81                 counter.fetch_add(1, Ordering::Relaxed);
82             });
83         }
84     });
85 
86     assert_eq!(THREADS, counter.load(Ordering::Relaxed));
87     assert!(result.is_err());
88 }
89 
90 #[test]
91 // Android aborts on panic and this test relies on stack unwinding.
92 #[cfg(not(target_os = "android"))]
panic_twice()93 fn panic_twice() {
94     let result = thread::scope(|scope| {
95         scope.spawn(|_| {
96             sleep(Duration::from_millis(500));
97             panic!("thread #1");
98         });
99         scope.spawn(|_| {
100             panic!("thread #2");
101         });
102     });
103 
104     let err = result.unwrap_err();
105     let vec = err
106         .downcast_ref::<Vec<Box<dyn Any + Send + 'static>>>()
107         .unwrap();
108     assert_eq!(2, vec.len());
109 
110     let first = vec[0].downcast_ref::<&str>().unwrap();
111     let second = vec[1].downcast_ref::<&str>().unwrap();
112     assert_eq!("thread #1", *first);
113     assert_eq!("thread #2", *second)
114 }
115 
116 #[test]
117 // Android aborts on panic and this test relies on stack unwinding.
118 #[cfg(not(target_os = "android"))]
panic_many()119 fn panic_many() {
120     let result = thread::scope(|scope| {
121         scope.spawn(|_| panic!("deliberate panic #1"));
122         scope.spawn(|_| panic!("deliberate panic #2"));
123         scope.spawn(|_| panic!("deliberate panic #3"));
124     });
125 
126     let err = result.unwrap_err();
127     let vec = err
128         .downcast_ref::<Vec<Box<dyn Any + Send + 'static>>>()
129         .unwrap();
130     assert_eq!(3, vec.len());
131 
132     for panic in vec.iter() {
133         let panic = panic.downcast_ref::<&str>().unwrap();
134         assert!(
135             *panic == "deliberate panic #1"
136                 || *panic == "deliberate panic #2"
137                 || *panic == "deliberate panic #3"
138         );
139     }
140 }
141 
142 #[test]
nesting()143 fn nesting() {
144     let var = "foo".to_string();
145 
146     struct Wrapper<'a> {
147         var: &'a String,
148     }
149 
150     impl<'a> Wrapper<'a> {
151         fn recurse(&'a self, scope: &thread::Scope<'a>, depth: usize) {
152             assert_eq!(self.var, "foo");
153 
154             if depth > 0 {
155                 scope.spawn(move |scope| {
156                     self.recurse(scope, depth - 1);
157                 });
158             }
159         }
160     }
161 
162     let wrapper = Wrapper { var: &var };
163 
164     thread::scope(|scope| {
165         scope.spawn(|scope| {
166             scope.spawn(|scope| {
167                 wrapper.recurse(scope, 5);
168             });
169         });
170     })
171     .unwrap();
172 }
173 
174 #[test]
join_nested()175 fn join_nested() {
176     thread::scope(|scope| {
177         scope.spawn(|scope| {
178             let handle = scope.spawn(|_| 7);
179 
180             sleep(Duration::from_millis(200));
181             handle.join().unwrap();
182         });
183 
184         sleep(Duration::from_millis(100));
185     })
186     .unwrap();
187 }
188 
189 #[test]
scope_returns_ok()190 fn scope_returns_ok() {
191     let result = thread::scope(|scope| scope.spawn(|_| 1234).join().unwrap()).unwrap();
192     assert_eq!(result, 1234);
193 }
194 
195 #[cfg(unix)]
196 #[test]
as_pthread_t()197 fn as_pthread_t() {
198     use std::os::unix::thread::JoinHandleExt;
199     thread::scope(|scope| {
200         let handle = scope.spawn(|_scope| {
201             sleep(Duration::from_millis(100));
202             42
203         });
204         let _pthread_t = handle.as_pthread_t();
205         handle.join().unwrap();
206     })
207     .unwrap();
208 }
209 
210 #[cfg(windows)]
211 #[test]
as_raw_handle()212 fn as_raw_handle() {
213     use std::os::windows::io::AsRawHandle;
214     thread::scope(|scope| {
215         let handle = scope.spawn(|_scope| {
216             sleep(Duration::from_millis(100));
217             42
218         });
219         let _raw_handle = handle.as_raw_handle();
220         handle.join().unwrap();
221     })
222     .unwrap();
223 }
224