1844a12a6SStefan Hajnoczi /* SPDX-License-Identifier: GPL-2.0-or-later */ 2844a12a6SStefan Hajnoczi /* 3844a12a6SStefan Hajnoczi * Test that poll handlers are not re-entrant in nested aio_poll() 4844a12a6SStefan Hajnoczi * 5844a12a6SStefan Hajnoczi * Copyright Red Hat 6844a12a6SStefan Hajnoczi * 7844a12a6SStefan Hajnoczi * Poll handlers are usually level-triggered. That means they continue firing 8844a12a6SStefan Hajnoczi * until the condition is reset (e.g. a virtqueue becomes empty). If a poll 9844a12a6SStefan Hajnoczi * handler calls nested aio_poll() before the condition is reset, then infinite 10844a12a6SStefan Hajnoczi * recursion occurs. 11844a12a6SStefan Hajnoczi * 12844a12a6SStefan Hajnoczi * aio_poll() is supposed to prevent this by disabling poll handlers in nested 13844a12a6SStefan Hajnoczi * aio_poll() calls. This test case checks that this is indeed what happens. 14844a12a6SStefan Hajnoczi */ 15844a12a6SStefan Hajnoczi #include "qemu/osdep.h" 16844a12a6SStefan Hajnoczi #include "block/aio.h" 17844a12a6SStefan Hajnoczi #include "qapi/error.h" 18844a12a6SStefan Hajnoczi 19844a12a6SStefan Hajnoczi typedef struct { 20844a12a6SStefan Hajnoczi AioContext *ctx; 21844a12a6SStefan Hajnoczi 22844a12a6SStefan Hajnoczi /* This is the EventNotifier that drives the test */ 23844a12a6SStefan Hajnoczi EventNotifier poll_notifier; 24844a12a6SStefan Hajnoczi 25844a12a6SStefan Hajnoczi /* This EventNotifier is only used to wake aio_poll() */ 26844a12a6SStefan Hajnoczi EventNotifier dummy_notifier; 27844a12a6SStefan Hajnoczi 28844a12a6SStefan Hajnoczi bool nested; 29844a12a6SStefan Hajnoczi } TestData; 30844a12a6SStefan Hajnoczi 31844a12a6SStefan Hajnoczi static void io_read(EventNotifier *notifier) 32844a12a6SStefan Hajnoczi { 33844a12a6SStefan Hajnoczi fprintf(stderr, "%s %p\n", __func__, notifier); 34844a12a6SStefan Hajnoczi event_notifier_test_and_clear(notifier); 35844a12a6SStefan Hajnoczi } 36844a12a6SStefan Hajnoczi 37844a12a6SStefan Hajnoczi static bool io_poll_true(void *opaque) 38844a12a6SStefan Hajnoczi { 39844a12a6SStefan Hajnoczi fprintf(stderr, "%s %p\n", __func__, opaque); 40844a12a6SStefan Hajnoczi return true; 41844a12a6SStefan Hajnoczi } 42844a12a6SStefan Hajnoczi 43844a12a6SStefan Hajnoczi static bool io_poll_false(void *opaque) 44844a12a6SStefan Hajnoczi { 45844a12a6SStefan Hajnoczi fprintf(stderr, "%s %p\n", __func__, opaque); 46844a12a6SStefan Hajnoczi return false; 47844a12a6SStefan Hajnoczi } 48844a12a6SStefan Hajnoczi 49844a12a6SStefan Hajnoczi static void io_poll_ready(EventNotifier *notifier) 50844a12a6SStefan Hajnoczi { 51844a12a6SStefan Hajnoczi TestData *td = container_of(notifier, TestData, poll_notifier); 52844a12a6SStefan Hajnoczi 53844a12a6SStefan Hajnoczi fprintf(stderr, "> %s\n", __func__); 54844a12a6SStefan Hajnoczi 55844a12a6SStefan Hajnoczi g_assert(!td->nested); 56844a12a6SStefan Hajnoczi td->nested = true; 57844a12a6SStefan Hajnoczi 58844a12a6SStefan Hajnoczi /* Wake the following nested aio_poll() call */ 59844a12a6SStefan Hajnoczi event_notifier_set(&td->dummy_notifier); 60844a12a6SStefan Hajnoczi 61844a12a6SStefan Hajnoczi /* This nested event loop must not call io_poll()/io_poll_ready() */ 62844a12a6SStefan Hajnoczi g_assert(aio_poll(td->ctx, true)); 63844a12a6SStefan Hajnoczi 64844a12a6SStefan Hajnoczi td->nested = false; 65844a12a6SStefan Hajnoczi 66844a12a6SStefan Hajnoczi fprintf(stderr, "< %s\n", __func__); 67844a12a6SStefan Hajnoczi } 68844a12a6SStefan Hajnoczi 69844a12a6SStefan Hajnoczi /* dummy_notifier never triggers */ 70844a12a6SStefan Hajnoczi static void io_poll_never_ready(EventNotifier *notifier) 71844a12a6SStefan Hajnoczi { 72844a12a6SStefan Hajnoczi g_assert_not_reached(); 73844a12a6SStefan Hajnoczi } 74844a12a6SStefan Hajnoczi 75844a12a6SStefan Hajnoczi static void test(void) 76844a12a6SStefan Hajnoczi { 77844a12a6SStefan Hajnoczi TestData td = { 78844a12a6SStefan Hajnoczi .ctx = aio_context_new(&error_abort), 79844a12a6SStefan Hajnoczi }; 80844a12a6SStefan Hajnoczi 81844a12a6SStefan Hajnoczi qemu_set_current_aio_context(td.ctx); 82844a12a6SStefan Hajnoczi 83844a12a6SStefan Hajnoczi /* Enable polling */ 84844a12a6SStefan Hajnoczi aio_context_set_poll_params(td.ctx, 1000000, 2, 2, &error_abort); 85844a12a6SStefan Hajnoczi 86844a12a6SStefan Hajnoczi /* 87844a12a6SStefan Hajnoczi * The GSource is unused but this has the side-effect of changing the fdmon 88844a12a6SStefan Hajnoczi * that AioContext uses. 89844a12a6SStefan Hajnoczi */ 90844a12a6SStefan Hajnoczi aio_get_g_source(td.ctx); 91844a12a6SStefan Hajnoczi 92844a12a6SStefan Hajnoczi /* Make the event notifier active (set) right away */ 93844a12a6SStefan Hajnoczi event_notifier_init(&td.poll_notifier, 1); 94*60f782b6SStefan Hajnoczi aio_set_event_notifier(td.ctx, &td.poll_notifier, 95844a12a6SStefan Hajnoczi io_read, io_poll_true, io_poll_ready); 96844a12a6SStefan Hajnoczi 97844a12a6SStefan Hajnoczi /* This event notifier will be used later */ 98844a12a6SStefan Hajnoczi event_notifier_init(&td.dummy_notifier, 0); 99*60f782b6SStefan Hajnoczi aio_set_event_notifier(td.ctx, &td.dummy_notifier, 100844a12a6SStefan Hajnoczi io_read, io_poll_false, io_poll_never_ready); 101844a12a6SStefan Hajnoczi 102844a12a6SStefan Hajnoczi /* Consume aio_notify() */ 103844a12a6SStefan Hajnoczi g_assert(!aio_poll(td.ctx, false)); 104844a12a6SStefan Hajnoczi 105844a12a6SStefan Hajnoczi /* 106844a12a6SStefan Hajnoczi * Run the io_read() handler. This has the side-effect of activating 107844a12a6SStefan Hajnoczi * polling in future aio_poll() calls. 108844a12a6SStefan Hajnoczi */ 109844a12a6SStefan Hajnoczi g_assert(aio_poll(td.ctx, true)); 110844a12a6SStefan Hajnoczi 111844a12a6SStefan Hajnoczi /* The second time around the io_poll()/io_poll_ready() handler runs */ 112844a12a6SStefan Hajnoczi g_assert(aio_poll(td.ctx, true)); 113844a12a6SStefan Hajnoczi 114844a12a6SStefan Hajnoczi /* Run io_poll()/io_poll_ready() one more time to show it keeps working */ 115844a12a6SStefan Hajnoczi g_assert(aio_poll(td.ctx, true)); 116844a12a6SStefan Hajnoczi 117*60f782b6SStefan Hajnoczi aio_set_event_notifier(td.ctx, &td.dummy_notifier, NULL, NULL, NULL); 118*60f782b6SStefan Hajnoczi aio_set_event_notifier(td.ctx, &td.poll_notifier, NULL, NULL, NULL); 119844a12a6SStefan Hajnoczi event_notifier_cleanup(&td.dummy_notifier); 120844a12a6SStefan Hajnoczi event_notifier_cleanup(&td.poll_notifier); 121844a12a6SStefan Hajnoczi aio_context_unref(td.ctx); 122844a12a6SStefan Hajnoczi } 123844a12a6SStefan Hajnoczi 124844a12a6SStefan Hajnoczi int main(int argc, char **argv) 125844a12a6SStefan Hajnoczi { 126844a12a6SStefan Hajnoczi g_test_init(&argc, &argv, NULL); 127844a12a6SStefan Hajnoczi g_test_add_func("/nested-aio-poll", test); 128844a12a6SStefan Hajnoczi return g_test_run(); 129844a12a6SStefan Hajnoczi } 130