xref: /openbmc/qemu/tests/unit/test-aio.c (revision 0c2c2932)
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 
103da668aa1SThomas Huth typedef struct {
104da668aa1SThomas Huth     QemuMutex start_lock;
105da668aa1SThomas Huth     EventNotifier notifier;
106da668aa1SThomas Huth     bool thread_acquired;
107da668aa1SThomas Huth } AcquireTestData;
108da668aa1SThomas Huth 
test_acquire_thread(void * opaque)109da668aa1SThomas Huth static void *test_acquire_thread(void *opaque)
110da668aa1SThomas Huth {
111da668aa1SThomas Huth     AcquireTestData *data = opaque;
112da668aa1SThomas Huth 
113da668aa1SThomas Huth     /* Wait for other thread to let us start */
114da668aa1SThomas Huth     qemu_mutex_lock(&data->start_lock);
115da668aa1SThomas Huth     qemu_mutex_unlock(&data->start_lock);
116da668aa1SThomas Huth 
117da668aa1SThomas Huth     /* event_notifier_set might be called either before or after
118da668aa1SThomas Huth      * the main thread's call to poll().  The test case's outcome
119da668aa1SThomas Huth      * should be the same in either case.
120da668aa1SThomas Huth      */
121da668aa1SThomas Huth     event_notifier_set(&data->notifier);
122da668aa1SThomas Huth     aio_context_acquire(ctx);
123da668aa1SThomas Huth     aio_context_release(ctx);
124da668aa1SThomas Huth 
125da668aa1SThomas Huth     data->thread_acquired = true; /* success, we got here */
126da668aa1SThomas Huth 
127da668aa1SThomas Huth     return NULL;
128da668aa1SThomas Huth }
129da668aa1SThomas Huth 
set_event_notifier(AioContext * nctx,EventNotifier * notifier,EventNotifierHandler * handler)130*0c2c2932SPhilippe Mathieu-Daudé static void set_event_notifier(AioContext *nctx, EventNotifier *notifier,
131da668aa1SThomas Huth                                EventNotifierHandler *handler)
132da668aa1SThomas Huth {
133*0c2c2932SPhilippe Mathieu-Daudé     aio_set_event_notifier(nctx, notifier, handler, NULL, NULL);
134da668aa1SThomas Huth }
135da668aa1SThomas Huth 
dummy_notifier_read(EventNotifier * n)136da668aa1SThomas Huth static void dummy_notifier_read(EventNotifier *n)
137da668aa1SThomas Huth {
138da668aa1SThomas Huth     event_notifier_test_and_clear(n);
139da668aa1SThomas Huth }
140da668aa1SThomas Huth 
test_acquire(void)141da668aa1SThomas Huth static void test_acquire(void)
142da668aa1SThomas Huth {
143da668aa1SThomas Huth     QemuThread thread;
144da668aa1SThomas Huth     AcquireTestData data;
145da668aa1SThomas Huth 
146da668aa1SThomas Huth     /* Dummy event notifier ensures aio_poll() will block */
147da668aa1SThomas Huth     event_notifier_init(&data.notifier, false);
148da668aa1SThomas Huth     set_event_notifier(ctx, &data.notifier, dummy_notifier_read);
149da668aa1SThomas Huth     g_assert(!aio_poll(ctx, false)); /* consume aio_notify() */
150da668aa1SThomas Huth 
151da668aa1SThomas Huth     qemu_mutex_init(&data.start_lock);
152da668aa1SThomas Huth     qemu_mutex_lock(&data.start_lock);
153da668aa1SThomas Huth     data.thread_acquired = false;
154da668aa1SThomas Huth 
155da668aa1SThomas Huth     qemu_thread_create(&thread, "test_acquire_thread",
156da668aa1SThomas Huth                        test_acquire_thread,
157da668aa1SThomas Huth                        &data, QEMU_THREAD_JOINABLE);
158da668aa1SThomas Huth 
159da668aa1SThomas Huth     /* Block in aio_poll(), let other thread kick us and acquire context */
160da668aa1SThomas Huth     aio_context_acquire(ctx);
161da668aa1SThomas Huth     qemu_mutex_unlock(&data.start_lock); /* let the thread run */
162da668aa1SThomas Huth     g_assert(aio_poll(ctx, true));
163da668aa1SThomas Huth     g_assert(!data.thread_acquired);
164da668aa1SThomas Huth     aio_context_release(ctx);
165da668aa1SThomas Huth 
166da668aa1SThomas Huth     qemu_thread_join(&thread);
167da668aa1SThomas Huth     set_event_notifier(ctx, &data.notifier, NULL);
168da668aa1SThomas Huth     event_notifier_cleanup(&data.notifier);
169da668aa1SThomas Huth 
170da668aa1SThomas Huth     g_assert(data.thread_acquired);
171da668aa1SThomas Huth }
172da668aa1SThomas Huth 
test_bh_schedule(void)173da668aa1SThomas Huth static void test_bh_schedule(void)
174da668aa1SThomas Huth {
175da668aa1SThomas Huth     BHTestData data = { .n = 0 };
176da668aa1SThomas Huth     data.bh = aio_bh_new(ctx, bh_test_cb, &data);
177da668aa1SThomas Huth 
178da668aa1SThomas Huth     qemu_bh_schedule(data.bh);
179da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 0);
180da668aa1SThomas Huth 
181da668aa1SThomas Huth     g_assert(aio_poll(ctx, true));
182da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 1);
183da668aa1SThomas Huth 
184da668aa1SThomas Huth     g_assert(!aio_poll(ctx, false));
185da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 1);
186da668aa1SThomas Huth     qemu_bh_delete(data.bh);
187da668aa1SThomas Huth }
188da668aa1SThomas Huth 
test_bh_schedule10(void)189da668aa1SThomas Huth static void test_bh_schedule10(void)
190da668aa1SThomas Huth {
191da668aa1SThomas Huth     BHTestData data = { .n = 0, .max = 10 };
192da668aa1SThomas Huth     data.bh = aio_bh_new(ctx, bh_test_cb, &data);
193da668aa1SThomas Huth 
194da668aa1SThomas Huth     qemu_bh_schedule(data.bh);
195da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 0);
196da668aa1SThomas Huth 
197da668aa1SThomas Huth     g_assert(aio_poll(ctx, false));
198da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 1);
199da668aa1SThomas Huth 
200da668aa1SThomas Huth     g_assert(aio_poll(ctx, true));
201da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 2);
202da668aa1SThomas Huth 
203da668aa1SThomas Huth     while (data.n < 10) {
204da668aa1SThomas Huth         aio_poll(ctx, true);
205da668aa1SThomas Huth     }
206da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 10);
207da668aa1SThomas Huth 
208da668aa1SThomas Huth     g_assert(!aio_poll(ctx, false));
209da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 10);
210da668aa1SThomas Huth     qemu_bh_delete(data.bh);
211da668aa1SThomas Huth }
212da668aa1SThomas Huth 
test_bh_cancel(void)213da668aa1SThomas Huth static void test_bh_cancel(void)
214da668aa1SThomas Huth {
215da668aa1SThomas Huth     BHTestData data = { .n = 0 };
216da668aa1SThomas Huth     data.bh = aio_bh_new(ctx, bh_test_cb, &data);
217da668aa1SThomas Huth 
218da668aa1SThomas Huth     qemu_bh_schedule(data.bh);
219da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 0);
220da668aa1SThomas Huth 
221da668aa1SThomas Huth     qemu_bh_cancel(data.bh);
222da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 0);
223da668aa1SThomas Huth 
224da668aa1SThomas Huth     g_assert(!aio_poll(ctx, false));
225da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 0);
226da668aa1SThomas Huth     qemu_bh_delete(data.bh);
227da668aa1SThomas Huth }
228da668aa1SThomas Huth 
test_bh_delete(void)229da668aa1SThomas Huth static void test_bh_delete(void)
230da668aa1SThomas Huth {
231da668aa1SThomas Huth     BHTestData data = { .n = 0 };
232da668aa1SThomas Huth     data.bh = aio_bh_new(ctx, bh_test_cb, &data);
233da668aa1SThomas Huth 
234da668aa1SThomas Huth     qemu_bh_schedule(data.bh);
235da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 0);
236da668aa1SThomas Huth 
237da668aa1SThomas Huth     qemu_bh_delete(data.bh);
238da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 0);
239da668aa1SThomas Huth 
240da668aa1SThomas Huth     g_assert(!aio_poll(ctx, false));
241da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 0);
242da668aa1SThomas Huth }
243da668aa1SThomas Huth 
test_bh_delete_from_cb(void)244da668aa1SThomas Huth static void test_bh_delete_from_cb(void)
245da668aa1SThomas Huth {
246da668aa1SThomas Huth     BHTestData data1 = { .n = 0, .max = 1 };
247da668aa1SThomas Huth 
248da668aa1SThomas Huth     data1.bh = aio_bh_new(ctx, bh_delete_cb, &data1);
249da668aa1SThomas Huth 
250da668aa1SThomas Huth     qemu_bh_schedule(data1.bh);
251da668aa1SThomas Huth     g_assert_cmpint(data1.n, ==, 0);
252da668aa1SThomas Huth 
253da668aa1SThomas Huth     while (data1.n < data1.max) {
254da668aa1SThomas Huth         aio_poll(ctx, true);
255da668aa1SThomas Huth     }
256da668aa1SThomas Huth     g_assert_cmpint(data1.n, ==, data1.max);
257da668aa1SThomas Huth     g_assert(data1.bh == NULL);
258da668aa1SThomas Huth 
259da668aa1SThomas Huth     g_assert(!aio_poll(ctx, false));
260da668aa1SThomas Huth }
261da668aa1SThomas Huth 
test_bh_delete_from_cb_many(void)262da668aa1SThomas Huth static void test_bh_delete_from_cb_many(void)
263da668aa1SThomas Huth {
264da668aa1SThomas Huth     BHTestData data1 = { .n = 0, .max = 1 };
265da668aa1SThomas Huth     BHTestData data2 = { .n = 0, .max = 3 };
266da668aa1SThomas Huth     BHTestData data3 = { .n = 0, .max = 2 };
267da668aa1SThomas Huth     BHTestData data4 = { .n = 0, .max = 4 };
268da668aa1SThomas Huth 
269da668aa1SThomas Huth     data1.bh = aio_bh_new(ctx, bh_delete_cb, &data1);
270da668aa1SThomas Huth     data2.bh = aio_bh_new(ctx, bh_delete_cb, &data2);
271da668aa1SThomas Huth     data3.bh = aio_bh_new(ctx, bh_delete_cb, &data3);
272da668aa1SThomas Huth     data4.bh = aio_bh_new(ctx, bh_delete_cb, &data4);
273da668aa1SThomas Huth 
274da668aa1SThomas Huth     qemu_bh_schedule(data1.bh);
275da668aa1SThomas Huth     qemu_bh_schedule(data2.bh);
276da668aa1SThomas Huth     qemu_bh_schedule(data3.bh);
277da668aa1SThomas Huth     qemu_bh_schedule(data4.bh);
278da668aa1SThomas Huth     g_assert_cmpint(data1.n, ==, 0);
279da668aa1SThomas Huth     g_assert_cmpint(data2.n, ==, 0);
280da668aa1SThomas Huth     g_assert_cmpint(data3.n, ==, 0);
281da668aa1SThomas Huth     g_assert_cmpint(data4.n, ==, 0);
282da668aa1SThomas Huth 
283da668aa1SThomas Huth     g_assert(aio_poll(ctx, false));
284da668aa1SThomas Huth     g_assert_cmpint(data1.n, ==, 1);
285da668aa1SThomas Huth     g_assert_cmpint(data2.n, ==, 1);
286da668aa1SThomas Huth     g_assert_cmpint(data3.n, ==, 1);
287da668aa1SThomas Huth     g_assert_cmpint(data4.n, ==, 1);
288da668aa1SThomas Huth     g_assert(data1.bh == NULL);
289da668aa1SThomas Huth 
290da668aa1SThomas Huth     while (data1.n < data1.max ||
291da668aa1SThomas Huth            data2.n < data2.max ||
292da668aa1SThomas Huth            data3.n < data3.max ||
293da668aa1SThomas Huth            data4.n < data4.max) {
294da668aa1SThomas Huth         aio_poll(ctx, true);
295da668aa1SThomas Huth     }
296da668aa1SThomas Huth     g_assert_cmpint(data1.n, ==, data1.max);
297da668aa1SThomas Huth     g_assert_cmpint(data2.n, ==, data2.max);
298da668aa1SThomas Huth     g_assert_cmpint(data3.n, ==, data3.max);
299da668aa1SThomas Huth     g_assert_cmpint(data4.n, ==, data4.max);
300da668aa1SThomas Huth     g_assert(data1.bh == NULL);
301da668aa1SThomas Huth     g_assert(data2.bh == NULL);
302da668aa1SThomas Huth     g_assert(data3.bh == NULL);
303da668aa1SThomas Huth     g_assert(data4.bh == NULL);
304da668aa1SThomas Huth }
305da668aa1SThomas Huth 
test_bh_flush(void)306da668aa1SThomas Huth static void test_bh_flush(void)
307da668aa1SThomas Huth {
308da668aa1SThomas Huth     BHTestData data = { .n = 0 };
309da668aa1SThomas Huth     data.bh = aio_bh_new(ctx, bh_test_cb, &data);
310da668aa1SThomas Huth 
311da668aa1SThomas Huth     qemu_bh_schedule(data.bh);
312da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 0);
313da668aa1SThomas Huth 
314da668aa1SThomas Huth     g_assert(aio_poll(ctx, true));
315da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 1);
316da668aa1SThomas Huth 
317da668aa1SThomas Huth     g_assert(!aio_poll(ctx, false));
318da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 1);
319da668aa1SThomas Huth     qemu_bh_delete(data.bh);
320da668aa1SThomas Huth }
321da668aa1SThomas Huth 
test_set_event_notifier(void)322da668aa1SThomas Huth static void test_set_event_notifier(void)
323da668aa1SThomas Huth {
324da668aa1SThomas Huth     EventNotifierTestData data = { .n = 0, .active = 0 };
325da668aa1SThomas Huth     event_notifier_init(&data.e, false);
326da668aa1SThomas Huth     set_event_notifier(ctx, &data.e, event_ready_cb);
327da668aa1SThomas Huth     g_assert(!aio_poll(ctx, false));
328da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 0);
329da668aa1SThomas Huth 
330da668aa1SThomas Huth     set_event_notifier(ctx, &data.e, NULL);
331da668aa1SThomas Huth     g_assert(!aio_poll(ctx, false));
332da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 0);
333da668aa1SThomas Huth     event_notifier_cleanup(&data.e);
334da668aa1SThomas Huth }
335da668aa1SThomas Huth 
test_wait_event_notifier(void)336da668aa1SThomas Huth static void test_wait_event_notifier(void)
337da668aa1SThomas Huth {
338da668aa1SThomas Huth     EventNotifierTestData data = { .n = 0, .active = 1 };
339da668aa1SThomas Huth     event_notifier_init(&data.e, false);
340da668aa1SThomas Huth     set_event_notifier(ctx, &data.e, event_ready_cb);
341da668aa1SThomas Huth     while (aio_poll(ctx, false));
342da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 0);
343da668aa1SThomas Huth     g_assert_cmpint(data.active, ==, 1);
344da668aa1SThomas Huth 
345da668aa1SThomas Huth     event_notifier_set(&data.e);
346da668aa1SThomas Huth     g_assert(aio_poll(ctx, false));
347da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 1);
348da668aa1SThomas Huth     g_assert_cmpint(data.active, ==, 0);
349da668aa1SThomas Huth 
350da668aa1SThomas Huth     g_assert(!aio_poll(ctx, false));
351da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 1);
352da668aa1SThomas Huth     g_assert_cmpint(data.active, ==, 0);
353da668aa1SThomas Huth 
354da668aa1SThomas Huth     set_event_notifier(ctx, &data.e, NULL);
355da668aa1SThomas Huth     g_assert(!aio_poll(ctx, false));
356da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 1);
357da668aa1SThomas Huth 
358da668aa1SThomas Huth     event_notifier_cleanup(&data.e);
359da668aa1SThomas Huth }
360da668aa1SThomas Huth 
test_flush_event_notifier(void)361da668aa1SThomas Huth static void test_flush_event_notifier(void)
362da668aa1SThomas Huth {
363da668aa1SThomas Huth     EventNotifierTestData data = { .n = 0, .active = 10, .auto_set = true };
364da668aa1SThomas Huth     event_notifier_init(&data.e, false);
365da668aa1SThomas Huth     set_event_notifier(ctx, &data.e, event_ready_cb);
366da668aa1SThomas Huth     while (aio_poll(ctx, false));
367da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 0);
368da668aa1SThomas Huth     g_assert_cmpint(data.active, ==, 10);
369da668aa1SThomas Huth 
370da668aa1SThomas Huth     event_notifier_set(&data.e);
371da668aa1SThomas Huth     g_assert(aio_poll(ctx, false));
372da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 1);
373da668aa1SThomas Huth     g_assert_cmpint(data.active, ==, 9);
374da668aa1SThomas Huth     g_assert(aio_poll(ctx, false));
375da668aa1SThomas Huth 
376da668aa1SThomas Huth     wait_until_inactive(&data);
377da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 10);
378da668aa1SThomas Huth     g_assert_cmpint(data.active, ==, 0);
379da668aa1SThomas Huth     g_assert(!aio_poll(ctx, false));
380da668aa1SThomas Huth 
381da668aa1SThomas Huth     set_event_notifier(ctx, &data.e, NULL);
382da668aa1SThomas Huth     g_assert(!aio_poll(ctx, false));
383da668aa1SThomas Huth     event_notifier_cleanup(&data.e);
384da668aa1SThomas Huth }
385da668aa1SThomas Huth 
test_wait_event_notifier_noflush(void)386da668aa1SThomas Huth static void test_wait_event_notifier_noflush(void)
387da668aa1SThomas Huth {
388da668aa1SThomas Huth     EventNotifierTestData data = { .n = 0 };
389da668aa1SThomas Huth     EventNotifierTestData dummy = { .n = 0, .active = 1 };
390da668aa1SThomas Huth 
391da668aa1SThomas Huth     event_notifier_init(&data.e, false);
392da668aa1SThomas Huth     set_event_notifier(ctx, &data.e, event_ready_cb);
393da668aa1SThomas Huth 
394da668aa1SThomas Huth     g_assert(!aio_poll(ctx, false));
395da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 0);
396da668aa1SThomas Huth 
397da668aa1SThomas Huth     /* Until there is an active descriptor, aio_poll may or may not call
398da668aa1SThomas Huth      * event_ready_cb.  Still, it must not block.  */
399da668aa1SThomas Huth     event_notifier_set(&data.e);
400da668aa1SThomas Huth     g_assert(aio_poll(ctx, true));
401da668aa1SThomas Huth     data.n = 0;
402da668aa1SThomas Huth 
403da668aa1SThomas Huth     /* An active event notifier forces aio_poll to look at EventNotifiers.  */
404da668aa1SThomas Huth     event_notifier_init(&dummy.e, false);
405da668aa1SThomas Huth     set_event_notifier(ctx, &dummy.e, event_ready_cb);
406da668aa1SThomas Huth 
407da668aa1SThomas Huth     event_notifier_set(&data.e);
408da668aa1SThomas Huth     g_assert(aio_poll(ctx, false));
409da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 1);
410da668aa1SThomas Huth     g_assert(!aio_poll(ctx, false));
411da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 1);
412da668aa1SThomas Huth 
413da668aa1SThomas Huth     event_notifier_set(&data.e);
414da668aa1SThomas Huth     g_assert(aio_poll(ctx, false));
415da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 2);
416da668aa1SThomas Huth     g_assert(!aio_poll(ctx, false));
417da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 2);
418da668aa1SThomas Huth 
419da668aa1SThomas Huth     event_notifier_set(&dummy.e);
420da668aa1SThomas Huth     wait_until_inactive(&dummy);
421da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 2);
422da668aa1SThomas Huth     g_assert_cmpint(dummy.n, ==, 1);
423da668aa1SThomas Huth     g_assert_cmpint(dummy.active, ==, 0);
424da668aa1SThomas Huth 
425da668aa1SThomas Huth     set_event_notifier(ctx, &dummy.e, NULL);
426da668aa1SThomas Huth     event_notifier_cleanup(&dummy.e);
427da668aa1SThomas Huth 
428da668aa1SThomas Huth     set_event_notifier(ctx, &data.e, NULL);
429da668aa1SThomas Huth     g_assert(!aio_poll(ctx, false));
430da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 2);
431da668aa1SThomas Huth 
432da668aa1SThomas Huth     event_notifier_cleanup(&data.e);
433da668aa1SThomas Huth }
434da668aa1SThomas Huth 
test_timer_schedule(void)435da668aa1SThomas Huth static void test_timer_schedule(void)
436da668aa1SThomas Huth {
437da668aa1SThomas Huth     TimerTestData data = { .n = 0, .ctx = ctx, .ns = SCALE_MS * 750LL,
438da668aa1SThomas Huth                            .max = 2,
439da668aa1SThomas Huth                            .clock_type = QEMU_CLOCK_REALTIME };
440da668aa1SThomas Huth     EventNotifier e;
441da668aa1SThomas Huth 
442da668aa1SThomas Huth     /* aio_poll will not block to wait for timers to complete unless it has
443da668aa1SThomas Huth      * an fd to wait on. Fixing this breaks other tests. So create a dummy one.
444da668aa1SThomas Huth      */
445da668aa1SThomas Huth     event_notifier_init(&e, false);
446da668aa1SThomas Huth     set_event_notifier(ctx, &e, dummy_io_handler_read);
447da668aa1SThomas Huth     aio_poll(ctx, false);
448da668aa1SThomas Huth 
449da668aa1SThomas Huth     aio_timer_init(ctx, &data.timer, data.clock_type,
450da668aa1SThomas Huth                    SCALE_NS, timer_test_cb, &data);
451da668aa1SThomas Huth     timer_mod(&data.timer,
452da668aa1SThomas Huth               qemu_clock_get_ns(data.clock_type) +
453da668aa1SThomas Huth               data.ns);
454da668aa1SThomas Huth 
455da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 0);
456da668aa1SThomas Huth 
45796420a30SMichael Tokarev     /* timer_mod may well cause an event notifier to have gone off,
458da668aa1SThomas Huth      * so clear that
459da668aa1SThomas Huth      */
460da668aa1SThomas Huth     do {} while (aio_poll(ctx, false));
461da668aa1SThomas Huth 
462da668aa1SThomas Huth     g_assert(!aio_poll(ctx, false));
463da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 0);
464da668aa1SThomas Huth 
465da668aa1SThomas Huth     g_usleep(1 * G_USEC_PER_SEC);
466da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 0);
467da668aa1SThomas Huth 
468da668aa1SThomas Huth     g_assert(aio_poll(ctx, false));
469da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 1);
470da668aa1SThomas Huth 
471da668aa1SThomas Huth     /* timer_mod called by our callback */
472da668aa1SThomas Huth     do {} while (aio_poll(ctx, false));
473da668aa1SThomas Huth 
474da668aa1SThomas Huth     g_assert(!aio_poll(ctx, false));
475da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 1);
476da668aa1SThomas Huth 
477da668aa1SThomas Huth     g_assert(aio_poll(ctx, true));
478da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 2);
479da668aa1SThomas Huth 
480da668aa1SThomas Huth     /* As max is now 2, an event notifier should not have gone off */
481da668aa1SThomas Huth 
482da668aa1SThomas Huth     g_assert(!aio_poll(ctx, false));
483da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 2);
484da668aa1SThomas Huth 
485da668aa1SThomas Huth     set_event_notifier(ctx, &e, NULL);
486da668aa1SThomas Huth     event_notifier_cleanup(&e);
487da668aa1SThomas Huth 
488da668aa1SThomas Huth     timer_del(&data.timer);
489da668aa1SThomas Huth }
490da668aa1SThomas Huth 
491da668aa1SThomas Huth /* Now the same tests, using the context as a GSource.  They are
492da668aa1SThomas Huth  * very similar to the ones above, with g_main_context_iteration
493da668aa1SThomas Huth  * replacing aio_poll.  However:
494da668aa1SThomas Huth  * - sometimes both the AioContext and the glib main loop wake
495da668aa1SThomas Huth  *   themselves up.  Hence, some "g_assert(!aio_poll(ctx, false));"
496da668aa1SThomas Huth  *   are replaced by "while (g_main_context_iteration(NULL, false));".
497da668aa1SThomas Huth  * - there is no exact replacement for a blocking wait.
498da668aa1SThomas Huth  *   "while (g_main_context_iteration(NULL, true)" seems to work,
499da668aa1SThomas Huth  *   but it is not documented _why_ it works.  For these tests a
500da668aa1SThomas Huth  *   non-blocking loop like "while (g_main_context_iteration(NULL, false)"
501da668aa1SThomas Huth  *   works well, and that's what I am using.
502da668aa1SThomas Huth  */
503da668aa1SThomas Huth 
test_source_flush(void)504da668aa1SThomas Huth static void test_source_flush(void)
505da668aa1SThomas Huth {
506da668aa1SThomas Huth     g_assert(!g_main_context_iteration(NULL, false));
507da668aa1SThomas Huth     aio_notify(ctx);
508da668aa1SThomas Huth     while (g_main_context_iteration(NULL, false));
509da668aa1SThomas Huth     g_assert(!g_main_context_iteration(NULL, false));
510da668aa1SThomas Huth }
511da668aa1SThomas Huth 
test_source_bh_schedule(void)512da668aa1SThomas Huth static void test_source_bh_schedule(void)
513da668aa1SThomas Huth {
514da668aa1SThomas Huth     BHTestData data = { .n = 0 };
515da668aa1SThomas Huth     data.bh = aio_bh_new(ctx, bh_test_cb, &data);
516da668aa1SThomas Huth 
517da668aa1SThomas Huth     qemu_bh_schedule(data.bh);
518da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 0);
519da668aa1SThomas Huth 
520da668aa1SThomas Huth     g_assert(g_main_context_iteration(NULL, true));
521da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 1);
522da668aa1SThomas Huth 
523da668aa1SThomas Huth     g_assert(!g_main_context_iteration(NULL, false));
524da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 1);
525da668aa1SThomas Huth     qemu_bh_delete(data.bh);
526da668aa1SThomas Huth }
527da668aa1SThomas Huth 
test_source_bh_schedule10(void)528da668aa1SThomas Huth static void test_source_bh_schedule10(void)
529da668aa1SThomas Huth {
530da668aa1SThomas Huth     BHTestData data = { .n = 0, .max = 10 };
531da668aa1SThomas Huth     data.bh = aio_bh_new(ctx, bh_test_cb, &data);
532da668aa1SThomas Huth 
533da668aa1SThomas Huth     qemu_bh_schedule(data.bh);
534da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 0);
535da668aa1SThomas Huth 
536da668aa1SThomas Huth     g_assert(g_main_context_iteration(NULL, false));
537da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 1);
538da668aa1SThomas Huth 
539da668aa1SThomas Huth     g_assert(g_main_context_iteration(NULL, true));
540da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 2);
541da668aa1SThomas Huth 
542da668aa1SThomas Huth     while (g_main_context_iteration(NULL, false));
543da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 10);
544da668aa1SThomas Huth 
545da668aa1SThomas Huth     g_assert(!g_main_context_iteration(NULL, false));
546da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 10);
547da668aa1SThomas Huth     qemu_bh_delete(data.bh);
548da668aa1SThomas Huth }
549da668aa1SThomas Huth 
test_source_bh_cancel(void)550da668aa1SThomas Huth static void test_source_bh_cancel(void)
551da668aa1SThomas Huth {
552da668aa1SThomas Huth     BHTestData data = { .n = 0 };
553da668aa1SThomas Huth     data.bh = aio_bh_new(ctx, bh_test_cb, &data);
554da668aa1SThomas Huth 
555da668aa1SThomas Huth     qemu_bh_schedule(data.bh);
556da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 0);
557da668aa1SThomas Huth 
558da668aa1SThomas Huth     qemu_bh_cancel(data.bh);
559da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 0);
560da668aa1SThomas Huth 
561da668aa1SThomas Huth     while (g_main_context_iteration(NULL, false));
562da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 0);
563da668aa1SThomas Huth     qemu_bh_delete(data.bh);
564da668aa1SThomas Huth }
565da668aa1SThomas Huth 
test_source_bh_delete(void)566da668aa1SThomas Huth static void test_source_bh_delete(void)
567da668aa1SThomas Huth {
568da668aa1SThomas Huth     BHTestData data = { .n = 0 };
569da668aa1SThomas Huth     data.bh = aio_bh_new(ctx, bh_test_cb, &data);
570da668aa1SThomas Huth 
571da668aa1SThomas Huth     qemu_bh_schedule(data.bh);
572da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 0);
573da668aa1SThomas Huth 
574da668aa1SThomas Huth     qemu_bh_delete(data.bh);
575da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 0);
576da668aa1SThomas Huth 
577da668aa1SThomas Huth     while (g_main_context_iteration(NULL, false));
578da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 0);
579da668aa1SThomas Huth }
580da668aa1SThomas Huth 
test_source_bh_delete_from_cb(void)581da668aa1SThomas Huth static void test_source_bh_delete_from_cb(void)
582da668aa1SThomas Huth {
583da668aa1SThomas Huth     BHTestData data1 = { .n = 0, .max = 1 };
584da668aa1SThomas Huth 
585da668aa1SThomas Huth     data1.bh = aio_bh_new(ctx, bh_delete_cb, &data1);
586da668aa1SThomas Huth 
587da668aa1SThomas Huth     qemu_bh_schedule(data1.bh);
588da668aa1SThomas Huth     g_assert_cmpint(data1.n, ==, 0);
589da668aa1SThomas Huth 
590da668aa1SThomas Huth     g_main_context_iteration(NULL, true);
591da668aa1SThomas Huth     g_assert_cmpint(data1.n, ==, data1.max);
592da668aa1SThomas Huth     g_assert(data1.bh == NULL);
593da668aa1SThomas Huth 
594da668aa1SThomas Huth     assert(g_main_context_iteration(NULL, false));
595da668aa1SThomas Huth     assert(!g_main_context_iteration(NULL, false));
596da668aa1SThomas Huth }
597da668aa1SThomas Huth 
test_source_bh_delete_from_cb_many(void)598da668aa1SThomas Huth static void test_source_bh_delete_from_cb_many(void)
599da668aa1SThomas Huth {
600da668aa1SThomas Huth     BHTestData data1 = { .n = 0, .max = 1 };
601da668aa1SThomas Huth     BHTestData data2 = { .n = 0, .max = 3 };
602da668aa1SThomas Huth     BHTestData data3 = { .n = 0, .max = 2 };
603da668aa1SThomas Huth     BHTestData data4 = { .n = 0, .max = 4 };
604da668aa1SThomas Huth 
605da668aa1SThomas Huth     data1.bh = aio_bh_new(ctx, bh_delete_cb, &data1);
606da668aa1SThomas Huth     data2.bh = aio_bh_new(ctx, bh_delete_cb, &data2);
607da668aa1SThomas Huth     data3.bh = aio_bh_new(ctx, bh_delete_cb, &data3);
608da668aa1SThomas Huth     data4.bh = aio_bh_new(ctx, bh_delete_cb, &data4);
609da668aa1SThomas Huth 
610da668aa1SThomas Huth     qemu_bh_schedule(data1.bh);
611da668aa1SThomas Huth     qemu_bh_schedule(data2.bh);
612da668aa1SThomas Huth     qemu_bh_schedule(data3.bh);
613da668aa1SThomas Huth     qemu_bh_schedule(data4.bh);
614da668aa1SThomas Huth     g_assert_cmpint(data1.n, ==, 0);
615da668aa1SThomas Huth     g_assert_cmpint(data2.n, ==, 0);
616da668aa1SThomas Huth     g_assert_cmpint(data3.n, ==, 0);
617da668aa1SThomas Huth     g_assert_cmpint(data4.n, ==, 0);
618da668aa1SThomas Huth 
619da668aa1SThomas Huth     g_assert(g_main_context_iteration(NULL, false));
620da668aa1SThomas Huth     g_assert_cmpint(data1.n, ==, 1);
621da668aa1SThomas Huth     g_assert_cmpint(data2.n, ==, 1);
622da668aa1SThomas Huth     g_assert_cmpint(data3.n, ==, 1);
623da668aa1SThomas Huth     g_assert_cmpint(data4.n, ==, 1);
624da668aa1SThomas Huth     g_assert(data1.bh == NULL);
625da668aa1SThomas Huth 
626da668aa1SThomas Huth     while (g_main_context_iteration(NULL, false));
627da668aa1SThomas Huth     g_assert_cmpint(data1.n, ==, data1.max);
628da668aa1SThomas Huth     g_assert_cmpint(data2.n, ==, data2.max);
629da668aa1SThomas Huth     g_assert_cmpint(data3.n, ==, data3.max);
630da668aa1SThomas Huth     g_assert_cmpint(data4.n, ==, data4.max);
631da668aa1SThomas Huth     g_assert(data1.bh == NULL);
632da668aa1SThomas Huth     g_assert(data2.bh == NULL);
633da668aa1SThomas Huth     g_assert(data3.bh == NULL);
634da668aa1SThomas Huth     g_assert(data4.bh == NULL);
635da668aa1SThomas Huth }
636da668aa1SThomas Huth 
test_source_bh_flush(void)637da668aa1SThomas Huth static void test_source_bh_flush(void)
638da668aa1SThomas Huth {
639da668aa1SThomas Huth     BHTestData data = { .n = 0 };
640da668aa1SThomas Huth     data.bh = aio_bh_new(ctx, bh_test_cb, &data);
641da668aa1SThomas Huth 
642da668aa1SThomas Huth     qemu_bh_schedule(data.bh);
643da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 0);
644da668aa1SThomas Huth 
645da668aa1SThomas Huth     g_assert(g_main_context_iteration(NULL, true));
646da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 1);
647da668aa1SThomas Huth 
648da668aa1SThomas Huth     g_assert(!g_main_context_iteration(NULL, false));
649da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 1);
650da668aa1SThomas Huth     qemu_bh_delete(data.bh);
651da668aa1SThomas Huth }
652da668aa1SThomas Huth 
test_source_set_event_notifier(void)653da668aa1SThomas Huth static void test_source_set_event_notifier(void)
654da668aa1SThomas Huth {
655da668aa1SThomas Huth     EventNotifierTestData data = { .n = 0, .active = 0 };
656da668aa1SThomas Huth     event_notifier_init(&data.e, false);
657da668aa1SThomas Huth     set_event_notifier(ctx, &data.e, event_ready_cb);
658da668aa1SThomas Huth     while (g_main_context_iteration(NULL, false));
659da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 0);
660da668aa1SThomas Huth 
661da668aa1SThomas Huth     set_event_notifier(ctx, &data.e, NULL);
662da668aa1SThomas Huth     while (g_main_context_iteration(NULL, false));
663da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 0);
664da668aa1SThomas Huth     event_notifier_cleanup(&data.e);
665da668aa1SThomas Huth }
666da668aa1SThomas Huth 
test_source_wait_event_notifier(void)667da668aa1SThomas Huth static void test_source_wait_event_notifier(void)
668da668aa1SThomas Huth {
669da668aa1SThomas Huth     EventNotifierTestData data = { .n = 0, .active = 1 };
670da668aa1SThomas Huth     event_notifier_init(&data.e, false);
671da668aa1SThomas Huth     set_event_notifier(ctx, &data.e, event_ready_cb);
672da668aa1SThomas Huth     while (g_main_context_iteration(NULL, false));
673da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 0);
674da668aa1SThomas Huth     g_assert_cmpint(data.active, ==, 1);
675da668aa1SThomas Huth 
676da668aa1SThomas Huth     event_notifier_set(&data.e);
677da668aa1SThomas Huth     g_assert(g_main_context_iteration(NULL, false));
678da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 1);
679da668aa1SThomas Huth     g_assert_cmpint(data.active, ==, 0);
680da668aa1SThomas Huth 
681da668aa1SThomas Huth     while (g_main_context_iteration(NULL, false));
682da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 1);
683da668aa1SThomas Huth     g_assert_cmpint(data.active, ==, 0);
684da668aa1SThomas Huth 
685da668aa1SThomas Huth     set_event_notifier(ctx, &data.e, NULL);
686da668aa1SThomas Huth     while (g_main_context_iteration(NULL, false));
687da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 1);
688da668aa1SThomas Huth 
689da668aa1SThomas Huth     event_notifier_cleanup(&data.e);
690da668aa1SThomas Huth }
691da668aa1SThomas Huth 
test_source_flush_event_notifier(void)692da668aa1SThomas Huth static void test_source_flush_event_notifier(void)
693da668aa1SThomas Huth {
694da668aa1SThomas Huth     EventNotifierTestData data = { .n = 0, .active = 10, .auto_set = true };
695da668aa1SThomas Huth     event_notifier_init(&data.e, false);
696da668aa1SThomas Huth     set_event_notifier(ctx, &data.e, event_ready_cb);
697da668aa1SThomas Huth     while (g_main_context_iteration(NULL, false));
698da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 0);
699da668aa1SThomas Huth     g_assert_cmpint(data.active, ==, 10);
700da668aa1SThomas Huth 
701da668aa1SThomas Huth     event_notifier_set(&data.e);
702da668aa1SThomas Huth     g_assert(g_main_context_iteration(NULL, false));
703da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 1);
704da668aa1SThomas Huth     g_assert_cmpint(data.active, ==, 9);
705da668aa1SThomas Huth     g_assert(g_main_context_iteration(NULL, false));
706da668aa1SThomas Huth 
707da668aa1SThomas Huth     while (g_main_context_iteration(NULL, false));
708da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 10);
709da668aa1SThomas Huth     g_assert_cmpint(data.active, ==, 0);
710da668aa1SThomas Huth     g_assert(!g_main_context_iteration(NULL, false));
711da668aa1SThomas Huth 
712da668aa1SThomas Huth     set_event_notifier(ctx, &data.e, NULL);
713da668aa1SThomas Huth     while (g_main_context_iteration(NULL, false));
714da668aa1SThomas Huth     event_notifier_cleanup(&data.e);
715da668aa1SThomas Huth }
716da668aa1SThomas Huth 
test_source_wait_event_notifier_noflush(void)717da668aa1SThomas Huth static void test_source_wait_event_notifier_noflush(void)
718da668aa1SThomas Huth {
719da668aa1SThomas Huth     EventNotifierTestData data = { .n = 0 };
720da668aa1SThomas Huth     EventNotifierTestData dummy = { .n = 0, .active = 1 };
721da668aa1SThomas Huth 
722da668aa1SThomas Huth     event_notifier_init(&data.e, false);
723da668aa1SThomas Huth     set_event_notifier(ctx, &data.e, event_ready_cb);
724da668aa1SThomas Huth 
725da668aa1SThomas Huth     while (g_main_context_iteration(NULL, false));
726da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 0);
727da668aa1SThomas Huth 
728da668aa1SThomas Huth     /* Until there is an active descriptor, glib may or may not call
729da668aa1SThomas Huth      * event_ready_cb.  Still, it must not block.  */
730da668aa1SThomas Huth     event_notifier_set(&data.e);
731da668aa1SThomas Huth     g_main_context_iteration(NULL, true);
732da668aa1SThomas Huth     data.n = 0;
733da668aa1SThomas Huth 
734da668aa1SThomas Huth     /* An active event notifier forces aio_poll to look at EventNotifiers.  */
735da668aa1SThomas Huth     event_notifier_init(&dummy.e, false);
736da668aa1SThomas Huth     set_event_notifier(ctx, &dummy.e, event_ready_cb);
737da668aa1SThomas Huth 
738da668aa1SThomas Huth     event_notifier_set(&data.e);
739da668aa1SThomas Huth     g_assert(g_main_context_iteration(NULL, false));
740da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 1);
741da668aa1SThomas Huth     g_assert(!g_main_context_iteration(NULL, false));
742da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 1);
743da668aa1SThomas Huth 
744da668aa1SThomas Huth     event_notifier_set(&data.e);
745da668aa1SThomas Huth     g_assert(g_main_context_iteration(NULL, false));
746da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 2);
747da668aa1SThomas Huth     g_assert(!g_main_context_iteration(NULL, false));
748da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 2);
749da668aa1SThomas Huth 
750da668aa1SThomas Huth     event_notifier_set(&dummy.e);
751da668aa1SThomas Huth     while (g_main_context_iteration(NULL, false));
752da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 2);
753da668aa1SThomas Huth     g_assert_cmpint(dummy.n, ==, 1);
754da668aa1SThomas Huth     g_assert_cmpint(dummy.active, ==, 0);
755da668aa1SThomas Huth 
756da668aa1SThomas Huth     set_event_notifier(ctx, &dummy.e, NULL);
757da668aa1SThomas Huth     event_notifier_cleanup(&dummy.e);
758da668aa1SThomas Huth 
759da668aa1SThomas Huth     set_event_notifier(ctx, &data.e, NULL);
760da668aa1SThomas Huth     while (g_main_context_iteration(NULL, false));
761da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 2);
762da668aa1SThomas Huth 
763da668aa1SThomas Huth     event_notifier_cleanup(&data.e);
764da668aa1SThomas Huth }
765da668aa1SThomas Huth 
test_source_timer_schedule(void)766da668aa1SThomas Huth static void test_source_timer_schedule(void)
767da668aa1SThomas Huth {
768da668aa1SThomas Huth     TimerTestData data = { .n = 0, .ctx = ctx, .ns = SCALE_MS * 750LL,
769da668aa1SThomas Huth                            .max = 2,
770da668aa1SThomas Huth                            .clock_type = QEMU_CLOCK_REALTIME };
771da668aa1SThomas Huth     EventNotifier e;
772da668aa1SThomas Huth     int64_t expiry;
773da668aa1SThomas Huth 
774da668aa1SThomas Huth     /* aio_poll will not block to wait for timers to complete unless it has
775da668aa1SThomas Huth      * an fd to wait on. Fixing this breaks other tests. So create a dummy one.
776da668aa1SThomas Huth      */
777da668aa1SThomas Huth     event_notifier_init(&e, false);
778da668aa1SThomas Huth     set_event_notifier(ctx, &e, dummy_io_handler_read);
779da668aa1SThomas Huth     do {} while (g_main_context_iteration(NULL, false));
780da668aa1SThomas Huth 
781da668aa1SThomas Huth     aio_timer_init(ctx, &data.timer, data.clock_type,
782da668aa1SThomas Huth                    SCALE_NS, timer_test_cb, &data);
783da668aa1SThomas Huth     expiry = qemu_clock_get_ns(data.clock_type) +
784da668aa1SThomas Huth         data.ns;
785da668aa1SThomas Huth     timer_mod(&data.timer, expiry);
786da668aa1SThomas Huth 
787da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 0);
788da668aa1SThomas Huth 
789da668aa1SThomas Huth     g_usleep(1 * G_USEC_PER_SEC);
790da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 0);
791da668aa1SThomas Huth 
792da668aa1SThomas Huth     g_assert(g_main_context_iteration(NULL, true));
793da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 1);
794da668aa1SThomas Huth     expiry += data.ns;
795da668aa1SThomas Huth 
796da668aa1SThomas Huth     while (data.n < 2) {
797da668aa1SThomas Huth         g_main_context_iteration(NULL, true);
798da668aa1SThomas Huth     }
799da668aa1SThomas Huth 
800da668aa1SThomas Huth     g_assert_cmpint(data.n, ==, 2);
801da668aa1SThomas Huth     g_assert(qemu_clock_get_ns(data.clock_type) > expiry);
802da668aa1SThomas Huth 
803da668aa1SThomas Huth     set_event_notifier(ctx, &e, NULL);
804da668aa1SThomas Huth     event_notifier_cleanup(&e);
805da668aa1SThomas Huth 
806da668aa1SThomas Huth     timer_del(&data.timer);
807da668aa1SThomas Huth }
808da668aa1SThomas Huth 
809da668aa1SThomas Huth /*
810da668aa1SThomas Huth  * Check that aio_co_enter() can chain many times
811da668aa1SThomas Huth  *
812da668aa1SThomas Huth  * Two coroutines should be able to invoke each other via aio_co_enter() many
813da668aa1SThomas Huth  * times without hitting a limit like stack exhaustion.  In other words, the
814da668aa1SThomas Huth  * calls should be chained instead of nested.
815da668aa1SThomas Huth  */
816da668aa1SThomas Huth 
817da668aa1SThomas Huth typedef struct {
818da668aa1SThomas Huth     Coroutine *other;
819da668aa1SThomas Huth     unsigned i;
820da668aa1SThomas Huth     unsigned max;
821da668aa1SThomas Huth } ChainData;
822da668aa1SThomas Huth 
chain(void * opaque)823da668aa1SThomas Huth static void coroutine_fn chain(void *opaque)
824da668aa1SThomas Huth {
825da668aa1SThomas Huth     ChainData *data = opaque;
826da668aa1SThomas Huth 
827da668aa1SThomas Huth     for (data->i = 0; data->i < data->max; data->i++) {
828da668aa1SThomas Huth         /* Queue up the other coroutine... */
829da668aa1SThomas Huth         aio_co_enter(ctx, data->other);
830da668aa1SThomas Huth 
831da668aa1SThomas Huth         /* ...and give control to it */
832da668aa1SThomas Huth         qemu_coroutine_yield();
833da668aa1SThomas Huth     }
834da668aa1SThomas Huth }
835da668aa1SThomas Huth 
test_queue_chaining(void)836da668aa1SThomas Huth static void test_queue_chaining(void)
837da668aa1SThomas Huth {
838da668aa1SThomas Huth     /* This number of iterations hit stack exhaustion in the past: */
839da668aa1SThomas Huth     ChainData data_a = { .max = 25000 };
840da668aa1SThomas Huth     ChainData data_b = { .max = 25000 };
841da668aa1SThomas Huth 
842da668aa1SThomas Huth     data_b.other = qemu_coroutine_create(chain, &data_a);
843da668aa1SThomas Huth     data_a.other = qemu_coroutine_create(chain, &data_b);
844da668aa1SThomas Huth 
845da668aa1SThomas Huth     qemu_coroutine_enter(data_b.other);
846da668aa1SThomas Huth 
847da668aa1SThomas Huth     g_assert_cmpint(data_a.i, ==, data_a.max);
848da668aa1SThomas Huth     g_assert_cmpint(data_b.i, ==, data_b.max - 1);
849da668aa1SThomas Huth 
850da668aa1SThomas Huth     /* Allow the second coroutine to terminate */
851da668aa1SThomas Huth     qemu_coroutine_enter(data_a.other);
852da668aa1SThomas Huth 
853da668aa1SThomas Huth     g_assert_cmpint(data_b.i, ==, data_b.max);
854da668aa1SThomas Huth }
855da668aa1SThomas Huth 
co_check_current_thread(void * opaque)85655159c34SPaolo Bonzini static void co_check_current_thread(void *opaque)
85755159c34SPaolo Bonzini {
85855159c34SPaolo Bonzini     QemuThread *main_thread = opaque;
85955159c34SPaolo Bonzini     assert(qemu_thread_is_self(main_thread));
86055159c34SPaolo Bonzini }
86155159c34SPaolo Bonzini 
test_aio_co_enter(void * co)86255159c34SPaolo Bonzini static void *test_aio_co_enter(void *co)
86355159c34SPaolo Bonzini {
86455159c34SPaolo Bonzini     /*
86555159c34SPaolo Bonzini      * qemu_get_current_aio_context() should not to be the main thread
86655159c34SPaolo Bonzini      * AioContext, because this is a worker thread that has not taken
86755159c34SPaolo Bonzini      * the BQL.  So aio_co_enter will schedule the coroutine in the
86855159c34SPaolo Bonzini      * main thread AioContext.
86955159c34SPaolo Bonzini      */
87055159c34SPaolo Bonzini     aio_co_enter(qemu_get_aio_context(), co);
87155159c34SPaolo Bonzini     return NULL;
87255159c34SPaolo Bonzini }
87355159c34SPaolo Bonzini 
test_worker_thread_co_enter(void)87455159c34SPaolo Bonzini static void test_worker_thread_co_enter(void)
87555159c34SPaolo Bonzini {
87655159c34SPaolo Bonzini     QemuThread this_thread, worker_thread;
87755159c34SPaolo Bonzini     Coroutine *co;
87855159c34SPaolo Bonzini 
87955159c34SPaolo Bonzini     qemu_thread_get_self(&this_thread);
88055159c34SPaolo Bonzini     co = qemu_coroutine_create(co_check_current_thread, &this_thread);
88155159c34SPaolo Bonzini 
88255159c34SPaolo Bonzini     qemu_thread_create(&worker_thread, "test_acquire_thread",
88355159c34SPaolo Bonzini                        test_aio_co_enter,
88455159c34SPaolo Bonzini                        co, QEMU_THREAD_JOINABLE);
88555159c34SPaolo Bonzini 
88655159c34SPaolo Bonzini     /* Test aio_co_enter from a worker thread.  */
88755159c34SPaolo Bonzini     qemu_thread_join(&worker_thread);
88855159c34SPaolo Bonzini     g_assert(aio_poll(ctx, true));
88955159c34SPaolo Bonzini     g_assert(!aio_poll(ctx, false));
89055159c34SPaolo Bonzini }
89155159c34SPaolo Bonzini 
892da668aa1SThomas Huth /* End of tests.  */
893da668aa1SThomas Huth 
main(int argc,char ** argv)894da668aa1SThomas Huth int main(int argc, char **argv)
895da668aa1SThomas Huth {
896da668aa1SThomas Huth     qemu_init_main_loop(&error_fatal);
897da668aa1SThomas Huth     ctx = qemu_get_aio_context();
898da668aa1SThomas Huth 
899da668aa1SThomas Huth     while (g_main_context_iteration(NULL, false));
900da668aa1SThomas Huth 
901da668aa1SThomas Huth     g_test_init(&argc, &argv, NULL);
902da668aa1SThomas Huth     g_test_add_func("/aio/acquire",                 test_acquire);
903da668aa1SThomas Huth     g_test_add_func("/aio/bh/schedule",             test_bh_schedule);
904da668aa1SThomas Huth     g_test_add_func("/aio/bh/schedule10",           test_bh_schedule10);
905da668aa1SThomas Huth     g_test_add_func("/aio/bh/cancel",               test_bh_cancel);
906da668aa1SThomas Huth     g_test_add_func("/aio/bh/delete",               test_bh_delete);
907da668aa1SThomas Huth     g_test_add_func("/aio/bh/callback-delete/one",  test_bh_delete_from_cb);
908da668aa1SThomas Huth     g_test_add_func("/aio/bh/callback-delete/many", test_bh_delete_from_cb_many);
909da668aa1SThomas Huth     g_test_add_func("/aio/bh/flush",                test_bh_flush);
910da668aa1SThomas Huth     g_test_add_func("/aio/event/add-remove",        test_set_event_notifier);
911da668aa1SThomas Huth     g_test_add_func("/aio/event/wait",              test_wait_event_notifier);
912da668aa1SThomas Huth     g_test_add_func("/aio/event/wait/no-flush-cb",  test_wait_event_notifier_noflush);
913da668aa1SThomas Huth     g_test_add_func("/aio/event/flush",             test_flush_event_notifier);
914da668aa1SThomas Huth     g_test_add_func("/aio/timer/schedule",          test_timer_schedule);
915da668aa1SThomas Huth 
916da668aa1SThomas Huth     g_test_add_func("/aio/coroutine/queue-chaining", test_queue_chaining);
91755159c34SPaolo Bonzini     g_test_add_func("/aio/coroutine/worker-thread-co-enter", test_worker_thread_co_enter);
918da668aa1SThomas Huth 
919da668aa1SThomas Huth     g_test_add_func("/aio-gsource/flush",                   test_source_flush);
920da668aa1SThomas Huth     g_test_add_func("/aio-gsource/bh/schedule",             test_source_bh_schedule);
921da668aa1SThomas Huth     g_test_add_func("/aio-gsource/bh/schedule10",           test_source_bh_schedule10);
922da668aa1SThomas Huth     g_test_add_func("/aio-gsource/bh/cancel",               test_source_bh_cancel);
923da668aa1SThomas Huth     g_test_add_func("/aio-gsource/bh/delete",               test_source_bh_delete);
924da668aa1SThomas Huth     g_test_add_func("/aio-gsource/bh/callback-delete/one",  test_source_bh_delete_from_cb);
925da668aa1SThomas Huth     g_test_add_func("/aio-gsource/bh/callback-delete/many", test_source_bh_delete_from_cb_many);
926da668aa1SThomas Huth     g_test_add_func("/aio-gsource/bh/flush",                test_source_bh_flush);
927da668aa1SThomas Huth     g_test_add_func("/aio-gsource/event/add-remove",        test_source_set_event_notifier);
928da668aa1SThomas Huth     g_test_add_func("/aio-gsource/event/wait",              test_source_wait_event_notifier);
929da668aa1SThomas Huth     g_test_add_func("/aio-gsource/event/wait/no-flush-cb",  test_source_wait_event_notifier_noflush);
930da668aa1SThomas Huth     g_test_add_func("/aio-gsource/event/flush",             test_source_flush_event_notifier);
931da668aa1SThomas Huth     g_test_add_func("/aio-gsource/timer/schedule",          test_source_timer_schedule);
932da668aa1SThomas Huth     return g_test_run();
933da668aa1SThomas Huth }
934