]>
Commit | Line | Data |
---|---|---|
b2ea25d7 PB |
1 | /* |
2 | * AioContext tests | |
3 | * | |
4 | * Copyright Red Hat, Inc. 2012 | |
5 | * | |
6 | * Authors: | |
7 | * Paolo Bonzini <pbonzini@redhat.com> | |
8 | * | |
9 | * This work is licensed under the terms of the GNU LGPL, version 2 or later. | |
10 | * See the COPYING.LIB file in the top-level directory. | |
11 | */ | |
12 | ||
13 | #include <glib.h> | |
737e150e | 14 | #include "block/aio.h" |
dae21b98 | 15 | #include "qemu/timer.h" |
a94a3fac | 16 | #include "qemu/sockets.h" |
b2ea25d7 PB |
17 | |
18 | AioContext *ctx; | |
19 | ||
24d1a6d9 SH |
20 | typedef struct { |
21 | EventNotifier e; | |
22 | int n; | |
23 | int active; | |
24 | bool auto_set; | |
25 | } EventNotifierTestData; | |
26 | ||
9fe3781f SH |
27 | /* Wait until there are no more BHs or AIO requests */ |
28 | static void wait_for_aio(void) | |
29 | { | |
30 | while (aio_poll(ctx, true)) { | |
31 | /* Do nothing */ | |
32 | } | |
33 | } | |
34 | ||
24d1a6d9 SH |
35 | /* Wait until event notifier becomes inactive */ |
36 | static void wait_until_inactive(EventNotifierTestData *data) | |
37 | { | |
38 | while (data->active > 0) { | |
39 | aio_poll(ctx, true); | |
40 | } | |
41 | } | |
42 | ||
b2ea25d7 PB |
43 | /* Simple callbacks for testing. */ |
44 | ||
45 | typedef struct { | |
46 | QEMUBH *bh; | |
47 | int n; | |
48 | int max; | |
49 | } BHTestData; | |
50 | ||
b53edf97 AB |
51 | typedef struct { |
52 | QEMUTimer timer; | |
53 | QEMUClockType clock_type; | |
54 | int n; | |
55 | int max; | |
56 | int64_t ns; | |
57 | AioContext *ctx; | |
58 | } TimerTestData; | |
59 | ||
b2ea25d7 PB |
60 | static void bh_test_cb(void *opaque) |
61 | { | |
62 | BHTestData *data = opaque; | |
63 | if (++data->n < data->max) { | |
64 | qemu_bh_schedule(data->bh); | |
65 | } | |
66 | } | |
67 | ||
b53edf97 AB |
68 | static void timer_test_cb(void *opaque) |
69 | { | |
70 | TimerTestData *data = opaque; | |
71 | if (++data->n < data->max) { | |
72 | timer_mod(&data->timer, | |
73 | qemu_clock_get_ns(data->clock_type) + data->ns); | |
74 | } | |
75 | } | |
76 | ||
77 | static void dummy_io_handler_read(void *opaque) | |
78 | { | |
79 | } | |
80 | ||
b2ea25d7 PB |
81 | static void bh_delete_cb(void *opaque) |
82 | { | |
83 | BHTestData *data = opaque; | |
84 | if (++data->n < data->max) { | |
85 | qemu_bh_schedule(data->bh); | |
86 | } else { | |
87 | qemu_bh_delete(data->bh); | |
88 | data->bh = NULL; | |
89 | } | |
90 | } | |
91 | ||
b2ea25d7 PB |
92 | static void event_ready_cb(EventNotifier *e) |
93 | { | |
94 | EventNotifierTestData *data = container_of(e, EventNotifierTestData, e); | |
95 | g_assert(event_notifier_test_and_clear(e)); | |
96 | data->n++; | |
97 | if (data->active > 0) { | |
98 | data->active--; | |
99 | } | |
100 | if (data->auto_set && data->active) { | |
101 | event_notifier_set(e); | |
102 | } | |
103 | } | |
104 | ||
105 | /* Tests using aio_*. */ | |
106 | ||
107 | static void test_notify(void) | |
108 | { | |
109 | g_assert(!aio_poll(ctx, false)); | |
110 | aio_notify(ctx); | |
111 | g_assert(!aio_poll(ctx, true)); | |
112 | g_assert(!aio_poll(ctx, false)); | |
113 | } | |
114 | ||
b2ea25d7 PB |
115 | static void test_bh_schedule(void) |
116 | { | |
117 | BHTestData data = { .n = 0 }; | |
118 | data.bh = aio_bh_new(ctx, bh_test_cb, &data); | |
119 | ||
120 | qemu_bh_schedule(data.bh); | |
121 | g_assert_cmpint(data.n, ==, 0); | |
122 | ||
123 | g_assert(aio_poll(ctx, true)); | |
124 | g_assert_cmpint(data.n, ==, 1); | |
125 | ||
126 | g_assert(!aio_poll(ctx, false)); | |
127 | g_assert_cmpint(data.n, ==, 1); | |
128 | qemu_bh_delete(data.bh); | |
129 | } | |
130 | ||
131 | static void test_bh_schedule10(void) | |
132 | { | |
133 | BHTestData data = { .n = 0, .max = 10 }; | |
134 | data.bh = aio_bh_new(ctx, bh_test_cb, &data); | |
135 | ||
136 | qemu_bh_schedule(data.bh); | |
137 | g_assert_cmpint(data.n, ==, 0); | |
138 | ||
139 | g_assert(aio_poll(ctx, false)); | |
140 | g_assert_cmpint(data.n, ==, 1); | |
141 | ||
142 | g_assert(aio_poll(ctx, true)); | |
143 | g_assert_cmpint(data.n, ==, 2); | |
144 | ||
9fe3781f | 145 | wait_for_aio(); |
b2ea25d7 PB |
146 | g_assert_cmpint(data.n, ==, 10); |
147 | ||
148 | g_assert(!aio_poll(ctx, false)); | |
149 | g_assert_cmpint(data.n, ==, 10); | |
150 | qemu_bh_delete(data.bh); | |
151 | } | |
152 | ||
153 | static void test_bh_cancel(void) | |
154 | { | |
155 | BHTestData data = { .n = 0 }; | |
156 | data.bh = aio_bh_new(ctx, bh_test_cb, &data); | |
157 | ||
158 | qemu_bh_schedule(data.bh); | |
159 | g_assert_cmpint(data.n, ==, 0); | |
160 | ||
161 | qemu_bh_cancel(data.bh); | |
162 | g_assert_cmpint(data.n, ==, 0); | |
163 | ||
164 | g_assert(!aio_poll(ctx, false)); | |
165 | g_assert_cmpint(data.n, ==, 0); | |
166 | qemu_bh_delete(data.bh); | |
167 | } | |
168 | ||
169 | static void test_bh_delete(void) | |
170 | { | |
171 | BHTestData data = { .n = 0 }; | |
172 | data.bh = aio_bh_new(ctx, bh_test_cb, &data); | |
173 | ||
174 | qemu_bh_schedule(data.bh); | |
175 | g_assert_cmpint(data.n, ==, 0); | |
176 | ||
177 | qemu_bh_delete(data.bh); | |
178 | g_assert_cmpint(data.n, ==, 0); | |
179 | ||
180 | g_assert(!aio_poll(ctx, false)); | |
181 | g_assert_cmpint(data.n, ==, 0); | |
182 | } | |
183 | ||
184 | static void test_bh_delete_from_cb(void) | |
185 | { | |
186 | BHTestData data1 = { .n = 0, .max = 1 }; | |
187 | ||
188 | data1.bh = aio_bh_new(ctx, bh_delete_cb, &data1); | |
189 | ||
190 | qemu_bh_schedule(data1.bh); | |
191 | g_assert_cmpint(data1.n, ==, 0); | |
192 | ||
9fe3781f | 193 | wait_for_aio(); |
b2ea25d7 PB |
194 | g_assert_cmpint(data1.n, ==, data1.max); |
195 | g_assert(data1.bh == NULL); | |
196 | ||
197 | g_assert(!aio_poll(ctx, false)); | |
198 | g_assert(!aio_poll(ctx, true)); | |
199 | } | |
200 | ||
201 | static void test_bh_delete_from_cb_many(void) | |
202 | { | |
203 | BHTestData data1 = { .n = 0, .max = 1 }; | |
204 | BHTestData data2 = { .n = 0, .max = 3 }; | |
205 | BHTestData data3 = { .n = 0, .max = 2 }; | |
206 | BHTestData data4 = { .n = 0, .max = 4 }; | |
207 | ||
208 | data1.bh = aio_bh_new(ctx, bh_delete_cb, &data1); | |
209 | data2.bh = aio_bh_new(ctx, bh_delete_cb, &data2); | |
210 | data3.bh = aio_bh_new(ctx, bh_delete_cb, &data3); | |
211 | data4.bh = aio_bh_new(ctx, bh_delete_cb, &data4); | |
212 | ||
213 | qemu_bh_schedule(data1.bh); | |
214 | qemu_bh_schedule(data2.bh); | |
215 | qemu_bh_schedule(data3.bh); | |
216 | qemu_bh_schedule(data4.bh); | |
217 | g_assert_cmpint(data1.n, ==, 0); | |
218 | g_assert_cmpint(data2.n, ==, 0); | |
219 | g_assert_cmpint(data3.n, ==, 0); | |
220 | g_assert_cmpint(data4.n, ==, 0); | |
221 | ||
222 | g_assert(aio_poll(ctx, false)); | |
223 | g_assert_cmpint(data1.n, ==, 1); | |
224 | g_assert_cmpint(data2.n, ==, 1); | |
225 | g_assert_cmpint(data3.n, ==, 1); | |
226 | g_assert_cmpint(data4.n, ==, 1); | |
227 | g_assert(data1.bh == NULL); | |
228 | ||
9fe3781f | 229 | wait_for_aio(); |
b2ea25d7 PB |
230 | g_assert_cmpint(data1.n, ==, data1.max); |
231 | g_assert_cmpint(data2.n, ==, data2.max); | |
232 | g_assert_cmpint(data3.n, ==, data3.max); | |
233 | g_assert_cmpint(data4.n, ==, data4.max); | |
234 | g_assert(data1.bh == NULL); | |
235 | g_assert(data2.bh == NULL); | |
236 | g_assert(data3.bh == NULL); | |
237 | g_assert(data4.bh == NULL); | |
238 | } | |
239 | ||
240 | static void test_bh_flush(void) | |
241 | { | |
242 | BHTestData data = { .n = 0 }; | |
243 | data.bh = aio_bh_new(ctx, bh_test_cb, &data); | |
244 | ||
245 | qemu_bh_schedule(data.bh); | |
246 | g_assert_cmpint(data.n, ==, 0); | |
247 | ||
9fe3781f | 248 | wait_for_aio(); |
b2ea25d7 PB |
249 | g_assert_cmpint(data.n, ==, 1); |
250 | ||
251 | g_assert(!aio_poll(ctx, false)); | |
252 | g_assert_cmpint(data.n, ==, 1); | |
253 | qemu_bh_delete(data.bh); | |
254 | } | |
255 | ||
256 | static void test_set_event_notifier(void) | |
257 | { | |
258 | EventNotifierTestData data = { .n = 0, .active = 0 }; | |
259 | event_notifier_init(&data.e, false); | |
f2e5dca4 | 260 | aio_set_event_notifier(ctx, &data.e, event_ready_cb); |
b2ea25d7 PB |
261 | g_assert(!aio_poll(ctx, false)); |
262 | g_assert_cmpint(data.n, ==, 0); | |
263 | ||
f2e5dca4 | 264 | aio_set_event_notifier(ctx, &data.e, NULL); |
b2ea25d7 PB |
265 | g_assert(!aio_poll(ctx, false)); |
266 | g_assert_cmpint(data.n, ==, 0); | |
267 | event_notifier_cleanup(&data.e); | |
268 | } | |
269 | ||
270 | static void test_wait_event_notifier(void) | |
271 | { | |
272 | EventNotifierTestData data = { .n = 0, .active = 1 }; | |
273 | event_notifier_init(&data.e, false); | |
f2e5dca4 | 274 | aio_set_event_notifier(ctx, &data.e, event_ready_cb); |
164a101f | 275 | g_assert(!aio_poll(ctx, false)); |
b2ea25d7 PB |
276 | g_assert_cmpint(data.n, ==, 0); |
277 | g_assert_cmpint(data.active, ==, 1); | |
278 | ||
279 | event_notifier_set(&data.e); | |
280 | g_assert(aio_poll(ctx, false)); | |
281 | g_assert_cmpint(data.n, ==, 1); | |
282 | g_assert_cmpint(data.active, ==, 0); | |
283 | ||
284 | g_assert(!aio_poll(ctx, false)); | |
285 | g_assert_cmpint(data.n, ==, 1); | |
286 | g_assert_cmpint(data.active, ==, 0); | |
287 | ||
f2e5dca4 | 288 | aio_set_event_notifier(ctx, &data.e, NULL); |
b2ea25d7 PB |
289 | g_assert(!aio_poll(ctx, false)); |
290 | g_assert_cmpint(data.n, ==, 1); | |
291 | ||
292 | event_notifier_cleanup(&data.e); | |
293 | } | |
294 | ||
295 | static void test_flush_event_notifier(void) | |
296 | { | |
297 | EventNotifierTestData data = { .n = 0, .active = 10, .auto_set = true }; | |
298 | event_notifier_init(&data.e, false); | |
f2e5dca4 | 299 | aio_set_event_notifier(ctx, &data.e, event_ready_cb); |
164a101f | 300 | g_assert(!aio_poll(ctx, false)); |
b2ea25d7 PB |
301 | g_assert_cmpint(data.n, ==, 0); |
302 | g_assert_cmpint(data.active, ==, 10); | |
303 | ||
304 | event_notifier_set(&data.e); | |
305 | g_assert(aio_poll(ctx, false)); | |
306 | g_assert_cmpint(data.n, ==, 1); | |
307 | g_assert_cmpint(data.active, ==, 9); | |
308 | g_assert(aio_poll(ctx, false)); | |
309 | ||
24d1a6d9 | 310 | wait_until_inactive(&data); |
b2ea25d7 PB |
311 | g_assert_cmpint(data.n, ==, 10); |
312 | g_assert_cmpint(data.active, ==, 0); | |
313 | g_assert(!aio_poll(ctx, false)); | |
314 | ||
f2e5dca4 | 315 | aio_set_event_notifier(ctx, &data.e, NULL); |
b2ea25d7 PB |
316 | g_assert(!aio_poll(ctx, false)); |
317 | event_notifier_cleanup(&data.e); | |
318 | } | |
319 | ||
320 | static void test_wait_event_notifier_noflush(void) | |
321 | { | |
322 | EventNotifierTestData data = { .n = 0 }; | |
323 | EventNotifierTestData dummy = { .n = 0, .active = 1 }; | |
324 | ||
325 | event_notifier_init(&data.e, false); | |
f2e5dca4 | 326 | aio_set_event_notifier(ctx, &data.e, event_ready_cb); |
b2ea25d7 PB |
327 | |
328 | g_assert(!aio_poll(ctx, false)); | |
329 | g_assert_cmpint(data.n, ==, 0); | |
330 | ||
331 | /* Until there is an active descriptor, aio_poll may or may not call | |
332 | * event_ready_cb. Still, it must not block. */ | |
333 | event_notifier_set(&data.e); | |
164a101f | 334 | g_assert(aio_poll(ctx, true)); |
b2ea25d7 PB |
335 | data.n = 0; |
336 | ||
337 | /* An active event notifier forces aio_poll to look at EventNotifiers. */ | |
338 | event_notifier_init(&dummy.e, false); | |
f2e5dca4 | 339 | aio_set_event_notifier(ctx, &dummy.e, event_ready_cb); |
b2ea25d7 PB |
340 | |
341 | event_notifier_set(&data.e); | |
342 | g_assert(aio_poll(ctx, false)); | |
343 | g_assert_cmpint(data.n, ==, 1); | |
164a101f | 344 | g_assert(!aio_poll(ctx, false)); |
b2ea25d7 PB |
345 | g_assert_cmpint(data.n, ==, 1); |
346 | ||
347 | event_notifier_set(&data.e); | |
348 | g_assert(aio_poll(ctx, false)); | |
349 | g_assert_cmpint(data.n, ==, 2); | |
164a101f | 350 | g_assert(!aio_poll(ctx, false)); |
b2ea25d7 PB |
351 | g_assert_cmpint(data.n, ==, 2); |
352 | ||
353 | event_notifier_set(&dummy.e); | |
24d1a6d9 | 354 | wait_until_inactive(&dummy); |
b2ea25d7 PB |
355 | g_assert_cmpint(data.n, ==, 2); |
356 | g_assert_cmpint(dummy.n, ==, 1); | |
357 | g_assert_cmpint(dummy.active, ==, 0); | |
358 | ||
f2e5dca4 | 359 | aio_set_event_notifier(ctx, &dummy.e, NULL); |
b2ea25d7 PB |
360 | event_notifier_cleanup(&dummy.e); |
361 | ||
f2e5dca4 | 362 | aio_set_event_notifier(ctx, &data.e, NULL); |
b2ea25d7 PB |
363 | g_assert(!aio_poll(ctx, false)); |
364 | g_assert_cmpint(data.n, ==, 2); | |
365 | ||
366 | event_notifier_cleanup(&data.e); | |
367 | } | |
368 | ||
b53edf97 AB |
369 | static void test_timer_schedule(void) |
370 | { | |
371 | TimerTestData data = { .n = 0, .ctx = ctx, .ns = SCALE_MS * 750LL, | |
372 | .max = 2, | |
373 | .clock_type = QEMU_CLOCK_VIRTUAL }; | |
374 | int pipefd[2]; | |
375 | ||
376 | /* aio_poll will not block to wait for timers to complete unless it has | |
377 | * an fd to wait on. Fixing this breaks other tests. So create a dummy one. | |
378 | */ | |
a94a3fac AB |
379 | g_assert(!qemu_pipe(pipefd)); |
380 | qemu_set_nonblock(pipefd[0]); | |
381 | qemu_set_nonblock(pipefd[1]); | |
382 | ||
b53edf97 | 383 | aio_set_fd_handler(ctx, pipefd[0], |
91c68f14 | 384 | dummy_io_handler_read, NULL, NULL); |
b53edf97 AB |
385 | aio_poll(ctx, false); |
386 | ||
387 | aio_timer_init(ctx, &data.timer, data.clock_type, | |
388 | SCALE_NS, timer_test_cb, &data); | |
389 | timer_mod(&data.timer, | |
390 | qemu_clock_get_ns(data.clock_type) + | |
391 | data.ns); | |
392 | ||
393 | g_assert_cmpint(data.n, ==, 0); | |
394 | ||
395 | /* timer_mod may well cause an event notifer to have gone off, | |
396 | * so clear that | |
397 | */ | |
398 | do {} while (aio_poll(ctx, false)); | |
399 | ||
400 | g_assert(!aio_poll(ctx, false)); | |
401 | g_assert_cmpint(data.n, ==, 0); | |
402 | ||
fcdda211 | 403 | g_usleep(1 * G_USEC_PER_SEC); |
b53edf97 AB |
404 | g_assert_cmpint(data.n, ==, 0); |
405 | ||
406 | g_assert(aio_poll(ctx, false)); | |
407 | g_assert_cmpint(data.n, ==, 1); | |
408 | ||
409 | /* timer_mod called by our callback */ | |
410 | do {} while (aio_poll(ctx, false)); | |
411 | ||
412 | g_assert(!aio_poll(ctx, false)); | |
413 | g_assert_cmpint(data.n, ==, 1); | |
414 | ||
415 | g_assert(aio_poll(ctx, true)); | |
416 | g_assert_cmpint(data.n, ==, 2); | |
417 | ||
418 | /* As max is now 2, an event notifier should not have gone off */ | |
419 | ||
420 | g_assert(!aio_poll(ctx, false)); | |
421 | g_assert_cmpint(data.n, ==, 2); | |
422 | ||
423 | aio_set_fd_handler(ctx, pipefd[0], NULL, NULL, NULL); | |
424 | close(pipefd[0]); | |
425 | close(pipefd[1]); | |
426 | ||
427 | timer_del(&data.timer); | |
428 | } | |
429 | ||
b2ea25d7 PB |
430 | /* Now the same tests, using the context as a GSource. They are |
431 | * very similar to the ones above, with g_main_context_iteration | |
432 | * replacing aio_poll. However: | |
433 | * - sometimes both the AioContext and the glib main loop wake | |
434 | * themselves up. Hence, some "g_assert(!aio_poll(ctx, false));" | |
435 | * are replaced by "while (g_main_context_iteration(NULL, false));". | |
9fe3781f | 436 | * - there is no exact replacement for a blocking wait. |
b2ea25d7 PB |
437 | * "while (g_main_context_iteration(NULL, true)" seems to work, |
438 | * but it is not documented _why_ it works. For these tests a | |
439 | * non-blocking loop like "while (g_main_context_iteration(NULL, false)" | |
440 | * works well, and that's what I am using. | |
441 | */ | |
442 | ||
443 | static void test_source_notify(void) | |
444 | { | |
445 | while (g_main_context_iteration(NULL, false)); | |
446 | aio_notify(ctx); | |
447 | g_assert(g_main_context_iteration(NULL, true)); | |
448 | g_assert(!g_main_context_iteration(NULL, false)); | |
449 | } | |
450 | ||
451 | static void test_source_flush(void) | |
452 | { | |
453 | g_assert(!g_main_context_iteration(NULL, false)); | |
454 | aio_notify(ctx); | |
455 | while (g_main_context_iteration(NULL, false)); | |
456 | g_assert(!g_main_context_iteration(NULL, false)); | |
457 | } | |
458 | ||
459 | static void test_source_bh_schedule(void) | |
460 | { | |
461 | BHTestData data = { .n = 0 }; | |
462 | data.bh = aio_bh_new(ctx, bh_test_cb, &data); | |
463 | ||
464 | qemu_bh_schedule(data.bh); | |
465 | g_assert_cmpint(data.n, ==, 0); | |
466 | ||
467 | g_assert(g_main_context_iteration(NULL, true)); | |
468 | g_assert_cmpint(data.n, ==, 1); | |
469 | ||
470 | g_assert(!g_main_context_iteration(NULL, false)); | |
471 | g_assert_cmpint(data.n, ==, 1); | |
472 | qemu_bh_delete(data.bh); | |
473 | } | |
474 | ||
475 | static void test_source_bh_schedule10(void) | |
476 | { | |
477 | BHTestData data = { .n = 0, .max = 10 }; | |
478 | data.bh = aio_bh_new(ctx, bh_test_cb, &data); | |
479 | ||
480 | qemu_bh_schedule(data.bh); | |
481 | g_assert_cmpint(data.n, ==, 0); | |
482 | ||
483 | g_assert(g_main_context_iteration(NULL, false)); | |
484 | g_assert_cmpint(data.n, ==, 1); | |
485 | ||
486 | g_assert(g_main_context_iteration(NULL, true)); | |
487 | g_assert_cmpint(data.n, ==, 2); | |
488 | ||
489 | while (g_main_context_iteration(NULL, false)); | |
490 | g_assert_cmpint(data.n, ==, 10); | |
491 | ||
492 | g_assert(!g_main_context_iteration(NULL, false)); | |
493 | g_assert_cmpint(data.n, ==, 10); | |
494 | qemu_bh_delete(data.bh); | |
495 | } | |
496 | ||
497 | static void test_source_bh_cancel(void) | |
498 | { | |
499 | BHTestData data = { .n = 0 }; | |
500 | data.bh = aio_bh_new(ctx, bh_test_cb, &data); | |
501 | ||
502 | qemu_bh_schedule(data.bh); | |
503 | g_assert_cmpint(data.n, ==, 0); | |
504 | ||
505 | qemu_bh_cancel(data.bh); | |
506 | g_assert_cmpint(data.n, ==, 0); | |
507 | ||
508 | while (g_main_context_iteration(NULL, false)); | |
509 | g_assert_cmpint(data.n, ==, 0); | |
510 | qemu_bh_delete(data.bh); | |
511 | } | |
512 | ||
513 | static void test_source_bh_delete(void) | |
514 | { | |
515 | BHTestData data = { .n = 0 }; | |
516 | data.bh = aio_bh_new(ctx, bh_test_cb, &data); | |
517 | ||
518 | qemu_bh_schedule(data.bh); | |
519 | g_assert_cmpint(data.n, ==, 0); | |
520 | ||
521 | qemu_bh_delete(data.bh); | |
522 | g_assert_cmpint(data.n, ==, 0); | |
523 | ||
524 | while (g_main_context_iteration(NULL, false)); | |
525 | g_assert_cmpint(data.n, ==, 0); | |
526 | } | |
527 | ||
528 | static void test_source_bh_delete_from_cb(void) | |
529 | { | |
530 | BHTestData data1 = { .n = 0, .max = 1 }; | |
531 | ||
532 | data1.bh = aio_bh_new(ctx, bh_delete_cb, &data1); | |
533 | ||
534 | qemu_bh_schedule(data1.bh); | |
535 | g_assert_cmpint(data1.n, ==, 0); | |
536 | ||
537 | g_main_context_iteration(NULL, true); | |
538 | g_assert_cmpint(data1.n, ==, data1.max); | |
539 | g_assert(data1.bh == NULL); | |
540 | ||
541 | g_assert(!g_main_context_iteration(NULL, false)); | |
542 | } | |
543 | ||
544 | static void test_source_bh_delete_from_cb_many(void) | |
545 | { | |
546 | BHTestData data1 = { .n = 0, .max = 1 }; | |
547 | BHTestData data2 = { .n = 0, .max = 3 }; | |
548 | BHTestData data3 = { .n = 0, .max = 2 }; | |
549 | BHTestData data4 = { .n = 0, .max = 4 }; | |
550 | ||
551 | data1.bh = aio_bh_new(ctx, bh_delete_cb, &data1); | |
552 | data2.bh = aio_bh_new(ctx, bh_delete_cb, &data2); | |
553 | data3.bh = aio_bh_new(ctx, bh_delete_cb, &data3); | |
554 | data4.bh = aio_bh_new(ctx, bh_delete_cb, &data4); | |
555 | ||
556 | qemu_bh_schedule(data1.bh); | |
557 | qemu_bh_schedule(data2.bh); | |
558 | qemu_bh_schedule(data3.bh); | |
559 | qemu_bh_schedule(data4.bh); | |
560 | g_assert_cmpint(data1.n, ==, 0); | |
561 | g_assert_cmpint(data2.n, ==, 0); | |
562 | g_assert_cmpint(data3.n, ==, 0); | |
563 | g_assert_cmpint(data4.n, ==, 0); | |
564 | ||
565 | g_assert(g_main_context_iteration(NULL, false)); | |
566 | g_assert_cmpint(data1.n, ==, 1); | |
567 | g_assert_cmpint(data2.n, ==, 1); | |
568 | g_assert_cmpint(data3.n, ==, 1); | |
569 | g_assert_cmpint(data4.n, ==, 1); | |
570 | g_assert(data1.bh == NULL); | |
571 | ||
572 | while (g_main_context_iteration(NULL, false)); | |
573 | g_assert_cmpint(data1.n, ==, data1.max); | |
574 | g_assert_cmpint(data2.n, ==, data2.max); | |
575 | g_assert_cmpint(data3.n, ==, data3.max); | |
576 | g_assert_cmpint(data4.n, ==, data4.max); | |
577 | g_assert(data1.bh == NULL); | |
578 | g_assert(data2.bh == NULL); | |
579 | g_assert(data3.bh == NULL); | |
580 | g_assert(data4.bh == NULL); | |
581 | } | |
582 | ||
583 | static void test_source_bh_flush(void) | |
584 | { | |
585 | BHTestData data = { .n = 0 }; | |
586 | data.bh = aio_bh_new(ctx, bh_test_cb, &data); | |
587 | ||
588 | qemu_bh_schedule(data.bh); | |
589 | g_assert_cmpint(data.n, ==, 0); | |
590 | ||
591 | g_assert(g_main_context_iteration(NULL, true)); | |
592 | g_assert_cmpint(data.n, ==, 1); | |
593 | ||
594 | g_assert(!g_main_context_iteration(NULL, false)); | |
595 | g_assert_cmpint(data.n, ==, 1); | |
596 | qemu_bh_delete(data.bh); | |
597 | } | |
598 | ||
599 | static void test_source_set_event_notifier(void) | |
600 | { | |
601 | EventNotifierTestData data = { .n = 0, .active = 0 }; | |
602 | event_notifier_init(&data.e, false); | |
f2e5dca4 | 603 | aio_set_event_notifier(ctx, &data.e, event_ready_cb); |
b2ea25d7 PB |
604 | while (g_main_context_iteration(NULL, false)); |
605 | g_assert_cmpint(data.n, ==, 0); | |
606 | ||
f2e5dca4 | 607 | aio_set_event_notifier(ctx, &data.e, NULL); |
b2ea25d7 PB |
608 | while (g_main_context_iteration(NULL, false)); |
609 | g_assert_cmpint(data.n, ==, 0); | |
610 | event_notifier_cleanup(&data.e); | |
611 | } | |
612 | ||
613 | static void test_source_wait_event_notifier(void) | |
614 | { | |
615 | EventNotifierTestData data = { .n = 0, .active = 1 }; | |
616 | event_notifier_init(&data.e, false); | |
f2e5dca4 | 617 | aio_set_event_notifier(ctx, &data.e, event_ready_cb); |
b2ea25d7 PB |
618 | g_assert(g_main_context_iteration(NULL, false)); |
619 | g_assert_cmpint(data.n, ==, 0); | |
620 | g_assert_cmpint(data.active, ==, 1); | |
621 | ||
622 | event_notifier_set(&data.e); | |
623 | g_assert(g_main_context_iteration(NULL, false)); | |
624 | g_assert_cmpint(data.n, ==, 1); | |
625 | g_assert_cmpint(data.active, ==, 0); | |
626 | ||
627 | while (g_main_context_iteration(NULL, false)); | |
628 | g_assert_cmpint(data.n, ==, 1); | |
629 | g_assert_cmpint(data.active, ==, 0); | |
630 | ||
f2e5dca4 | 631 | aio_set_event_notifier(ctx, &data.e, NULL); |
b2ea25d7 PB |
632 | while (g_main_context_iteration(NULL, false)); |
633 | g_assert_cmpint(data.n, ==, 1); | |
634 | ||
635 | event_notifier_cleanup(&data.e); | |
636 | } | |
637 | ||
638 | static void test_source_flush_event_notifier(void) | |
639 | { | |
640 | EventNotifierTestData data = { .n = 0, .active = 10, .auto_set = true }; | |
641 | event_notifier_init(&data.e, false); | |
f2e5dca4 | 642 | aio_set_event_notifier(ctx, &data.e, event_ready_cb); |
b2ea25d7 PB |
643 | g_assert(g_main_context_iteration(NULL, false)); |
644 | g_assert_cmpint(data.n, ==, 0); | |
645 | g_assert_cmpint(data.active, ==, 10); | |
646 | ||
647 | event_notifier_set(&data.e); | |
648 | g_assert(g_main_context_iteration(NULL, false)); | |
649 | g_assert_cmpint(data.n, ==, 1); | |
650 | g_assert_cmpint(data.active, ==, 9); | |
651 | g_assert(g_main_context_iteration(NULL, false)); | |
652 | ||
653 | while (g_main_context_iteration(NULL, false)); | |
654 | g_assert_cmpint(data.n, ==, 10); | |
655 | g_assert_cmpint(data.active, ==, 0); | |
656 | g_assert(!g_main_context_iteration(NULL, false)); | |
657 | ||
f2e5dca4 | 658 | aio_set_event_notifier(ctx, &data.e, NULL); |
b2ea25d7 PB |
659 | while (g_main_context_iteration(NULL, false)); |
660 | event_notifier_cleanup(&data.e); | |
661 | } | |
662 | ||
663 | static void test_source_wait_event_notifier_noflush(void) | |
664 | { | |
665 | EventNotifierTestData data = { .n = 0 }; | |
666 | EventNotifierTestData dummy = { .n = 0, .active = 1 }; | |
667 | ||
668 | event_notifier_init(&data.e, false); | |
f2e5dca4 | 669 | aio_set_event_notifier(ctx, &data.e, event_ready_cb); |
b2ea25d7 PB |
670 | |
671 | while (g_main_context_iteration(NULL, false)); | |
672 | g_assert_cmpint(data.n, ==, 0); | |
673 | ||
674 | /* Until there is an active descriptor, glib may or may not call | |
675 | * event_ready_cb. Still, it must not block. */ | |
676 | event_notifier_set(&data.e); | |
677 | g_main_context_iteration(NULL, true); | |
678 | data.n = 0; | |
679 | ||
680 | /* An active event notifier forces aio_poll to look at EventNotifiers. */ | |
681 | event_notifier_init(&dummy.e, false); | |
f2e5dca4 | 682 | aio_set_event_notifier(ctx, &dummy.e, event_ready_cb); |
b2ea25d7 PB |
683 | |
684 | event_notifier_set(&data.e); | |
685 | g_assert(g_main_context_iteration(NULL, false)); | |
686 | g_assert_cmpint(data.n, ==, 1); | |
687 | g_assert(!g_main_context_iteration(NULL, false)); | |
688 | g_assert_cmpint(data.n, ==, 1); | |
689 | ||
690 | event_notifier_set(&data.e); | |
691 | g_assert(g_main_context_iteration(NULL, false)); | |
692 | g_assert_cmpint(data.n, ==, 2); | |
693 | g_assert(!g_main_context_iteration(NULL, false)); | |
694 | g_assert_cmpint(data.n, ==, 2); | |
695 | ||
696 | event_notifier_set(&dummy.e); | |
697 | while (g_main_context_iteration(NULL, false)); | |
698 | g_assert_cmpint(data.n, ==, 2); | |
699 | g_assert_cmpint(dummy.n, ==, 1); | |
700 | g_assert_cmpint(dummy.active, ==, 0); | |
701 | ||
f2e5dca4 | 702 | aio_set_event_notifier(ctx, &dummy.e, NULL); |
b2ea25d7 PB |
703 | event_notifier_cleanup(&dummy.e); |
704 | ||
f2e5dca4 | 705 | aio_set_event_notifier(ctx, &data.e, NULL); |
b2ea25d7 PB |
706 | while (g_main_context_iteration(NULL, false)); |
707 | g_assert_cmpint(data.n, ==, 2); | |
708 | ||
709 | event_notifier_cleanup(&data.e); | |
710 | } | |
711 | ||
b53edf97 AB |
712 | static void test_source_timer_schedule(void) |
713 | { | |
714 | TimerTestData data = { .n = 0, .ctx = ctx, .ns = SCALE_MS * 750LL, | |
715 | .max = 2, | |
716 | .clock_type = QEMU_CLOCK_VIRTUAL }; | |
717 | int pipefd[2]; | |
718 | int64_t expiry; | |
719 | ||
720 | /* aio_poll will not block to wait for timers to complete unless it has | |
721 | * an fd to wait on. Fixing this breaks other tests. So create a dummy one. | |
722 | */ | |
a94a3fac AB |
723 | g_assert(!qemu_pipe(pipefd)); |
724 | qemu_set_nonblock(pipefd[0]); | |
725 | qemu_set_nonblock(pipefd[1]); | |
726 | ||
b53edf97 | 727 | aio_set_fd_handler(ctx, pipefd[0], |
91c68f14 | 728 | dummy_io_handler_read, NULL, NULL); |
b53edf97 AB |
729 | do {} while (g_main_context_iteration(NULL, false)); |
730 | ||
731 | aio_timer_init(ctx, &data.timer, data.clock_type, | |
732 | SCALE_NS, timer_test_cb, &data); | |
733 | expiry = qemu_clock_get_ns(data.clock_type) + | |
734 | data.ns; | |
735 | timer_mod(&data.timer, expiry); | |
736 | ||
737 | g_assert_cmpint(data.n, ==, 0); | |
738 | ||
fcdda211 | 739 | g_usleep(1 * G_USEC_PER_SEC); |
b53edf97 AB |
740 | g_assert_cmpint(data.n, ==, 0); |
741 | ||
742 | g_assert(g_main_context_iteration(NULL, false)); | |
743 | g_assert_cmpint(data.n, ==, 1); | |
744 | ||
745 | /* The comment above was not kidding when it said this wakes up itself */ | |
746 | do { | |
747 | g_assert(g_main_context_iteration(NULL, true)); | |
748 | } while (qemu_clock_get_ns(data.clock_type) <= expiry); | |
fcdda211 | 749 | g_usleep(1 * G_USEC_PER_SEC); |
b53edf97 AB |
750 | g_main_context_iteration(NULL, false); |
751 | ||
752 | g_assert_cmpint(data.n, ==, 2); | |
753 | ||
754 | aio_set_fd_handler(ctx, pipefd[0], NULL, NULL, NULL); | |
755 | close(pipefd[0]); | |
756 | close(pipefd[1]); | |
757 | ||
758 | timer_del(&data.timer); | |
759 | } | |
760 | ||
761 | ||
b2ea25d7 PB |
762 | /* End of tests. */ |
763 | ||
764 | int main(int argc, char **argv) | |
765 | { | |
766 | GSource *src; | |
767 | ||
dae21b98 AB |
768 | init_clocks(); |
769 | ||
b2ea25d7 PB |
770 | ctx = aio_context_new(); |
771 | src = aio_get_g_source(ctx); | |
772 | g_source_attach(src, NULL); | |
773 | g_source_unref(src); | |
774 | ||
775 | while (g_main_context_iteration(NULL, false)); | |
776 | ||
777 | g_test_init(&argc, &argv, NULL); | |
778 | g_test_add_func("/aio/notify", test_notify); | |
b2ea25d7 PB |
779 | g_test_add_func("/aio/bh/schedule", test_bh_schedule); |
780 | g_test_add_func("/aio/bh/schedule10", test_bh_schedule10); | |
781 | g_test_add_func("/aio/bh/cancel", test_bh_cancel); | |
782 | g_test_add_func("/aio/bh/delete", test_bh_delete); | |
783 | g_test_add_func("/aio/bh/callback-delete/one", test_bh_delete_from_cb); | |
784 | g_test_add_func("/aio/bh/callback-delete/many", test_bh_delete_from_cb_many); | |
785 | g_test_add_func("/aio/bh/flush", test_bh_flush); | |
786 | g_test_add_func("/aio/event/add-remove", test_set_event_notifier); | |
787 | g_test_add_func("/aio/event/wait", test_wait_event_notifier); | |
788 | g_test_add_func("/aio/event/wait/no-flush-cb", test_wait_event_notifier_noflush); | |
789 | g_test_add_func("/aio/event/flush", test_flush_event_notifier); | |
b53edf97 | 790 | g_test_add_func("/aio/timer/schedule", test_timer_schedule); |
b2ea25d7 PB |
791 | |
792 | g_test_add_func("/aio-gsource/notify", test_source_notify); | |
793 | g_test_add_func("/aio-gsource/flush", test_source_flush); | |
794 | g_test_add_func("/aio-gsource/bh/schedule", test_source_bh_schedule); | |
795 | g_test_add_func("/aio-gsource/bh/schedule10", test_source_bh_schedule10); | |
796 | g_test_add_func("/aio-gsource/bh/cancel", test_source_bh_cancel); | |
797 | g_test_add_func("/aio-gsource/bh/delete", test_source_bh_delete); | |
798 | g_test_add_func("/aio-gsource/bh/callback-delete/one", test_source_bh_delete_from_cb); | |
799 | g_test_add_func("/aio-gsource/bh/callback-delete/many", test_source_bh_delete_from_cb_many); | |
800 | g_test_add_func("/aio-gsource/bh/flush", test_source_bh_flush); | |
801 | g_test_add_func("/aio-gsource/event/add-remove", test_source_set_event_notifier); | |
802 | g_test_add_func("/aio-gsource/event/wait", test_source_wait_event_notifier); | |
803 | g_test_add_func("/aio-gsource/event/wait/no-flush-cb", test_source_wait_event_notifier_noflush); | |
804 | g_test_add_func("/aio-gsource/event/flush", test_source_flush_event_notifier); | |
b53edf97 | 805 | g_test_add_func("/aio-gsource/timer/schedule", test_source_timer_schedule); |
b2ea25d7 PB |
806 | return g_test_run(); |
807 | } |