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