1 | /* Copyright Joyent, Inc. and other Node contributors. All rights reserved. |
2 | * |
3 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
4 | * of this software and associated documentation files (the "Software"), to |
5 | * deal in the Software without restriction, including without limitation the |
6 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
7 | * sell copies of the Software, and to permit persons to whom the Software is |
8 | * furnished to do so, subject to the following conditions: |
9 | * |
10 | * The above copyright notice and this permission notice shall be included in |
11 | * all copies or substantial portions of the Software. |
12 | * |
13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
18 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
19 | * IN THE SOFTWARE. |
20 | */ |
21 | |
22 | /* Tests commented out with XXX are ones that are failing on Linux */ |
23 | |
24 | /* |
25 | * Purpose of this test is to check semantics of starting and stopping |
26 | * prepare, check and idle watchers. |
27 | * |
28 | * - A watcher must be able to safely stop or close itself; |
29 | * - Once a watcher is stopped or closed its callback should never be called. |
30 | * - If a watcher is closed, it is implicitly stopped and its close_cb should |
31 | * be called exactly once. |
32 | * - A watcher can safely start and stop other watchers of the same type. |
33 | * - Prepare and check watchers are called once per event loop iterations. |
34 | * - All active idle watchers are queued when the event loop has no more work |
35 | * to do. This is done repeatedly until all idle watchers are inactive. |
36 | * - If a watcher starts another watcher of the same type its callback is not |
37 | * immediately queued. For check and prepare watchers, that means that if |
38 | * a watcher makes another of the same type active, it'll not be called until |
39 | * the next event loop iteration. For idle. watchers this means that the |
40 | * newly activated idle watcher might not be queued immediately. |
41 | * - Prepare, check, idle watchers keep the event loop alive even when they're |
42 | * not active. |
43 | * |
44 | * This is what the test globally does: |
45 | * |
46 | * - prepare_1 is always active and counts event loop iterations. It also |
47 | * creates and starts prepare_2 every other iteration. Finally it verifies |
48 | * that no idle watchers are active before polling. |
49 | * - prepare_2 is started by prepare_1 every other iteration. It immediately |
50 | * stops itself. It verifies that a watcher is not queued immediately |
51 | * if created by another watcher of the same type. |
52 | * - There's a check watcher that stops the event loop after a certain number |
53 | * of iterations. It starts a varying number of idle_1 watchers. |
54 | * - Idle_1 watchers stop themselves after being called a few times. All idle_1 |
55 | * watchers try to start the idle_2 watcher if it is not already started or |
56 | * awaiting its close callback. |
57 | * - The idle_2 watcher always exists but immediately closes itself after |
58 | * being started by a check_1 watcher. It verifies that a watcher is |
59 | * implicitly stopped when closed, and that a watcher can close itself |
60 | * safely. |
61 | * - There is a repeating timer. It does not keep the event loop alive |
62 | * (ev_unref) but makes sure that the loop keeps polling the system for |
63 | * events. |
64 | */ |
65 | |
66 | |
67 | #include "uv.h" |
68 | #include "task.h" |
69 | |
70 | #include <math.h> |
71 | |
72 | |
73 | #define IDLE_COUNT 7 |
74 | #define ITERATIONS 21 |
75 | #define TIMEOUT 100 |
76 | |
77 | |
78 | static uv_prepare_t prepare_1_handle; |
79 | static uv_prepare_t prepare_2_handle; |
80 | |
81 | static uv_check_t check_handle; |
82 | |
83 | static uv_idle_t idle_1_handles[IDLE_COUNT]; |
84 | static uv_idle_t idle_2_handle; |
85 | |
86 | static uv_timer_t timer_handle; |
87 | |
88 | |
89 | static int loop_iteration = 0; |
90 | |
91 | static int prepare_1_cb_called = 0; |
92 | static int prepare_1_close_cb_called = 0; |
93 | |
94 | static int prepare_2_cb_called = 0; |
95 | static int prepare_2_close_cb_called = 0; |
96 | |
97 | static int check_cb_called = 0; |
98 | static int check_close_cb_called = 0; |
99 | |
100 | static int idle_1_cb_called = 0; |
101 | static int idle_1_close_cb_called = 0; |
102 | static int idles_1_active = 0; |
103 | |
104 | static int idle_2_cb_called = 0; |
105 | static int idle_2_close_cb_called = 0; |
106 | static int idle_2_cb_started = 0; |
107 | static int idle_2_is_active = 0; |
108 | |
109 | |
110 | static void timer_cb(uv_timer_t* handle) { |
111 | ASSERT(handle == &timer_handle); |
112 | } |
113 | |
114 | |
115 | static void idle_2_close_cb(uv_handle_t* handle) { |
116 | fprintf(stderr, "%s" , "IDLE_2_CLOSE_CB\n" ); |
117 | fflush(stderr); |
118 | |
119 | ASSERT(handle == (uv_handle_t*)&idle_2_handle); |
120 | |
121 | ASSERT(idle_2_is_active); |
122 | |
123 | idle_2_close_cb_called++; |
124 | idle_2_is_active = 0; |
125 | } |
126 | |
127 | |
128 | static void idle_2_cb(uv_idle_t* handle) { |
129 | fprintf(stderr, "%s" , "IDLE_2_CB\n" ); |
130 | fflush(stderr); |
131 | |
132 | ASSERT(handle == &idle_2_handle); |
133 | |
134 | idle_2_cb_called++; |
135 | |
136 | uv_close((uv_handle_t*)handle, idle_2_close_cb); |
137 | } |
138 | |
139 | |
140 | static void idle_1_cb(uv_idle_t* handle) { |
141 | int r; |
142 | |
143 | fprintf(stderr, "%s" , "IDLE_1_CB\n" ); |
144 | fflush(stderr); |
145 | |
146 | ASSERT(handle != NULL); |
147 | ASSERT(idles_1_active > 0); |
148 | |
149 | /* Init idle_2 and make it active */ |
150 | if (!idle_2_is_active && !uv_is_closing((uv_handle_t*)&idle_2_handle)) { |
151 | r = uv_idle_init(uv_default_loop(), &idle_2_handle); |
152 | ASSERT(r == 0); |
153 | r = uv_idle_start(&idle_2_handle, idle_2_cb); |
154 | ASSERT(r == 0); |
155 | idle_2_is_active = 1; |
156 | idle_2_cb_started++; |
157 | } |
158 | |
159 | idle_1_cb_called++; |
160 | |
161 | if (idle_1_cb_called % 5 == 0) { |
162 | r = uv_idle_stop((uv_idle_t*)handle); |
163 | ASSERT(r == 0); |
164 | idles_1_active--; |
165 | } |
166 | } |
167 | |
168 | |
169 | static void idle_1_close_cb(uv_handle_t* handle) { |
170 | fprintf(stderr, "%s" , "IDLE_1_CLOSE_CB\n" ); |
171 | fflush(stderr); |
172 | |
173 | ASSERT(handle != NULL); |
174 | |
175 | idle_1_close_cb_called++; |
176 | } |
177 | |
178 | |
179 | static void prepare_1_close_cb(uv_handle_t* handle) { |
180 | fprintf(stderr, "%s" , "PREPARE_1_CLOSE_CB" ); |
181 | fflush(stderr); |
182 | ASSERT(handle == (uv_handle_t*)&prepare_1_handle); |
183 | |
184 | prepare_1_close_cb_called++; |
185 | } |
186 | |
187 | |
188 | static void check_close_cb(uv_handle_t* handle) { |
189 | fprintf(stderr, "%s" , "CHECK_CLOSE_CB\n" ); |
190 | fflush(stderr); |
191 | ASSERT(handle == (uv_handle_t*)&check_handle); |
192 | |
193 | check_close_cb_called++; |
194 | } |
195 | |
196 | |
197 | static void prepare_2_close_cb(uv_handle_t* handle) { |
198 | fprintf(stderr, "%s" , "PREPARE_2_CLOSE_CB\n" ); |
199 | fflush(stderr); |
200 | ASSERT(handle == (uv_handle_t*)&prepare_2_handle); |
201 | |
202 | prepare_2_close_cb_called++; |
203 | } |
204 | |
205 | |
206 | static void check_cb(uv_check_t* handle) { |
207 | int i, r; |
208 | |
209 | fprintf(stderr, "%s" , "CHECK_CB\n" ); |
210 | fflush(stderr); |
211 | ASSERT(handle == &check_handle); |
212 | |
213 | if (loop_iteration < ITERATIONS) { |
214 | /* Make some idle watchers active */ |
215 | for (i = 0; i < 1 + (loop_iteration % IDLE_COUNT); i++) { |
216 | r = uv_idle_start(&idle_1_handles[i], idle_1_cb); |
217 | ASSERT(r == 0); |
218 | idles_1_active++; |
219 | } |
220 | |
221 | } else { |
222 | /* End of the test - close all handles */ |
223 | uv_close((uv_handle_t*)&prepare_1_handle, prepare_1_close_cb); |
224 | uv_close((uv_handle_t*)&check_handle, check_close_cb); |
225 | uv_close((uv_handle_t*)&prepare_2_handle, prepare_2_close_cb); |
226 | |
227 | for (i = 0; i < IDLE_COUNT; i++) { |
228 | uv_close((uv_handle_t*)&idle_1_handles[i], idle_1_close_cb); |
229 | } |
230 | |
231 | /* This handle is closed/recreated every time, close it only if it is |
232 | * active. */ |
233 | if (idle_2_is_active) { |
234 | uv_close((uv_handle_t*)&idle_2_handle, idle_2_close_cb); |
235 | } |
236 | } |
237 | |
238 | check_cb_called++; |
239 | } |
240 | |
241 | |
242 | static void prepare_2_cb(uv_prepare_t* handle) { |
243 | int r; |
244 | |
245 | fprintf(stderr, "%s" , "PREPARE_2_CB\n" ); |
246 | fflush(stderr); |
247 | ASSERT(handle == &prepare_2_handle); |
248 | |
249 | /* Prepare_2 gets started by prepare_1 when (loop_iteration % 2 == 0), and it |
250 | * stops itself immediately. A started watcher is not queued until the next |
251 | * round, so when this callback is made (loop_iteration % 2 == 0) cannot be |
252 | * true. */ |
253 | ASSERT(loop_iteration % 2 != 0); |
254 | |
255 | r = uv_prepare_stop((uv_prepare_t*)handle); |
256 | ASSERT(r == 0); |
257 | |
258 | prepare_2_cb_called++; |
259 | } |
260 | |
261 | |
262 | static void prepare_1_cb(uv_prepare_t* handle) { |
263 | int r; |
264 | |
265 | fprintf(stderr, "%s" , "PREPARE_1_CB\n" ); |
266 | fflush(stderr); |
267 | ASSERT(handle == &prepare_1_handle); |
268 | |
269 | if (loop_iteration % 2 == 0) { |
270 | r = uv_prepare_start(&prepare_2_handle, prepare_2_cb); |
271 | ASSERT(r == 0); |
272 | } |
273 | |
274 | prepare_1_cb_called++; |
275 | loop_iteration++; |
276 | |
277 | printf("Loop iteration %d of %d.\n" , loop_iteration, ITERATIONS); |
278 | } |
279 | |
280 | |
281 | TEST_IMPL(loop_handles) { |
282 | int i; |
283 | int r; |
284 | |
285 | r = uv_prepare_init(uv_default_loop(), &prepare_1_handle); |
286 | ASSERT(r == 0); |
287 | r = uv_prepare_start(&prepare_1_handle, prepare_1_cb); |
288 | ASSERT(r == 0); |
289 | |
290 | r = uv_check_init(uv_default_loop(), &check_handle); |
291 | ASSERT(r == 0); |
292 | r = uv_check_start(&check_handle, check_cb); |
293 | ASSERT(r == 0); |
294 | |
295 | /* initialize only, prepare_2 is started by prepare_1_cb */ |
296 | r = uv_prepare_init(uv_default_loop(), &prepare_2_handle); |
297 | ASSERT(r == 0); |
298 | |
299 | for (i = 0; i < IDLE_COUNT; i++) { |
300 | /* initialize only, idle_1 handles are started by check_cb */ |
301 | r = uv_idle_init(uv_default_loop(), &idle_1_handles[i]); |
302 | ASSERT(r == 0); |
303 | } |
304 | |
305 | /* don't init or start idle_2, both is done by idle_1_cb */ |
306 | |
307 | /* The timer callback is there to keep the event loop polling unref it as it |
308 | * is not supposed to keep the loop alive */ |
309 | r = uv_timer_init(uv_default_loop(), &timer_handle); |
310 | ASSERT(r == 0); |
311 | r = uv_timer_start(&timer_handle, timer_cb, TIMEOUT, TIMEOUT); |
312 | ASSERT(r == 0); |
313 | uv_unref((uv_handle_t*)&timer_handle); |
314 | |
315 | r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); |
316 | ASSERT(r == 0); |
317 | |
318 | ASSERT(loop_iteration == ITERATIONS); |
319 | |
320 | ASSERT(prepare_1_cb_called == ITERATIONS); |
321 | ASSERT(prepare_1_close_cb_called == 1); |
322 | |
323 | ASSERT(prepare_2_cb_called == ITERATIONS / 2); |
324 | ASSERT(prepare_2_close_cb_called == 1); |
325 | |
326 | ASSERT(check_cb_called == ITERATIONS); |
327 | ASSERT(check_close_cb_called == 1); |
328 | |
329 | /* idle_1_cb should be called a lot */ |
330 | ASSERT(idle_1_close_cb_called == IDLE_COUNT); |
331 | |
332 | ASSERT(idle_2_close_cb_called == idle_2_cb_started); |
333 | ASSERT(idle_2_is_active == 0); |
334 | |
335 | MAKE_VALGRIND_HAPPY(); |
336 | return 0; |
337 | } |
338 | |