]>
Commit | Line | Data |
---|---|---|
2c00a5a8 XL |
1 | #![cfg(test)] |
2 | ||
3 | #[allow(deprecated)] | |
4 | use Configuration; | |
5 | use {ThreadPoolBuilder, ThreadPoolBuildError}; | |
6 | use std::sync::{Arc, Barrier}; | |
7 | use std::sync::atomic::{AtomicUsize, Ordering}; | |
8 | ||
9 | #[test] | |
10 | fn worker_thread_index() { | |
11 | let pool = ThreadPoolBuilder::new().num_threads(22).build().unwrap(); | |
12 | assert_eq!(pool.current_num_threads(), 22); | |
13 | assert_eq!(pool.current_thread_index(), None); | |
14 | let index = pool.install(|| pool.current_thread_index().unwrap()); | |
15 | assert!(index < 22); | |
16 | } | |
17 | ||
18 | #[test] | |
19 | fn start_callback_called() { | |
20 | let n_threads = 16; | |
21 | let n_called = Arc::new(AtomicUsize::new(0)); | |
22 | // Wait for all the threads in the pool plus the one running tests. | |
23 | let barrier = Arc::new(Barrier::new(n_threads + 1)); | |
24 | ||
25 | let b = barrier.clone(); | |
26 | let nc = n_called.clone(); | |
27 | let start_handler = move |_| { | |
28 | nc.fetch_add(1, Ordering::SeqCst); | |
29 | b.wait(); | |
30 | }; | |
31 | ||
32 | let conf = ThreadPoolBuilder::new() | |
33 | .num_threads(n_threads) | |
34 | .start_handler(start_handler); | |
35 | let _ = conf.build().unwrap(); | |
36 | ||
37 | // Wait for all the threads to have been scheduled to run. | |
38 | barrier.wait(); | |
39 | ||
40 | // The handler must have been called on every started thread. | |
41 | assert_eq!(n_called.load(Ordering::SeqCst), n_threads); | |
42 | } | |
43 | ||
44 | #[test] | |
45 | fn exit_callback_called() { | |
46 | let n_threads = 16; | |
47 | let n_called = Arc::new(AtomicUsize::new(0)); | |
48 | // Wait for all the threads in the pool plus the one running tests. | |
49 | let barrier = Arc::new(Barrier::new(n_threads + 1)); | |
50 | ||
51 | let b = barrier.clone(); | |
52 | let nc = n_called.clone(); | |
53 | let exit_handler = move |_| { | |
54 | nc.fetch_add(1, Ordering::SeqCst); | |
55 | b.wait(); | |
56 | }; | |
57 | ||
58 | let conf = ThreadPoolBuilder::new() | |
59 | .num_threads(n_threads) | |
60 | .exit_handler(exit_handler); | |
61 | { | |
62 | let _ = conf.build().unwrap(); | |
63 | // Drop the pool so it stops the running threads. | |
64 | } | |
65 | ||
66 | // Wait for all the threads to have been scheduled to run. | |
67 | barrier.wait(); | |
68 | ||
69 | // The handler must have been called on every exiting thread. | |
70 | assert_eq!(n_called.load(Ordering::SeqCst), n_threads); | |
71 | } | |
72 | ||
73 | #[test] | |
74 | fn handler_panics_handled_correctly() { | |
75 | let n_threads = 16; | |
76 | let n_called = Arc::new(AtomicUsize::new(0)); | |
77 | // Wait for all the threads in the pool plus the one running tests. | |
78 | let start_barrier = Arc::new(Barrier::new(n_threads + 1)); | |
79 | let exit_barrier = Arc::new(Barrier::new(n_threads + 1)); | |
80 | ||
81 | let start_handler = move |_| { | |
82 | panic!("ensure panic handler is called when starting"); | |
83 | }; | |
84 | let exit_handler = move |_| { | |
85 | panic!("ensure panic handler is called when exiting"); | |
86 | }; | |
87 | ||
88 | let sb = start_barrier.clone(); | |
89 | let eb = exit_barrier.clone(); | |
90 | let nc = n_called.clone(); | |
91 | let panic_handler = move |_| { | |
92 | let val = nc.fetch_add(1, Ordering::SeqCst); | |
93 | if val < n_threads { | |
94 | sb.wait(); | |
95 | } else { | |
96 | eb.wait(); | |
97 | } | |
98 | }; | |
99 | ||
100 | let conf = ThreadPoolBuilder::new() | |
101 | .num_threads(n_threads) | |
102 | .start_handler(start_handler) | |
103 | .exit_handler(exit_handler) | |
104 | .panic_handler(panic_handler); | |
105 | { | |
106 | let _ = conf.build().unwrap(); | |
107 | ||
108 | // Wait for all the threads to start, panic in the start handler, | |
109 | // and been taken care of by the panic handler. | |
110 | start_barrier.wait(); | |
111 | ||
112 | // Drop the pool so it stops the running threads. | |
113 | } | |
114 | ||
115 | // Wait for all the threads to exit, panic in the exit handler, | |
116 | // and been taken care of by the panic handler. | |
117 | exit_barrier.wait(); | |
118 | ||
119 | // The panic handler must have been called twice on every thread. | |
120 | assert_eq!(n_called.load(Ordering::SeqCst), 2 * n_threads); | |
121 | } | |
122 | ||
123 | #[test] | |
124 | #[allow(deprecated)] | |
125 | fn check_config_build() { | |
126 | let pool = ThreadPoolBuilder::new().num_threads(22).build().unwrap(); | |
127 | assert_eq!(pool.current_num_threads(), 22); | |
128 | } | |
129 | ||
130 | ||
131 | /// Helper used by check_error_send_sync to ensure ThreadPoolBuildError is Send + Sync | |
132 | fn _send_sync<T: Send + Sync>() { } | |
133 | ||
134 | #[test] | |
135 | fn check_error_send_sync() { | |
136 | _send_sync::<ThreadPoolBuildError>(); | |
137 | } | |
138 | ||
139 | #[allow(deprecated)] | |
140 | #[test] | |
141 | fn configuration() { | |
142 | let start_handler = move |_| { }; | |
143 | let exit_handler = move |_| { }; | |
144 | let panic_handler = move |_| { }; | |
145 | let thread_name = move |i| { format!("thread_name_{}", i) }; | |
146 | ||
147 | // Ensure we can call all public methods on Configuration | |
148 | Configuration::new() | |
149 | .thread_name(thread_name) | |
150 | .num_threads(5) | |
151 | .panic_handler(panic_handler) | |
152 | .stack_size(4e6 as usize) | |
153 | .breadth_first() | |
154 | .start_handler(start_handler) | |
155 | .exit_handler(exit_handler) | |
156 | .build().unwrap(); | |
157 | } |