From patchwork Sat Aug 10 10:06:32 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alex Bligh X-Patchwork-Id: 266210 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (unknown [IPv6:2001:4830:134:3::12]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 122462C0084 for ; Sat, 10 Aug 2013 20:20:55 +1000 (EST) Received: from localhost ([::1]:42780 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1V86Hz-0005cb-9k for incoming@patchwork.ozlabs.org; Sat, 10 Aug 2013 06:20:51 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:55974) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1V864j-0000HL-6f for qemu-devel@nongnu.org; Sat, 10 Aug 2013 06:07:13 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1V864c-0005Es-W6 for qemu-devel@nongnu.org; Sat, 10 Aug 2013 06:07:09 -0400 Received: from mail.avalus.com ([2001:41c8:10:1dd::10]:52142) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1V864c-0005Ee-Lv for qemu-devel@nongnu.org; Sat, 10 Aug 2013 06:07:02 -0400 Received: by mail.avalus.com (Postfix) with ESMTPSA id 03CB5C561C9; Sat, 10 Aug 2013 11:07:01 +0100 (BST) From: Alex Bligh To: qemu-devel@nongnu.org Date: Sat, 10 Aug 2013 11:06:32 +0100 Message-Id: <1376129195-29872-29-git-send-email-alex@alex.org.uk> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1376129195-29872-1-git-send-email-alex@alex.org.uk> References: <1376129195-29872-1-git-send-email-alex@alex.org.uk> X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2001:41c8:10:1dd::10 Cc: Kevin Wolf , Anthony Liguori , Alex Bligh , Jan Kiszka , liu ping fan , Stefan Hajnoczi , Paolo Bonzini , MORITA Kazutaka , rth@twiddle.net Subject: [Qemu-devel] [RFC] [PATCHv9 28/31] aio / timers: Add test harness for AioContext timers X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Add a test harness for AioContext timers. The g_source equivalent is unsatisfactory as it suffers from false wakeups. Signed-off-by: Alex Bligh --- tests/test-aio.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) diff --git a/tests/test-aio.c b/tests/test-aio.c index eedf7f8..f751543 100644 --- a/tests/test-aio.c +++ b/tests/test-aio.c @@ -32,6 +32,15 @@ typedef struct { int max; } BHTestData; +typedef struct { + QEMUTimer timer; + QEMUClockType clock_type; + int n; + int max; + int64_t ns; + AioContext *ctx; +} TimerTestData; + static void bh_test_cb(void *opaque) { BHTestData *data = opaque; @@ -40,6 +49,24 @@ static void bh_test_cb(void *opaque) } } +static void timer_test_cb(void *opaque) +{ + TimerTestData *data = opaque; + if (++data->n < data->max) { + timer_mod(&data->timer, + qemu_clock_get_ns(data->clock_type) + data->ns); + } +} + +static void dummy_io_handler_read(void *opaque) +{ +} + +static int dummy_io_handler_flush(void *opaque) +{ + return 1; +} + static void bh_delete_cb(void *opaque) { BHTestData *data = opaque; @@ -341,6 +368,65 @@ static void test_wait_event_notifier_noflush(void) event_notifier_cleanup(&data.e); } +static void test_timer_schedule(void) +{ + TimerTestData data = { .n = 0, .ctx = ctx, .ns = SCALE_MS * 750LL, + .max = 2, + .clock_type = QEMU_CLOCK_VIRTUAL }; + int pipefd[2]; + + /* aio_poll will not block to wait for timers to complete unless it has + * an fd to wait on. Fixing this breaks other tests. So create a dummy one. + */ + g_assert(!pipe2(pipefd, O_NONBLOCK)); + aio_set_fd_handler(ctx, pipefd[0], + dummy_io_handler_read, NULL, dummy_io_handler_flush, + NULL); + aio_poll(ctx, false); + + aio_timer_init(ctx, &data.timer, data.clock_type, + SCALE_NS, timer_test_cb, &data); + timer_mod(&data.timer, + qemu_clock_get_ns(data.clock_type) + + data.ns); + + g_assert_cmpint(data.n, ==, 0); + + /* timer_mod may well cause an event notifer to have gone off, + * so clear that + */ + do {} while (aio_poll(ctx, false)); + + g_assert(!aio_poll(ctx, false)); + g_assert_cmpint(data.n, ==, 0); + + sleep(1); + g_assert_cmpint(data.n, ==, 0); + + g_assert(aio_poll(ctx, false)); + g_assert_cmpint(data.n, ==, 1); + + /* timer_mod called by our callback */ + do {} while (aio_poll(ctx, false)); + + g_assert(!aio_poll(ctx, false)); + g_assert_cmpint(data.n, ==, 1); + + g_assert(aio_poll(ctx, true)); + g_assert_cmpint(data.n, ==, 2); + + /* As max is now 2, an event notifier should not have gone off */ + + g_assert(!aio_poll(ctx, false)); + g_assert_cmpint(data.n, ==, 2); + + aio_set_fd_handler(ctx, pipefd[0], NULL, NULL, NULL, NULL); + close(pipefd[0]); + close(pipefd[1]); + + timer_del(&data.timer); +} + /* Now the same tests, using the context as a GSource. They are * very similar to the ones above, with g_main_context_iteration * replacing aio_poll. However: @@ -623,6 +709,54 @@ static void test_source_wait_event_notifier_noflush(void) event_notifier_cleanup(&data.e); } +static void test_source_timer_schedule(void) +{ + TimerTestData data = { .n = 0, .ctx = ctx, .ns = SCALE_MS * 750LL, + .max = 2, + .clock_type = QEMU_CLOCK_VIRTUAL }; + int pipefd[2]; + int64_t expiry; + + /* aio_poll will not block to wait for timers to complete unless it has + * an fd to wait on. Fixing this breaks other tests. So create a dummy one. + */ + g_assert(!pipe2(pipefd, O_NONBLOCK)); + aio_set_fd_handler(ctx, pipefd[0], + dummy_io_handler_read, NULL, dummy_io_handler_flush, + NULL); + do {} while (g_main_context_iteration(NULL, false)); + + aio_timer_init(ctx, &data.timer, data.clock_type, + SCALE_NS, timer_test_cb, &data); + expiry = qemu_clock_get_ns(data.clock_type) + + data.ns; + timer_mod(&data.timer, expiry); + + g_assert_cmpint(data.n, ==, 0); + + sleep(1); + g_assert_cmpint(data.n, ==, 0); + + g_assert(g_main_context_iteration(NULL, false)); + g_assert_cmpint(data.n, ==, 1); + + /* The comment above was not kidding when it said this wakes up itself */ + do { + g_assert(g_main_context_iteration(NULL, true)); + } while (qemu_clock_get_ns(data.clock_type) <= expiry); + sleep(1); + g_main_context_iteration(NULL, false); + + g_assert_cmpint(data.n, ==, 2); + + aio_set_fd_handler(ctx, pipefd[0], NULL, NULL, NULL, NULL); + close(pipefd[0]); + close(pipefd[1]); + + timer_del(&data.timer); +} + + /* End of tests. */ int main(int argc, char **argv) @@ -651,6 +785,7 @@ int main(int argc, char **argv) g_test_add_func("/aio/event/wait", test_wait_event_notifier); g_test_add_func("/aio/event/wait/no-flush-cb", test_wait_event_notifier_noflush); g_test_add_func("/aio/event/flush", test_flush_event_notifier); + g_test_add_func("/aio/timer/schedule", test_timer_schedule); g_test_add_func("/aio-gsource/notify", test_source_notify); g_test_add_func("/aio-gsource/flush", test_source_flush); @@ -665,5 +800,6 @@ int main(int argc, char **argv) g_test_add_func("/aio-gsource/event/wait", test_source_wait_event_notifier); g_test_add_func("/aio-gsource/event/wait/no-flush-cb", test_source_wait_event_notifier_noflush); g_test_add_func("/aio-gsource/event/flush", test_source_flush_event_notifier); + g_test_add_func("/aio-gsource/timer/schedule", test_source_timer_schedule); return g_test_run(); }